1*90c8c64dSAndroid Build Coastguard Worker/* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Workerimport * as path from 'path'; 17*90c8c64dSAndroid Build Coastguard Workerimport {browser, by, element, ElementFinder, protractor} from 'protractor'; 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Workerclass E2eTestUtils { 20*90c8c64dSAndroid Build Coastguard Worker static readonly WINSCOPE_URL = 'http://localhost:8080'; 21*90c8c64dSAndroid Build Coastguard Worker static readonly REMOTE_TOOL_MOCK_URL = 'http://localhost:8081'; 22*90c8c64dSAndroid Build Coastguard Worker 23*90c8c64dSAndroid Build Coastguard Worker static async beforeEach(defaultTimeoutMs: number) { 24*90c8c64dSAndroid Build Coastguard Worker await browser.manage().timeouts().implicitlyWait(defaultTimeoutMs); 25*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.checkServerIsUp('Winscope', E2eTestUtils.WINSCOPE_URL); 26*90c8c64dSAndroid Build Coastguard Worker await browser.driver.manage().window().maximize(); 27*90c8c64dSAndroid Build Coastguard Worker } 28*90c8c64dSAndroid Build Coastguard Worker 29*90c8c64dSAndroid Build Coastguard Worker static async checkServerIsUp(name: string, url: string) { 30*90c8c64dSAndroid Build Coastguard Worker try { 31*90c8c64dSAndroid Build Coastguard Worker await browser.get(url); 32*90c8c64dSAndroid Build Coastguard Worker } catch (error) { 33*90c8c64dSAndroid Build Coastguard Worker fail(`${name} server (${url}) looks down. Did you start it?`); 34*90c8c64dSAndroid Build Coastguard Worker } 35*90c8c64dSAndroid Build Coastguard Worker } 36*90c8c64dSAndroid Build Coastguard Worker 37*90c8c64dSAndroid Build Coastguard Worker static async loadTraceAndCheckViewer( 38*90c8c64dSAndroid Build Coastguard Worker fixturePath: string, 39*90c8c64dSAndroid Build Coastguard Worker viewerTabTitle: string, 40*90c8c64dSAndroid Build Coastguard Worker viewerSelector: string, 41*90c8c64dSAndroid Build Coastguard Worker ) { 42*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.uploadFixture(fixturePath); 43*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.closeSnackBar(); 44*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.clickViewTracesButton(); 45*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.clickViewerTabButton(viewerTabTitle); 46*90c8c64dSAndroid Build Coastguard Worker 47*90c8c64dSAndroid Build Coastguard Worker const viewerPresent = await element(by.css(viewerSelector)).isPresent(); 48*90c8c64dSAndroid Build Coastguard Worker expect(viewerPresent).toBeTruthy(); 49*90c8c64dSAndroid Build Coastguard Worker } 50*90c8c64dSAndroid Build Coastguard Worker 51*90c8c64dSAndroid Build Coastguard Worker static async loadBugReport(defaulttimeMs: number) { 52*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.uploadFixture('bugreports/bugreport_stripped.zip'); 53*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.checkHasLoadedTracesFromBugReport(); 54*90c8c64dSAndroid Build Coastguard Worker expect(await E2eTestUtils.areMessagesEmitted(defaulttimeMs)).toBeTruthy(); 55*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.checkEmitsUnsupportedFileFormatMessages(); 56*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.checkEmitsOldDataMessages(); 57*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.closeSnackBar(); 58*90c8c64dSAndroid Build Coastguard Worker } 59*90c8c64dSAndroid Build Coastguard Worker 60*90c8c64dSAndroid Build Coastguard Worker static async areMessagesEmitted(defaultTimeoutMs: number): Promise<boolean> { 61*90c8c64dSAndroid Build Coastguard Worker // Messages are emitted quickly. There is no Need to wait for the entire 62*90c8c64dSAndroid Build Coastguard Worker // default timeout to understand whether the messages where emitted or not. 63*90c8c64dSAndroid Build Coastguard Worker await browser.manage().timeouts().implicitlyWait(1000); 64*90c8c64dSAndroid Build Coastguard Worker const emitted = await element(by.css('snack-bar')).isPresent(); 65*90c8c64dSAndroid Build Coastguard Worker await browser.manage().timeouts().implicitlyWait(defaultTimeoutMs); 66*90c8c64dSAndroid Build Coastguard Worker return emitted; 67*90c8c64dSAndroid Build Coastguard Worker } 68*90c8c64dSAndroid Build Coastguard Worker 69*90c8c64dSAndroid Build Coastguard Worker static async clickViewTracesButton() { 70*90c8c64dSAndroid Build Coastguard Worker const button = element(by.css('.load-btn')); 71*90c8c64dSAndroid Build Coastguard Worker await button.click(); 72*90c8c64dSAndroid Build Coastguard Worker } 73*90c8c64dSAndroid Build Coastguard Worker 74*90c8c64dSAndroid Build Coastguard Worker static async clickClearAllButton() { 75*90c8c64dSAndroid Build Coastguard Worker const button = element(by.css('.clear-all-btn')); 76*90c8c64dSAndroid Build Coastguard Worker await button.click(); 77*90c8c64dSAndroid Build Coastguard Worker } 78*90c8c64dSAndroid Build Coastguard Worker 79*90c8c64dSAndroid Build Coastguard Worker static async clickCloseIcon() { 80*90c8c64dSAndroid Build Coastguard Worker const button = element.all(by.css('.uploaded-files button')).first(); 81*90c8c64dSAndroid Build Coastguard Worker await button.click(); 82*90c8c64dSAndroid Build Coastguard Worker } 83*90c8c64dSAndroid Build Coastguard Worker 84*90c8c64dSAndroid Build Coastguard Worker static async clickDownloadTracesButton() { 85*90c8c64dSAndroid Build Coastguard Worker const button = element(by.css('.save-button')); 86*90c8c64dSAndroid Build Coastguard Worker await button.click(); 87*90c8c64dSAndroid Build Coastguard Worker } 88*90c8c64dSAndroid Build Coastguard Worker 89*90c8c64dSAndroid Build Coastguard Worker static async clickUploadNewButton() { 90*90c8c64dSAndroid Build Coastguard Worker const button = element(by.css('.upload-new')); 91*90c8c64dSAndroid Build Coastguard Worker await button.click(); 92*90c8c64dSAndroid Build Coastguard Worker } 93*90c8c64dSAndroid Build Coastguard Worker 94*90c8c64dSAndroid Build Coastguard Worker static async closeSnackBar() { 95*90c8c64dSAndroid Build Coastguard Worker const closeButton = element(by.css('.snack-bar-action')); 96*90c8c64dSAndroid Build Coastguard Worker const isPresent = await closeButton.isPresent(); 97*90c8c64dSAndroid Build Coastguard Worker if (isPresent) { 98*90c8c64dSAndroid Build Coastguard Worker await closeButton.click(); 99*90c8c64dSAndroid Build Coastguard Worker } 100*90c8c64dSAndroid Build Coastguard Worker } 101*90c8c64dSAndroid Build Coastguard Worker 102*90c8c64dSAndroid Build Coastguard Worker static async clickViewerTabButton(title: string) { 103*90c8c64dSAndroid Build Coastguard Worker const tabs: ElementFinder[] = await element.all(by.css('trace-view .tab')); 104*90c8c64dSAndroid Build Coastguard Worker for (const tab of tabs) { 105*90c8c64dSAndroid Build Coastguard Worker const tabTitle = await tab.getText(); 106*90c8c64dSAndroid Build Coastguard Worker if (tabTitle.includes(title)) { 107*90c8c64dSAndroid Build Coastguard Worker await tab.click(); 108*90c8c64dSAndroid Build Coastguard Worker return; 109*90c8c64dSAndroid Build Coastguard Worker } 110*90c8c64dSAndroid Build Coastguard Worker } 111*90c8c64dSAndroid Build Coastguard Worker throw new Error(`could not find tab corresponding to ${title}`); 112*90c8c64dSAndroid Build Coastguard Worker } 113*90c8c64dSAndroid Build Coastguard Worker 114*90c8c64dSAndroid Build Coastguard Worker static async checkTimelineTraceSelector(trace: { 115*90c8c64dSAndroid Build Coastguard Worker icon: string; 116*90c8c64dSAndroid Build Coastguard Worker color: string; 117*90c8c64dSAndroid Build Coastguard Worker }) { 118*90c8c64dSAndroid Build Coastguard Worker const traceSelector = element(by.css('#trace-selector')); 119*90c8c64dSAndroid Build Coastguard Worker const text = await traceSelector.getText(); 120*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain(trace.icon); 121*90c8c64dSAndroid Build Coastguard Worker 122*90c8c64dSAndroid Build Coastguard Worker const icons = await element.all(by.css('.shown-selection .mat-icon')); 123*90c8c64dSAndroid Build Coastguard Worker const iconColors: string[] = []; 124*90c8c64dSAndroid Build Coastguard Worker for (const icon of icons) { 125*90c8c64dSAndroid Build Coastguard Worker iconColors.push(await icon.getCssValue('color')); 126*90c8c64dSAndroid Build Coastguard Worker } 127*90c8c64dSAndroid Build Coastguard Worker expect( 128*90c8c64dSAndroid Build Coastguard Worker iconColors.some((iconColor) => iconColor === trace.color), 129*90c8c64dSAndroid Build Coastguard Worker ).toBeTruthy(); 130*90c8c64dSAndroid Build Coastguard Worker } 131*90c8c64dSAndroid Build Coastguard Worker 132*90c8c64dSAndroid Build Coastguard Worker static async checkInitialRealTimestamp(timestamp: string) { 133*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.changeRealTimestampInWinscope(timestamp); 134*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.checkWinscopeRealTimestamp(timestamp.slice(12)); 135*90c8c64dSAndroid Build Coastguard Worker const prevEntryButton = element(by.css('#prev_entry_button')); 136*90c8c64dSAndroid Build Coastguard Worker const isDisabled = await prevEntryButton.getAttribute('disabled'); 137*90c8c64dSAndroid Build Coastguard Worker expect(isDisabled).toEqual('true'); 138*90c8c64dSAndroid Build Coastguard Worker } 139*90c8c64dSAndroid Build Coastguard Worker 140*90c8c64dSAndroid Build Coastguard Worker static async checkFinalRealTimestamp(timestamp: string) { 141*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.changeRealTimestampInWinscope(timestamp); 142*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.checkWinscopeRealTimestamp(timestamp.slice(12)); 143*90c8c64dSAndroid Build Coastguard Worker const nextEntryButton = element(by.css('#next_entry_button')); 144*90c8c64dSAndroid Build Coastguard Worker const isDisabled = await nextEntryButton.getAttribute('disabled'); 145*90c8c64dSAndroid Build Coastguard Worker expect(isDisabled).toEqual('true'); 146*90c8c64dSAndroid Build Coastguard Worker } 147*90c8c64dSAndroid Build Coastguard Worker 148*90c8c64dSAndroid Build Coastguard Worker static async checkWinscopeRealTimestamp(timestamp: string) { 149*90c8c64dSAndroid Build Coastguard Worker const inputElement = element(by.css('input[name="humanTimeInput"]')); 150*90c8c64dSAndroid Build Coastguard Worker const value = await inputElement.getAttribute('value'); 151*90c8c64dSAndroid Build Coastguard Worker expect(value).toEqual(timestamp); 152*90c8c64dSAndroid Build Coastguard Worker } 153*90c8c64dSAndroid Build Coastguard Worker 154*90c8c64dSAndroid Build Coastguard Worker static async changeRealTimestampInWinscope(newTimestamp: string) { 155*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.updateInputField('', 'humanTimeInput', newTimestamp); 156*90c8c64dSAndroid Build Coastguard Worker } 157*90c8c64dSAndroid Build Coastguard Worker 158*90c8c64dSAndroid Build Coastguard Worker static async checkWinscopeNsTimestamp(newTimestamp: string) { 159*90c8c64dSAndroid Build Coastguard Worker const inputElement = element(by.css('input[name="nsTimeInput"]')); 160*90c8c64dSAndroid Build Coastguard Worker const valueWithNsSuffix = await inputElement.getAttribute('value'); 161*90c8c64dSAndroid Build Coastguard Worker expect(valueWithNsSuffix).toEqual(newTimestamp + ' ns'); 162*90c8c64dSAndroid Build Coastguard Worker } 163*90c8c64dSAndroid Build Coastguard Worker 164*90c8c64dSAndroid Build Coastguard Worker static async changeNsTimestampInWinscope(newTimestamp: string) { 165*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.updateInputField('', 'nsTimeInput', newTimestamp); 166*90c8c64dSAndroid Build Coastguard Worker } 167*90c8c64dSAndroid Build Coastguard Worker 168*90c8c64dSAndroid Build Coastguard Worker static async filterHierarchy(viewer: string, filterString: string) { 169*90c8c64dSAndroid Build Coastguard Worker await E2eTestUtils.updateInputField( 170*90c8c64dSAndroid Build Coastguard Worker `${viewer} hierarchy-view .title-section`, 171*90c8c64dSAndroid Build Coastguard Worker 'filter', 172*90c8c64dSAndroid Build Coastguard Worker filterString, 173*90c8c64dSAndroid Build Coastguard Worker ); 174*90c8c64dSAndroid Build Coastguard Worker } 175*90c8c64dSAndroid Build Coastguard Worker 176*90c8c64dSAndroid Build Coastguard Worker static async updateInputField( 177*90c8c64dSAndroid Build Coastguard Worker inputFieldSelector: string, 178*90c8c64dSAndroid Build Coastguard Worker inputFieldName: string, 179*90c8c64dSAndroid Build Coastguard Worker newInput: string, 180*90c8c64dSAndroid Build Coastguard Worker ) { 181*90c8c64dSAndroid Build Coastguard Worker const inputElement = element( 182*90c8c64dSAndroid Build Coastguard Worker by.css(`${inputFieldSelector} input[name="${inputFieldName}"]`), 183*90c8c64dSAndroid Build Coastguard Worker ); 184*90c8c64dSAndroid Build Coastguard Worker const inputStringStep1 = newInput.slice(0, -1); 185*90c8c64dSAndroid Build Coastguard Worker const inputStringStep2 = newInput.slice(-1) + '\r\n'; 186*90c8c64dSAndroid Build Coastguard Worker const script = `document.querySelector("${inputFieldSelector} input[name=\\"${inputFieldName}\\"]").value = "${inputStringStep1}"`; 187*90c8c64dSAndroid Build Coastguard Worker await browser.executeScript(script); 188*90c8c64dSAndroid Build Coastguard Worker await inputElement.sendKeys(inputStringStep2); 189*90c8c64dSAndroid Build Coastguard Worker } 190*90c8c64dSAndroid Build Coastguard Worker 191*90c8c64dSAndroid Build Coastguard Worker static async selectItemInHierarchy(viewer: string, itemName: string) { 192*90c8c64dSAndroid Build Coastguard Worker const nodes: ElementFinder[] = await element.all( 193*90c8c64dSAndroid Build Coastguard Worker by.css(`${viewer} hierarchy-view .node`), 194*90c8c64dSAndroid Build Coastguard Worker ); 195*90c8c64dSAndroid Build Coastguard Worker for (const node of nodes) { 196*90c8c64dSAndroid Build Coastguard Worker const id = await node.getAttribute('id'); 197*90c8c64dSAndroid Build Coastguard Worker if (id.includes(itemName)) { 198*90c8c64dSAndroid Build Coastguard Worker const desc = node.element(by.css('.description')); 199*90c8c64dSAndroid Build Coastguard Worker await desc.click(); 200*90c8c64dSAndroid Build Coastguard Worker return; 201*90c8c64dSAndroid Build Coastguard Worker } 202*90c8c64dSAndroid Build Coastguard Worker } 203*90c8c64dSAndroid Build Coastguard Worker throw new Error(`could not find item matching ${itemName} in hierarchy`); 204*90c8c64dSAndroid Build Coastguard Worker } 205*90c8c64dSAndroid Build Coastguard Worker 206*90c8c64dSAndroid Build Coastguard Worker static async applyStateToHierarchyOptions( 207*90c8c64dSAndroid Build Coastguard Worker viewerSelector: string, 208*90c8c64dSAndroid Build Coastguard Worker shouldEnable: boolean, 209*90c8c64dSAndroid Build Coastguard Worker ) { 210*90c8c64dSAndroid Build Coastguard Worker const options: ElementFinder[] = await element.all( 211*90c8c64dSAndroid Build Coastguard Worker by.css(`${viewerSelector} hierarchy-view .view-controls .user-option`), 212*90c8c64dSAndroid Build Coastguard Worker ); 213*90c8c64dSAndroid Build Coastguard Worker for (const option of options) { 214*90c8c64dSAndroid Build Coastguard Worker const isEnabled = !(await option.getAttribute('class')).includes( 215*90c8c64dSAndroid Build Coastguard Worker 'not-enabled', 216*90c8c64dSAndroid Build Coastguard Worker ); 217*90c8c64dSAndroid Build Coastguard Worker if (shouldEnable && !isEnabled) { 218*90c8c64dSAndroid Build Coastguard Worker await option.click(); 219*90c8c64dSAndroid Build Coastguard Worker } else if (!shouldEnable && isEnabled) { 220*90c8c64dSAndroid Build Coastguard Worker await option.click(); 221*90c8c64dSAndroid Build Coastguard Worker } 222*90c8c64dSAndroid Build Coastguard Worker } 223*90c8c64dSAndroid Build Coastguard Worker } 224*90c8c64dSAndroid Build Coastguard Worker 225*90c8c64dSAndroid Build Coastguard Worker static async checkItemInPropertiesTree( 226*90c8c64dSAndroid Build Coastguard Worker viewer: string, 227*90c8c64dSAndroid Build Coastguard Worker itemName: string, 228*90c8c64dSAndroid Build Coastguard Worker expectedText: string, 229*90c8c64dSAndroid Build Coastguard Worker ) { 230*90c8c64dSAndroid Build Coastguard Worker const nodes = await element.all(by.css(`${viewer} .properties-view .node`)); 231*90c8c64dSAndroid Build Coastguard Worker for (const node of nodes) { 232*90c8c64dSAndroid Build Coastguard Worker const id: string = await node.getAttribute('id'); 233*90c8c64dSAndroid Build Coastguard Worker if (id === 'node' + itemName) { 234*90c8c64dSAndroid Build Coastguard Worker const text = await node.getText(); 235*90c8c64dSAndroid Build Coastguard Worker expect(text).toEqual(expectedText); 236*90c8c64dSAndroid Build Coastguard Worker return; 237*90c8c64dSAndroid Build Coastguard Worker } 238*90c8c64dSAndroid Build Coastguard Worker } 239*90c8c64dSAndroid Build Coastguard Worker throw new Error(`could not find item ${itemName} in properties tree`); 240*90c8c64dSAndroid Build Coastguard Worker } 241*90c8c64dSAndroid Build Coastguard Worker 242*90c8c64dSAndroid Build Coastguard Worker static async checkRectLabel(viewer: string, expectedLabel: string) { 243*90c8c64dSAndroid Build Coastguard Worker const labels = await element.all( 244*90c8c64dSAndroid Build Coastguard Worker by.css(`${viewer} rects-view .rect-label`), 245*90c8c64dSAndroid Build Coastguard Worker ); 246*90c8c64dSAndroid Build Coastguard Worker 247*90c8c64dSAndroid Build Coastguard Worker let foundLabel: ElementFinder | undefined; 248*90c8c64dSAndroid Build Coastguard Worker 249*90c8c64dSAndroid Build Coastguard Worker for (const label of labels) { 250*90c8c64dSAndroid Build Coastguard Worker const text = await label.getText(); 251*90c8c64dSAndroid Build Coastguard Worker if (text.includes(expectedLabel)) { 252*90c8c64dSAndroid Build Coastguard Worker foundLabel = label; 253*90c8c64dSAndroid Build Coastguard Worker break; 254*90c8c64dSAndroid Build Coastguard Worker } 255*90c8c64dSAndroid Build Coastguard Worker } 256*90c8c64dSAndroid Build Coastguard Worker 257*90c8c64dSAndroid Build Coastguard Worker expect(foundLabel).toBeTruthy(); 258*90c8c64dSAndroid Build Coastguard Worker } 259*90c8c64dSAndroid Build Coastguard Worker 260*90c8c64dSAndroid Build Coastguard Worker static async checkTotalScrollEntries( 261*90c8c64dSAndroid Build Coastguard Worker viewerSelector: string, 262*90c8c64dSAndroid Build Coastguard Worker numberOfEntries: number, 263*90c8c64dSAndroid Build Coastguard Worker scrollToBottom = false, 264*90c8c64dSAndroid Build Coastguard Worker ) { 265*90c8c64dSAndroid Build Coastguard Worker if (scrollToBottom) { 266*90c8c64dSAndroid Build Coastguard Worker const viewport = element(by.css(`${viewerSelector} .scroll`)); 267*90c8c64dSAndroid Build Coastguard Worker let lastId: string | undefined; 268*90c8c64dSAndroid Build Coastguard Worker let lastScrollEntryItemId = await E2eTestUtils.getLastScrollEntryItemId( 269*90c8c64dSAndroid Build Coastguard Worker viewerSelector, 270*90c8c64dSAndroid Build Coastguard Worker ); 271*90c8c64dSAndroid Build Coastguard Worker while (lastId !== lastScrollEntryItemId) { 272*90c8c64dSAndroid Build Coastguard Worker lastId = lastScrollEntryItemId; 273*90c8c64dSAndroid Build Coastguard Worker await viewport.sendKeys(protractor.Key.END); 274*90c8c64dSAndroid Build Coastguard Worker await new Promise<void>((resolve) => setTimeout(resolve, 500)); 275*90c8c64dSAndroid Build Coastguard Worker lastScrollEntryItemId = await E2eTestUtils.getLastScrollEntryItemId( 276*90c8c64dSAndroid Build Coastguard Worker viewerSelector, 277*90c8c64dSAndroid Build Coastguard Worker ); 278*90c8c64dSAndroid Build Coastguard Worker } 279*90c8c64dSAndroid Build Coastguard Worker } 280*90c8c64dSAndroid Build Coastguard Worker const entries = await element.all( 281*90c8c64dSAndroid Build Coastguard Worker by.css(`${viewerSelector} .scroll .entry`), 282*90c8c64dSAndroid Build Coastguard Worker ); 283*90c8c64dSAndroid Build Coastguard Worker expect(await entries[entries.length - 1].getAttribute('item-id')).toEqual( 284*90c8c64dSAndroid Build Coastguard Worker `${numberOfEntries - 1}`, 285*90c8c64dSAndroid Build Coastguard Worker ); 286*90c8c64dSAndroid Build Coastguard Worker } 287*90c8c64dSAndroid Build Coastguard Worker 288*90c8c64dSAndroid Build Coastguard Worker static async getLastScrollEntryItemId( 289*90c8c64dSAndroid Build Coastguard Worker viewerSelector: string, 290*90c8c64dSAndroid Build Coastguard Worker ): Promise<string> { 291*90c8c64dSAndroid Build Coastguard Worker const entries = await element.all( 292*90c8c64dSAndroid Build Coastguard Worker by.css(`${viewerSelector} .scroll .entry`), 293*90c8c64dSAndroid Build Coastguard Worker ); 294*90c8c64dSAndroid Build Coastguard Worker return await entries[entries.length - 1].getAttribute('item-id'); 295*90c8c64dSAndroid Build Coastguard Worker } 296*90c8c64dSAndroid Build Coastguard Worker 297*90c8c64dSAndroid Build Coastguard Worker static async toggleSelectFilterOptions( 298*90c8c64dSAndroid Build Coastguard Worker viewerSelector: string, 299*90c8c64dSAndroid Build Coastguard Worker filterSelector: string, 300*90c8c64dSAndroid Build Coastguard Worker options: string[], 301*90c8c64dSAndroid Build Coastguard Worker ) { 302*90c8c64dSAndroid Build Coastguard Worker await element( 303*90c8c64dSAndroid Build Coastguard Worker by.css( 304*90c8c64dSAndroid Build Coastguard Worker `${viewerSelector} .headers ${filterSelector} .mat-select-trigger`, 305*90c8c64dSAndroid Build Coastguard Worker ), 306*90c8c64dSAndroid Build Coastguard Worker ).click(); 307*90c8c64dSAndroid Build Coastguard Worker 308*90c8c64dSAndroid Build Coastguard Worker const optionElements: ElementFinder[] = await element.all( 309*90c8c64dSAndroid Build Coastguard Worker by.css('.mat-select-panel .mat-option'), 310*90c8c64dSAndroid Build Coastguard Worker ); 311*90c8c64dSAndroid Build Coastguard Worker for (const optionEl of optionElements) { 312*90c8c64dSAndroid Build Coastguard Worker const optionText = (await optionEl.getText()).trim(); 313*90c8c64dSAndroid Build Coastguard Worker if (options.some((option) => optionText === option)) { 314*90c8c64dSAndroid Build Coastguard Worker await optionEl.click(); 315*90c8c64dSAndroid Build Coastguard Worker } 316*90c8c64dSAndroid Build Coastguard Worker } 317*90c8c64dSAndroid Build Coastguard Worker 318*90c8c64dSAndroid Build Coastguard Worker const backdrop = await element( 319*90c8c64dSAndroid Build Coastguard Worker by.css('.cdk-overlay-backdrop'), 320*90c8c64dSAndroid Build Coastguard Worker ).getWebElement(); 321*90c8c64dSAndroid Build Coastguard Worker await browser.actions().mouseMove(backdrop, {x: 0, y: 0}).click().perform(); 322*90c8c64dSAndroid Build Coastguard Worker } 323*90c8c64dSAndroid Build Coastguard Worker 324*90c8c64dSAndroid Build Coastguard Worker static async uploadFixture(...paths: string[]) { 325*90c8c64dSAndroid Build Coastguard Worker const inputFile = element(by.css('input[type="file"]')); 326*90c8c64dSAndroid Build Coastguard Worker 327*90c8c64dSAndroid Build Coastguard Worker // Uploading multiple files is not properly supported but 328*90c8c64dSAndroid Build Coastguard Worker // chrome handles file paths joined with new lines 329*90c8c64dSAndroid Build Coastguard Worker await inputFile.sendKeys( 330*90c8c64dSAndroid Build Coastguard Worker paths.map((it) => E2eTestUtils.getFixturePath(it)).join('\n'), 331*90c8c64dSAndroid Build Coastguard Worker ); 332*90c8c64dSAndroid Build Coastguard Worker } 333*90c8c64dSAndroid Build Coastguard Worker 334*90c8c64dSAndroid Build Coastguard Worker static getFixturePath(filename: string): string { 335*90c8c64dSAndroid Build Coastguard Worker if (path.isAbsolute(filename)) { 336*90c8c64dSAndroid Build Coastguard Worker return filename; 337*90c8c64dSAndroid Build Coastguard Worker } 338*90c8c64dSAndroid Build Coastguard Worker return path.join( 339*90c8c64dSAndroid Build Coastguard Worker E2eTestUtils.getProjectRootPath(), 340*90c8c64dSAndroid Build Coastguard Worker 'src/test/fixtures', 341*90c8c64dSAndroid Build Coastguard Worker filename, 342*90c8c64dSAndroid Build Coastguard Worker ); 343*90c8c64dSAndroid Build Coastguard Worker } 344*90c8c64dSAndroid Build Coastguard Worker 345*90c8c64dSAndroid Build Coastguard Worker private static getProjectRootPath(): string { 346*90c8c64dSAndroid Build Coastguard Worker let root = __dirname; 347*90c8c64dSAndroid Build Coastguard Worker while (path.basename(root) !== 'winscope') { 348*90c8c64dSAndroid Build Coastguard Worker root = path.dirname(root); 349*90c8c64dSAndroid Build Coastguard Worker } 350*90c8c64dSAndroid Build Coastguard Worker return root; 351*90c8c64dSAndroid Build Coastguard Worker } 352*90c8c64dSAndroid Build Coastguard Worker 353*90c8c64dSAndroid Build Coastguard Worker private static async checkHasLoadedTracesFromBugReport() { 354*90c8c64dSAndroid Build Coastguard Worker const text = await element(by.css('.uploaded-files')).getText(); 355*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('Window Manager'); 356*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('Surface Flinger'); 357*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('Transactions'); 358*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('Transitions'); 359*90c8c64dSAndroid Build Coastguard Worker 360*90c8c64dSAndroid Build Coastguard Worker // Should be merged into a single Transitions trace 361*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('WM Transitions'); 362*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('Shell Transitions'); 363*90c8c64dSAndroid Build Coastguard Worker 364*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('layers_trace_from_transactions.winscope'); 365*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('transactions_trace.winscope'); 366*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('wm_transition_trace.winscope'); 367*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('shell_transition_trace.winscope'); 368*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('window_CRITICAL.proto'); 369*90c8c64dSAndroid Build Coastguard Worker 370*90c8c64dSAndroid Build Coastguard Worker // discards some traces due to old data 371*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('ProtoLog'); 372*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('IME Service'); 373*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('IME system_server'); 374*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('IME Clients'); 375*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('wm_log.winscope'); 376*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('ime_trace_service.winscope'); 377*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('ime_trace_managerservice.winscope'); 378*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('wm_trace.winscope'); 379*90c8c64dSAndroid Build Coastguard Worker expect(text).not.toContain('ime_trace_clients.winscope'); 380*90c8c64dSAndroid Build Coastguard Worker } 381*90c8c64dSAndroid Build Coastguard Worker 382*90c8c64dSAndroid Build Coastguard Worker private static async checkEmitsUnsupportedFileFormatMessages() { 383*90c8c64dSAndroid Build Coastguard Worker const text = await element(by.css('snack-bar')).getText(); 384*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('unsupported format'); 385*90c8c64dSAndroid Build Coastguard Worker } 386*90c8c64dSAndroid Build Coastguard Worker 387*90c8c64dSAndroid Build Coastguard Worker private static async checkEmitsOldDataMessages() { 388*90c8c64dSAndroid Build Coastguard Worker const text = await element(by.css('snack-bar')).getText(); 389*90c8c64dSAndroid Build Coastguard Worker expect(text).toContain('discarded because data is old'); 390*90c8c64dSAndroid Build Coastguard Worker } 391*90c8c64dSAndroid Build Coastguard Worker} 392*90c8c64dSAndroid Build Coastguard Worker 393*90c8c64dSAndroid Build Coastguard Workerexport {E2eTestUtils}; 394