1/* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16import {NO_ERRORS_SCHEMA} from '@angular/core'; 17import {ComponentFixture, TestBed} from '@angular/core/testing'; 18import {MatButtonModule} from '@angular/material/button'; 19import {MatCardModule} from '@angular/material/card'; 20import {MatDividerModule} from '@angular/material/divider'; 21import {MatIconModule} from '@angular/material/icon'; 22import {MatListModule} from '@angular/material/list'; 23import {MatProgressBarModule} from '@angular/material/progress-bar'; 24import {MatSnackBar, MatSnackBarModule} from '@angular/material/snack-bar'; 25import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 26import {AdbProxyComponent} from './adb_proxy_component'; 27import {CollectTracesComponent} from './collect_traces_component'; 28import {TraceConfigComponent} from './trace_config_component'; 29import {WebAdbComponent} from './web_adb_component'; 30 31describe('CollectTracesComponent', () => { 32 let fixture: ComponentFixture<CollectTracesComponent>; 33 let component: CollectTracesComponent; 34 let htmlElement: HTMLElement; 35 36 beforeEach(async () => { 37 await TestBed.configureTestingModule({ 38 imports: [ 39 MatIconModule, 40 MatCardModule, 41 MatListModule, 42 MatButtonModule, 43 MatDividerModule, 44 MatProgressBarModule, 45 BrowserAnimationsModule, 46 MatSnackBarModule, 47 ], 48 providers: [MatSnackBar], 49 declarations: [ 50 CollectTracesComponent, 51 AdbProxyComponent, 52 WebAdbComponent, 53 TraceConfigComponent, 54 ], 55 schemas: [NO_ERRORS_SCHEMA], 56 }).compileComponents(); 57 fixture = TestBed.createComponent(CollectTracesComponent); 58 component = fixture.componentInstance; 59 htmlElement = fixture.nativeElement; 60 component.isAdbProxy = true; 61 }); 62 63 it('can be created', () => { 64 expect(component).toBeTruthy(); 65 }); 66 67 it('renders the expected card title', () => { 68 fixture.detectChanges(); 69 expect(htmlElement.querySelector('.title')?.innerHTML).toContain('Collect Traces'); 70 }); 71 72 it('displays connecting message', () => { 73 component.connect.isConnectingState = jasmine.createSpy().and.returnValue(true); 74 fixture.detectChanges(); 75 expect(htmlElement.querySelector('.connecting-message')?.innerHTML).toContain('Connecting...'); 76 }); 77 78 it('displays adb set up', async () => { 79 component.connect.adbSuccess = jasmine.createSpy().and.returnValue(false); 80 fixture.detectChanges(); 81 fixture.whenStable().then(() => { 82 expect(htmlElement.querySelector('.set-up-adb')).toBeTruthy(); 83 const proxyTab: HTMLButtonElement | null = htmlElement.querySelector('.proxy-tab'); 84 expect(proxyTab).toBeInstanceOf(HTMLButtonElement); 85 const webTab: HTMLButtonElement | null = htmlElement.querySelector('.web-tab'); 86 expect(webTab).toBeInstanceOf(HTMLButtonElement); 87 }); 88 }); 89 90 it('displays adb proxy element', async () => { 91 component.connect.adbSuccess = jasmine.createSpy().and.returnValue(false); 92 component.isAdbProxy = true; 93 fixture.detectChanges(); 94 fixture.whenStable().then(() => { 95 expect(htmlElement.querySelector('adb-proxy')).toBeTruthy(); 96 expect(htmlElement.querySelector('web-adb')).toBeFalsy(); 97 }); 98 }); 99 100 it('displays web adb element', async () => { 101 component.connect.adbSuccess = jasmine.createSpy().and.returnValue(false); 102 component.isAdbProxy = false; 103 fixture.detectChanges(); 104 fixture.whenStable().then(() => { 105 expect(htmlElement.querySelector('adb-proxy')).toBeFalsy(); 106 expect(htmlElement.querySelector('web-adb')).toBeTruthy(); 107 }); 108 }); 109 110 it('changes to adb workflow tab', async () => { 111 component.connect.adbSuccess = jasmine.createSpy().and.returnValue(false); 112 component.isAdbProxy = true; 113 fixture.detectChanges(); 114 fixture.whenStable().then(() => { 115 const webTab: HTMLButtonElement | null = htmlElement.querySelector('.web-tab'); 116 expect(webTab).toBeInstanceOf(HTMLButtonElement); 117 webTab?.dispatchEvent(new Event('click')); 118 fixture.whenStable().then(() => { 119 expect(component.displayWebAdbTab).toHaveBeenCalled(); 120 }); 121 }); 122 }); 123 124 it('displays no connected devices', async () => { 125 component.connect.isDevicesState = jasmine.createSpy().and.returnValue(true); 126 component.connect.devices = jasmine.createSpy().and.returnValue({}); 127 fixture.detectChanges(); 128 fixture.whenStable().then(() => { 129 const el = htmlElement.querySelector('.devices-connecting'); 130 expect(el).toBeTruthy(); 131 expect(el?.innerHTML).toContain('No devices detected'); 132 }); 133 }); 134 135 it('displays connected authorised devices', async () => { 136 component.connect.isDevicesState = jasmine.createSpy().and.returnValue(true); 137 component.connect.devices = jasmine 138 .createSpy() 139 .and.returnValue({'35562': {model: 'Pixel 6', authorised: true}}); 140 fixture.detectChanges(); 141 fixture.whenStable().then(() => { 142 const el = htmlElement.querySelector('.devices-connecting'); 143 expect(el).toBeTruthy(); 144 expect(el?.innerHTML).toContain('Connected devices:'); 145 expect(el?.innerHTML).toContain('Pixel 6'); 146 expect(el?.innerHTML).toContain('smartphone'); 147 }); 148 }); 149 150 it('displays connected unauthorised devices', async () => { 151 component.connect.isDevicesState = jasmine.createSpy().and.returnValue(true); 152 component.connect.devices = jasmine 153 .createSpy() 154 .and.returnValue({'35562': {model: 'Pixel 6', authorised: false}}); 155 fixture.detectChanges(); 156 fixture.whenStable().then(() => { 157 const el = htmlElement.querySelector('.devices-connecting'); 158 expect(el).toBeTruthy(); 159 expect(el?.innerHTML).toContain('Connected devices:'); 160 expect(el?.innerHTML).toContain('unauthorised'); 161 expect(el?.innerHTML).toContain('screen_lock_portrait'); 162 }); 163 }); 164 165 it('displays trace collection config elements', async () => { 166 component.connect.isStartTraceState = jasmine.createSpy().and.returnValue(true); 167 const mock = {model: 'Pixel 6', authorised: true}; 168 component.connect.devices = jasmine.createSpy().and.returnValue({'35562': mock}); 169 component.connect.selectedDevice = jasmine.createSpy().and.returnValue(mock); 170 fixture.detectChanges(); 171 172 fixture.whenStable().then(() => { 173 const el = htmlElement.querySelector('.trace-collection-config'); 174 expect(el).toBeTruthy(); 175 expect(el?.innerHTML).toContain('smartphone'); 176 expect(el?.innerHTML).toContain('Pixel 6'); 177 expect(el?.innerHTML).toContain('35562'); 178 179 const traceSection = htmlElement.querySelector('.trace-section'); 180 expect(traceSection).toBeTruthy(); 181 182 const dumpSection = htmlElement.querySelector('.dump-section'); 183 expect(dumpSection).toBeTruthy(); 184 }); 185 }); 186 187 it('start trace button works as expected', async () => { 188 component.connect.isStartTraceState = jasmine.createSpy().and.returnValue(true); 189 const mock = {model: 'Pixel 6', authorised: true}; 190 component.connect.devices = jasmine.createSpy().and.returnValue({'35562': mock}); 191 component.connect.selectedDevice = jasmine.createSpy().and.returnValue(mock); 192 fixture.detectChanges(); 193 194 fixture.whenStable().then(() => { 195 const start: HTMLButtonElement | null = htmlElement.querySelector('.start-btn'); 196 expect(start).toBeInstanceOf(HTMLButtonElement); 197 start?.dispatchEvent(new Event('click')); 198 fixture.whenStable().then(() => { 199 expect(component.startTracing).toHaveBeenCalled(); 200 expect(component.connect.startTrace).toHaveBeenCalled(); 201 }); 202 }); 203 }); 204 205 it('dump state button works as expected', async () => { 206 component.connect.isStartTraceState = jasmine.createSpy().and.returnValue(true); 207 const mock = {model: 'Pixel 6', authorised: true}; 208 component.connect.devices = jasmine.createSpy().and.returnValue({'35562': mock}); 209 component.connect.selectedDevice = jasmine.createSpy().and.returnValue(mock); 210 fixture.detectChanges(); 211 212 fixture.whenStable().then(() => { 213 const dump: HTMLButtonElement | null = htmlElement.querySelector('.dump-btn'); 214 expect(dump).toBeInstanceOf(HTMLButtonElement); 215 dump?.dispatchEvent(new Event('click')); 216 fixture.whenStable().then(() => { 217 expect(component.dumpState).toHaveBeenCalled(); 218 expect(component.connect.dumpState).toHaveBeenCalled(); 219 }); 220 }); 221 }); 222 223 it('change device button works as expected', async () => { 224 component.connect.isStartTraceState = jasmine.createSpy().and.returnValue(true); 225 const mock = {model: 'Pixel 6', authorised: true}; 226 component.connect.devices = jasmine.createSpy().and.returnValue({'35562': mock}); 227 component.connect.selectedDevice = jasmine.createSpy().and.returnValue(mock); 228 fixture.detectChanges(); 229 230 fixture.whenStable().then(() => { 231 const change: HTMLButtonElement | null = htmlElement.querySelector('.change-btn'); 232 expect(change).toBeInstanceOf(HTMLButtonElement); 233 change?.dispatchEvent(new Event('click')); 234 fixture.whenStable().then(() => { 235 expect(component.connect.resetLastDevice).toHaveBeenCalled(); 236 }); 237 }); 238 }); 239 240 it('displays unknown error message', () => { 241 component.connect.isErrorState = jasmine.createSpy().and.returnValue(true); 242 component.connect.proxy!.errorText = 'bad things are happening'; 243 fixture.detectChanges(); 244 fixture.whenStable().then(() => { 245 const el = htmlElement.querySelector('.unknown-error'); 246 expect(el?.innerHTML).toContain('Error:'); 247 expect(el?.innerHTML).toContain('bad things are happening'); 248 const retry: HTMLButtonElement | null = htmlElement.querySelector('.retry-btn'); 249 expect(retry).toBeInstanceOf(HTMLButtonElement); 250 retry?.dispatchEvent(new Event('click')); 251 fixture.whenStable().then(() => { 252 expect(component.connect.restart).toHaveBeenCalled(); 253 }); 254 }); 255 }); 256 257 it('displays end tracing elements', () => { 258 component.connect.isEndTraceState = jasmine.createSpy().and.returnValue(true); 259 fixture.detectChanges(); 260 fixture.whenStable().then(() => { 261 const el = htmlElement.querySelector('.end-tracing'); 262 expect(el?.innerHTML).toContain('Tracing...'); 263 expect(htmlElement.querySelector('mat-progress-bar')).toBeTruthy(); 264 265 const end: HTMLButtonElement | null = htmlElement.querySelector('.end'); 266 expect(end).toBeInstanceOf(HTMLButtonElement); 267 end?.dispatchEvent(new Event('click')); 268 fixture.whenStable().then(() => { 269 expect(component.endTrace).toHaveBeenCalled(); 270 expect(component.connect.endTrace).toHaveBeenCalled(); 271 }); 272 }); 273 }); 274 275 it('displays loading data elements', () => { 276 component.connect.isLoadDataState = jasmine.createSpy().and.returnValue(true); 277 fixture.detectChanges(); 278 fixture.whenStable().then(() => { 279 expect(htmlElement.querySelector('.load-data')?.innerHTML).toContain('Loading data...'); 280 expect(htmlElement.querySelector('mat-progress-bar')).toBeTruthy(); 281 }); 282 }); 283}); 284