UNPKG

chrome-devtools-frontend

Version:
219 lines (196 loc) 10.5 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Trace from '../../../../models/trace/trace.js'; import { dispatchClickEvent, dispatchKeyDownEvent, querySelectorErrorOnMissing, raf, renderElementIntoDOM, } from '../../../../testing/DOMHelpers.js'; import {describeWithEnvironment} from '../../../../testing/EnvironmentHelpers.js'; import {TraceLoader} from '../../../../testing/TraceLoader.js'; import * as PerfUI from './perf_ui.js'; describeWithEnvironment('FilmStripView', function() { async function renderView(filmStripData: Trace.Extras.FilmStrip.Data): Promise<PerfUI.FilmStripView.FilmStripView> { const filmStripView = new PerfUI.FilmStripView.FilmStripView(); filmStripView.setModel(filmStripData); const container = document.createElement('div'); renderElementIntoDOM(container); filmStripView.markAsRoot(); filmStripView.show(container); // Give the film strip time to render. await raf(); return filmStripView; } it('generates frames and timestamps', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = await renderView(Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace)); const renderedFrames = Array.from(filmStrip.contentElement.querySelectorAll<HTMLElement>('button.frame')); assert.lengthOf(renderedFrames, 5); const expectedTimeLabelsForFrames = [ '0ms', '139ms', '222ms', '239ms', '289ms', ]; // Ensure for each frame that we rendered the right snapshot from the trace // data. And that the time label is as expected. renderedFrames.forEach((frame, index) => { const img = querySelectorErrorOnMissing<HTMLImageElement>(frame, 'img'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue(img.src.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[index].args.dataUri)); const timeElement = querySelectorErrorOnMissing<HTMLDivElement>(frame, '.time'); // Remove whitespace to avoid having to compare with &nbsp; in the // expected text. assert.strictEqual(timeElement.innerText.replace(/\s/, ''), expectedTimeLabelsForFrames[index]); }); assert.deepEqual(1, 1); filmStrip.detach(); }); it('shows status text', async function() { const filmStripView = new PerfUI.FilmStripView.FilmStripView(); filmStripView.markAsRoot(); renderElementIntoDOM(filmStripView); const expectedStatusText = 'Placeholder'; filmStripView.setStatusText(expectedStatusText); assert.deepEqual(filmStripView.contentElement.textContent, expectedStatusText); filmStripView.detach(); }); describe('FilmStripView Dialog', function() { async function renderDialogWithTrace(filmStrip: Trace.Extras.FilmStrip.Data, selectedFrameIndex: number): Promise<{dialog: PerfUI.FilmStripView.Dialog, shadowRoot: ShadowRoot}> { const dialogWidget = PerfUI.FilmStripView.Dialog.fromFilmStrip(filmStrip, selectedFrameIndex); // Give the dialog time to render await raf(); // Creating the dialog widget is enough to cause it to render, so now we can find the Dialog HTML. const container = document.body.querySelector<HTMLDivElement>('[data-devtools-glass-pane]'); const containerShadowRoot = container?.shadowRoot; if (!containerShadowRoot) { throw new Error('Could not find the Dialog shadowRoot'); } return {dialog: dialogWidget, shadowRoot: containerShadowRoot}; } it('renders and shows the provided frame by default', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, 0); const renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue( renderedImage?.currentSrc.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[0].args.dataUri)); dialog.hide(); }); it('does not let the user navigate back if they are at the first frame already', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, 0); const previousBtn = shadowRoot.querySelector('devtools-button'); assert.isTrue(previousBtn?.textContent === '◀' || previousBtn?.textContent === '&#9664;'); if (!previousBtn) { throw new Error('Could not find previous button'); } dispatchClickEvent(previousBtn); await raf(); const renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue( renderedImage?.currentSrc.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[0].args.dataUri)); dialog.hide(); }); it('lets the user navigate back to the previous frame with the mouse', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, 1); const previousBtn = shadowRoot.querySelector('devtools-button'); assert.isTrue(previousBtn?.textContent === '◀' || previousBtn?.textContent === '&#9664;'); if (!previousBtn) { throw new Error('Could not find previous button'); } dispatchClickEvent(previousBtn); await raf(); const renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue( renderedImage?.currentSrc.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[0].args.dataUri)); dialog.hide(); }); it('lets the user navigate back to the previous frame with the keyboard', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, 1); const renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); if (!renderedImage) { throw new Error('Could not find film-strip-dialog img'); } dispatchKeyDownEvent(renderedImage, { key: 'ArrowLeft', bubbles: true, }); await raf(); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue( renderedImage?.currentSrc.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[0].args.dataUri)); dialog.hide(); }); it('lets the user navigate forwards to the next frame with the mouse', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, 0); const nextBtn = shadowRoot.querySelectorAll('devtools-button')[1]; assert.isTrue(nextBtn.textContent === '▶' || nextBtn.textContent === '&#9654;'); if (!nextBtn) { throw new Error('Could not find next button'); } dispatchClickEvent(nextBtn); await raf(); const renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue( renderedImage?.currentSrc.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[1].args.dataUri)); dialog.hide(); }); it('does not let the user go beyond the last image', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const numberOfFrames = filmStrip.frames.length; const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, numberOfFrames - 1); let renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue(renderedImage?.currentSrc.includes( parsedTrace.Screenshots.legacySyntheticScreenshots[numberOfFrames - 1].args.dataUri)); const nextBtn = shadowRoot.querySelectorAll('devtools-button')[1]; assert.isTrue(nextBtn.textContent === '▶' || nextBtn.textContent === '&#9654;'); if (!nextBtn) { throw new Error('Could not find next button'); } dispatchClickEvent(nextBtn); await raf(); renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue(renderedImage?.currentSrc.includes( parsedTrace.Screenshots.legacySyntheticScreenshots[numberOfFrames - 1].args.dataUri)); dialog.hide(); }); it('lets the user navigate forwards to the next frame with the keyboard', async function() { const {parsedTrace} = await TraceLoader.traceEngine(this, 'web-dev.json.gz'); const filmStrip = Trace.Extras.FilmStrip.fromParsedTrace(parsedTrace); const {dialog, shadowRoot} = await renderDialogWithTrace(filmStrip, 0); const renderedImage = shadowRoot.querySelector<HTMLImageElement>('[data-film-strip-dialog-img]'); if (!renderedImage) { throw new Error('Could not find film-strip-dialog img'); } dispatchKeyDownEvent(renderedImage, { key: 'ArrowRight', bubbles: true, }); await raf(); assert.isOk(parsedTrace.Screenshots.legacySyntheticScreenshots); assert.isTrue( renderedImage?.currentSrc.includes(parsedTrace.Screenshots.legacySyntheticScreenshots[1].args.dataUri)); dialog.hide(); }); }); });