diff --git a/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts b/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts index 36d4cf655eccf..7da822af1d4a7 100644 --- a/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts +++ b/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { SnapshotStorage } from '../../../../../trace-viewer/src/sw/snapshotStorage'; +import { SnapshotStorage } from '../../../utils/isomorphic/trace/snapshotStorage'; import { ManualPromise } from '../../../utils'; import { HarTracer } from '../../har/harTracer'; import { Snapshotter } from '../recorder/snapshotter'; -import type { SnapshotRenderer } from '../../../../../trace-viewer/src/sw/snapshotRenderer'; +import type { SnapshotRenderer } from '../../../utils/isomorphic/trace/snapshotRenderer'; import type { BrowserContext } from '../../browserContext'; import type { HarTracerDelegate } from '../../har/harTracer'; import type { Page } from '../../page'; diff --git a/packages/trace-viewer/src/sw/lruCache.ts b/packages/playwright-core/src/utils/isomorphic/lruCache.ts similarity index 100% rename from packages/trace-viewer/src/sw/lruCache.ts rename to packages/playwright-core/src/utils/isomorphic/lruCache.ts diff --git a/packages/playwright-core/src/utils/isomorphic/trace/DEPS.list b/packages/playwright-core/src/utils/isomorphic/trace/DEPS.list new file mode 100644 index 0000000000000..4192108ed5425 --- /dev/null +++ b/packages/playwright-core/src/utils/isomorphic/trace/DEPS.list @@ -0,0 +1,3 @@ +[*] +./** +../** diff --git a/packages/trace-viewer/src/types/entries.ts b/packages/playwright-core/src/utils/isomorphic/trace/entries.ts similarity index 94% rename from packages/trace-viewer/src/types/entries.ts rename to packages/playwright-core/src/utils/isomorphic/trace/entries.ts index c97a3e37c598b..b203acb9a19dd 100644 --- a/packages/trace-viewer/src/types/entries.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/entries.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { Language } from '../../../playwright-core/src/utils/isomorphic/locatorGenerators'; +import type { Language } from '../locatorGenerators'; import type { ResourceSnapshot } from '@trace/snapshot'; import type * as trace from '@trace/trace'; diff --git a/packages/trace-viewer/src/sw/snapshotRenderer.ts b/packages/playwright-core/src/utils/isomorphic/trace/snapshotRenderer.ts similarity index 94% rename from packages/trace-viewer/src/sw/snapshotRenderer.ts rename to packages/playwright-core/src/utils/isomorphic/trace/snapshotRenderer.ts index 6473688e6e475..64efaebb36281 100644 --- a/packages/trace-viewer/src/sw/snapshotRenderer.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/snapshotRenderer.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { escapeHTMLAttribute, escapeHTML } from '@isomorphic/stringUtils'; +import { escapeHTMLAttribute, escapeHTML } from '../stringUtils'; import type { FrameSnapshot, NodeNameAttributesChildNodesSnapshot, NodeSnapshot, RenderedFrameSnapshot, ResourceSnapshot, SubtreeReferenceSnapshot } from '@trace/snapshot'; -import type { PageEntry } from '../types/entries'; -import type { LRUCache } from './lruCache'; +import type { PageEntry } from './entries'; +import type { LRUCache } from '../lruCache'; function findClosest(items: T[], metric: (v: T) => number, target: number) { return items.find((item, index) => { @@ -254,7 +254,9 @@ declare global { function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefined)[]) { function applyPlaywrightAttributes(viewport: ViewportSize, ...targetIds: (string | undefined)[]) { - const searchParams = new URLSearchParams(location.search); + // eslint-disable-next-line no-restricted-globals + const win = window; + const searchParams = new URLSearchParams(win.location.search); const shouldPopulateCanvasFromScreenshot = searchParams.has('shouldPopulateCanvasFromScreenshot'); const isUnderTest = searchParams.has('isUnderTest'); @@ -268,7 +270,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine viewport, frames: new WeakMap(), }; - window['__playwright_frame_bounding_rects__'] = frameBoundingRectsInfo; + win['__playwright_frame_bounding_rects__'] = frameBoundingRectsInfo; const kPointerWarningTitle = 'Recorded click position in absolute coordinates did not' + ' match the center of the clicked element. This is likely due to a difference between' + @@ -279,7 +281,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine const targetElements: Element[] = []; const canvasElements: HTMLCanvasElement[] = []; - let topSnapshotWindow: Window = window; + let topSnapshotWindow: Window = win; while (topSnapshotWindow !== topSnapshotWindow.parent && !topSnapshotWindow.location.pathname.match(/\/page@[a-z0-9]+$/)) topSnapshotWindow = topSnapshotWindow.parent; @@ -342,7 +344,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine iframe.setAttribute('src', 'data:text/html,'); } else { // Retain query parameters to inherit name=, time=, pointX=, pointY= and other values from parent. - const url = new URL(window.location.href); + const url = new URL(win.location.href); // We can be loading iframe from within iframe, reset base to be absolute. const index = url.pathname.lastIndexOf('/snapshot/'); if (index !== -1) @@ -354,10 +356,10 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine { const body = root.querySelector(`body[__playwright_custom_elements__]`); - if (body && window.customElements) { + if (body && win.customElements) { const customElements = (body.getAttribute('__playwright_custom_elements__') || '').split(','); for (const elementName of customElements) - window.customElements.define(elementName, class extends HTMLElement {}); + win.customElements.define(elementName, class extends HTMLElement {}); } } @@ -387,7 +389,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine }; const onLoad = () => { - window.removeEventListener('load', onLoad); + win.removeEventListener('load', onLoad); for (const element of scrollTops) { element.scrollTop = +element.getAttribute('__playwright_scroll_top_')!; element.removeAttribute('__playwright_scroll_top_'); @@ -401,19 +403,19 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine frameBoundingRectsInfo.frames.get(element)!.scrollLeft = element.scrollTop; } - document.styleSheets[0].disabled = true; + win.document.styleSheets[0].disabled = true; - const search = new URL(window.location.href).searchParams; - const isTopFrame = window === topSnapshotWindow; + const search = new URL(win.location.href).searchParams; + const isTopFrame = win === topSnapshotWindow; if (search.get('pointX') && search.get('pointY')) { const pointX = +search.get('pointX')!; const pointY = +search.get('pointY')!; const hasInputTarget = search.has('hasInputTarget'); const hasTargetElements = targetElements.length > 0; - const roots = document.documentElement ? [document.documentElement] : []; + const roots = win.document.documentElement ? [win.document.documentElement] : []; for (const target of (hasTargetElements ? targetElements : roots)) { - const pointElement = document.createElement('x-pw-pointer'); + const pointElement = win.document.createElement('x-pw-pointer'); pointElement.style.position = 'fixed'; pointElement.style.backgroundColor = '#f44336'; pointElement.style.width = '20px'; @@ -436,7 +438,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine // "Warning symbol" indicates that action point is not 100% correct. // Note that action point is relative to the top frame, so we can only compare in the top frame. if (isTopFrame && (Math.abs(centerX - pointX) >= 10 || Math.abs(centerY - pointY) >= 10)) { - const warningElement = document.createElement('x-pw-pointer-warning'); + const warningElement = win.document.createElement('x-pw-pointer-warning'); warningElement.textContent = '⚠'; warningElement.style.fontSize = '19px'; warningElement.style.color = 'white'; @@ -445,13 +447,13 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine pointElement.appendChild(warningElement); pointElement.setAttribute('title', kPointerWarningTitle); } - document.documentElement.appendChild(pointElement); + win.document.documentElement.appendChild(pointElement); } else if (isTopFrame && !hasInputTarget) { // For actions without a target element, e.g. page.mouse.move(), // show the point at the recorded location, which is relative to the top frame. pointElement.style.left = pointX + 'px'; pointElement.style.top = pointY + 'px'; - document.documentElement.appendChild(pointElement); + win.document.documentElement.appendChild(pointElement); } } } @@ -459,7 +461,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine if (canvasElements.length > 0) { function drawCheckerboard(context: CanvasRenderingContext2D, canvas: HTMLCanvasElement) { function createCheckerboardPattern() { - const pattern = document.createElement('canvas'); + const pattern = win.document.createElement('canvas'); pattern.width = pattern.width / Math.floor(pattern.width / 24); pattern.height = pattern.height / Math.floor(pattern.height / 24); const context = pattern.getContext('2d')!; @@ -492,7 +494,7 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine continue; } - let currWindow: Window = window; + let currWindow: Window = win; while (currWindow !== topSnapshotWindow) { const iframe = currWindow.frameElement!; currWindow = currWindow.parent; @@ -553,10 +555,10 @@ function snapshotScript(viewport: ViewportSize, ...targetIds: (string | undefine } }; - const onDOMContentLoaded = () => visit(document); + const onDOMContentLoaded = () => visit(win.document); - window.addEventListener('load', onLoad); - window.addEventListener('DOMContentLoaded', onDOMContentLoaded); + win.addEventListener('load', onLoad); + win.addEventListener('DOMContentLoaded', onDOMContentLoaded); } return `\n(${applyPlaywrightAttributes.toString()})(${JSON.stringify(viewport)}${targetIds.map(id => `, "${id}"`).join('')})`; diff --git a/packages/trace-viewer/src/sw/snapshotServer.ts b/packages/playwright-core/src/utils/isomorphic/trace/snapshotServer.ts similarity index 96% rename from packages/trace-viewer/src/sw/snapshotServer.ts rename to packages/playwright-core/src/utils/isomorphic/trace/snapshotServer.ts index 64a86935402f7..843667af33606 100644 --- a/packages/trace-viewer/src/sw/snapshotServer.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/snapshotServer.ts @@ -19,8 +19,6 @@ import type { SnapshotRenderer } from './snapshotRenderer'; import type { SnapshotStorage } from './snapshotStorage'; import type { ResourceSnapshot } from '@trace/snapshot'; -type Point = { x: number, y: number }; - export class SnapshotServer { private _snapshotStorage: SnapshotStorage; private _resourceLoader: (sha1: string) => Promise; @@ -117,12 +115,6 @@ export class SnapshotServer { } } -declare global { - interface Window { - showSnapshot: (url: string, point?: Point) => Promise; - } -} - function removeHash(url: string) { try { const u = new URL(url); diff --git a/packages/trace-viewer/src/sw/snapshotStorage.ts b/packages/playwright-core/src/utils/isomorphic/trace/snapshotStorage.ts similarity index 97% rename from packages/trace-viewer/src/sw/snapshotStorage.ts rename to packages/playwright-core/src/utils/isomorphic/trace/snapshotStorage.ts index d08fba647001a..4b0206cfacb04 100644 --- a/packages/trace-viewer/src/sw/snapshotStorage.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/snapshotStorage.ts @@ -15,10 +15,10 @@ */ import { rewriteURLForCustomProtocol, SnapshotRenderer } from './snapshotRenderer'; -import { LRUCache } from './lruCache'; +import { LRUCache } from '../lruCache'; import type { FrameSnapshot, ResourceSnapshot } from '@trace/snapshot'; -import type { PageEntry } from '../types/entries'; +import type { PageEntry } from './entries'; export class SnapshotStorage { diff --git a/packages/trace-viewer/src/sw/traceModel.ts b/packages/playwright-core/src/utils/isomorphic/trace/traceLoader.ts similarity index 95% rename from packages/trace-viewer/src/sw/traceModel.ts rename to packages/playwright-core/src/utils/isomorphic/trace/traceLoader.ts index e86129c77856d..3f0b3ffdab875 100644 --- a/packages/trace-viewer/src/sw/traceModel.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/traceLoader.ts @@ -19,9 +19,9 @@ import { parseClientSideCallMetadata } from '@isomorphic/traceUtils'; import { SnapshotStorage } from './snapshotStorage'; import { TraceModernizer } from './traceModernizer'; -import type { ContextEntry } from '../types/entries'; +import type { ContextEntry } from './entries'; -export interface TraceModelBackend { +export interface TraceLoaderBackend { entryNames(): Promise; hasEntry(entryName: string): Promise; readText(entryName: string): Promise; @@ -30,16 +30,16 @@ export interface TraceModelBackend { traceURL(): string; } -export class TraceModel { +export class TraceLoader { contextEntries: ContextEntry[] = []; private _snapshotStorage: SnapshotStorage | undefined; - private _backend!: TraceModelBackend; + private _backend!: TraceLoaderBackend; private _resourceToContentType = new Map(); constructor() { } - async load(backend: TraceModelBackend, unzipProgress: (done: number, total: number) => void) { + async load(backend: TraceLoaderBackend, unzipProgress: (done: number, total: number) => void) { this._backend = backend; const ordinals: string[] = []; diff --git a/packages/trace-viewer/src/ui/modelUtil.ts b/packages/playwright-core/src/utils/isomorphic/trace/traceModel.ts similarity index 99% rename from packages/trace-viewer/src/ui/modelUtil.ts rename to packages/playwright-core/src/utils/isomorphic/trace/traceModel.ts index 6203992a99b25..4483815a3b1fd 100644 --- a/packages/trace-viewer/src/ui/modelUtil.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/traceModel.ts @@ -20,7 +20,7 @@ import type { Language } from '@isomorphic/locatorGenerators'; import type { ResourceSnapshot } from '@trace/snapshot'; import type * as trace from '@trace/trace'; import type { ActionTraceEvent } from '@trace/trace'; -import type { ActionEntry, ContextEntry, PageEntry } from '../types/entries'; +import type { ActionEntry, ContextEntry, PageEntry } from '@isomorphic/trace/entries'; import type { StackFrame } from '@protocol/channels'; import type { ActionGroup } from '@isomorphic/protocolFormatter'; @@ -61,7 +61,7 @@ export type ErrorDescription = { export type Attachment = trace.AfterActionTraceEventAttachment & { callId: string }; -export class MultiTraceModel { +export class TraceModel { readonly startTime: number; readonly endTime: number; readonly browserName: string; diff --git a/packages/trace-viewer/src/sw/traceModernizer.ts b/packages/playwright-core/src/utils/isomorphic/trace/traceModernizer.ts similarity index 99% rename from packages/trace-viewer/src/sw/traceModernizer.ts rename to packages/playwright-core/src/utils/isomorphic/trace/traceModernizer.ts index a2354c366ff56..f2b4f159deef0 100644 --- a/packages/trace-viewer/src/sw/traceModernizer.ts +++ b/packages/playwright-core/src/utils/isomorphic/trace/traceModernizer.ts @@ -21,7 +21,7 @@ import type * as traceV5 from './versions/traceV5'; import type * as traceV6 from './versions/traceV6'; import type * as traceV7 from './versions/traceV7'; import type * as traceV8 from './versions/traceV8'; -import type { ActionEntry, ContextEntry, PageEntry } from '../types/entries'; +import type { ActionEntry, ContextEntry, PageEntry } from './entries'; import type { SnapshotStorage } from './snapshotStorage'; export class TraceVersionError extends Error { @@ -299,6 +299,7 @@ export class TraceModernizer { class: metadata.type, method: metadata.method, params: metadata.params, + // eslint-disable-next-line no-restricted-globals wallTime: metadata.wallTime || Date.now(), log: metadata.log, beforeSnapshot: metadata.snapshots.find(s => s.title === 'before')?.snapshotName, diff --git a/packages/trace-viewer/src/sw/versions/traceV3.ts b/packages/playwright-core/src/utils/isomorphic/trace/versions/traceV3.ts similarity index 100% rename from packages/trace-viewer/src/sw/versions/traceV3.ts rename to packages/playwright-core/src/utils/isomorphic/trace/versions/traceV3.ts diff --git a/packages/trace-viewer/src/sw/versions/traceV4.ts b/packages/playwright-core/src/utils/isomorphic/trace/versions/traceV4.ts similarity index 100% rename from packages/trace-viewer/src/sw/versions/traceV4.ts rename to packages/playwright-core/src/utils/isomorphic/trace/versions/traceV4.ts diff --git a/packages/trace-viewer/src/sw/versions/traceV5.ts b/packages/playwright-core/src/utils/isomorphic/trace/versions/traceV5.ts similarity index 100% rename from packages/trace-viewer/src/sw/versions/traceV5.ts rename to packages/playwright-core/src/utils/isomorphic/trace/versions/traceV5.ts diff --git a/packages/trace-viewer/src/sw/versions/traceV6.ts b/packages/playwright-core/src/utils/isomorphic/trace/versions/traceV6.ts similarity index 100% rename from packages/trace-viewer/src/sw/versions/traceV6.ts rename to packages/playwright-core/src/utils/isomorphic/trace/versions/traceV6.ts diff --git a/packages/trace-viewer/src/sw/versions/traceV7.ts b/packages/playwright-core/src/utils/isomorphic/trace/versions/traceV7.ts similarity index 100% rename from packages/trace-viewer/src/sw/versions/traceV7.ts rename to packages/playwright-core/src/utils/isomorphic/trace/versions/traceV7.ts diff --git a/packages/trace-viewer/src/sw/versions/traceV8.ts b/packages/playwright-core/src/utils/isomorphic/trace/versions/traceV8.ts similarity index 100% rename from packages/trace-viewer/src/sw/versions/traceV8.ts rename to packages/playwright-core/src/utils/isomorphic/trace/versions/traceV8.ts diff --git a/packages/trace-viewer/src/sw/main.ts b/packages/trace-viewer/src/sw/main.ts index 4252972d072af..40f50c028f0a1 100644 --- a/packages/trace-viewer/src/sw/main.ts +++ b/packages/trace-viewer/src/sw/main.ts @@ -14,11 +14,12 @@ * limitations under the License. */ +import { SnapshotServer } from '@isomorphic/trace/snapshotServer'; +import { TraceLoader } from '@isomorphic/trace/traceLoader'; +import { TraceVersionError } from '@isomorphic/trace/traceModernizer'; + import { Progress, splitProgress } from './progress'; -import { SnapshotServer } from './snapshotServer'; -import { TraceModel } from './traceModel'; -import { FetchTraceModelBackend, traceFileURL, ZipTraceModelBackend } from './traceModelBackends'; -import { TraceVersionError } from './traceModernizer'; +import { FetchTraceLoaderBackend, traceFileURL, ZipTraceLoaderBackend } from './traceLoaderBackends'; type Client = { id: string; @@ -59,7 +60,7 @@ self.addEventListener('activate', function(event: any) { }); type LoadedTrace = { - traceModel: TraceModel; + traceLoader: TraceLoader; snapshotServer: SnapshotServer; }; @@ -105,23 +106,23 @@ function loadTrace(clientId: string, url: URL, isContextRequest: boolean, progre async function innerLoadTrace(traceUrl: string, progress: Progress): Promise { await gc(); - const traceModel = new TraceModel(); + const traceLoader = new TraceLoader(); try { // Allow 10% to hop from sw to page. const [fetchProgress, unzipProgress] = splitProgress(progress, [0.5, 0.4, 0.1]); - const backend = isLiveTrace(traceUrl) || traceUrl.endsWith('traces.dir') ? new FetchTraceModelBackend(traceUrl) : new ZipTraceModelBackend(traceUrl, fetchProgress); - await traceModel.load(backend, unzipProgress); + const backend = isLiveTrace(traceUrl) || traceUrl.endsWith('traces.dir') ? new FetchTraceLoaderBackend(traceUrl) : new ZipTraceLoaderBackend(traceUrl, fetchProgress); + await traceLoader.load(backend, unzipProgress); } catch (error: any) { // eslint-disable-next-line no-console console.error(error); - if (error?.message?.includes('Cannot find .trace file') && await traceModel.hasEntry('index.html')) + if (error?.message?.includes('Cannot find .trace file') && await traceLoader.hasEntry('index.html')) throw new Error('Could not load trace. Did you upload a Playwright HTML report instead? Make sure to extract the archive first and then double-click the index.html file or put it on a web server.'); if (error instanceof TraceVersionError) throw new Error(`Could not load trace from ${traceUrl}. ${error.message}`); throw new Error(`Could not load trace from ${traceUrl}. Make sure a valid Playwright Trace is accessible over this url.`); } - const snapshotServer = new SnapshotServer(traceModel.storage(), sha1 => traceModel.resourceForSha1(sha1)); - return { traceModel, snapshotServer }; + const snapshotServer = new SnapshotServer(traceLoader.storage(), sha1 => traceLoader.resourceForSha1(sha1)); + return { traceLoader, snapshotServer }; } async function doFetch(event: FetchEvent): Promise { @@ -204,7 +205,7 @@ async function doFetch(event: FetchEvent): Promise { return errorResponse; if (relativePath === '/contexts') { - return new Response(JSON.stringify(loadedTrace!.traceModel.contextEntries), { + return new Response(JSON.stringify(loadedTrace!.traceLoader.contextEntries), { status: 200, headers: { 'Content-Type': 'application/json' } }); @@ -221,7 +222,7 @@ async function doFetch(event: FetchEvent): Promise { } if (relativePath.startsWith('/sha1/')) { - const blob = await loadedTrace!.traceModel.resourceForSha1(relativePath.slice('/sha1/'.length)); + const blob = await loadedTrace!.traceLoader.resourceForSha1(relativePath.slice('/sha1/'.length)); if (blob) return new Response(blob, { status: 200, headers: downloadHeaders(url.searchParams) }); return new Response(null, { status: 404 }); diff --git a/packages/trace-viewer/src/sw/traceModelBackends.ts b/packages/trace-viewer/src/sw/traceLoaderBackends.ts similarity index 95% rename from packages/trace-viewer/src/sw/traceModelBackends.ts rename to packages/trace-viewer/src/sw/traceLoaderBackends.ts index da60e9c1e9811..6ee4cb4d52033 100644 --- a/packages/trace-viewer/src/sw/traceModelBackends.ts +++ b/packages/trace-viewer/src/sw/traceLoaderBackends.ts @@ -17,13 +17,13 @@ import * as zipImport from '@zip.js/zip.js/lib/zip-no-worker-inflate.js'; import type * as zip from '@zip.js/zip.js'; -import type { TraceModelBackend } from './traceModel'; +import type { TraceLoaderBackend } from '@isomorphic/trace/traceLoader'; const zipjs = zipImport as typeof zip; type Progress = (done: number, total: number) => undefined; -export class ZipTraceModelBackend implements TraceModelBackend { +export class ZipTraceLoaderBackend implements TraceLoaderBackend { private _zipReader: zip.ZipReader; private _entriesPromise: Promise>; private _traceURL: string; @@ -94,7 +94,7 @@ export class ZipTraceModelBackend implements TraceModelBackend { } } -export class FetchTraceModelBackend implements TraceModelBackend { +export class FetchTraceLoaderBackend implements TraceLoaderBackend { private _entriesPromise: Promise>; private _path: string; diff --git a/packages/trace-viewer/src/ui/actionList.tsx b/packages/trace-viewer/src/ui/actionList.tsx index b2b0ebc757523..16e4e716135b0 100644 --- a/packages/trace-viewer/src/ui/actionList.tsx +++ b/packages/trace-viewer/src/ui/actionList.tsx @@ -18,11 +18,11 @@ import type { ActionTraceEvent } from '@trace/trace'; import { clsx, msToString } from '@web/uiUtils'; import * as React from 'react'; import './actionList.css'; -import * as modelUtil from './modelUtil'; +import { stats, buildActionTree } from '@isomorphic/trace/traceModel'; import { asLocatorDescription, type Language } from '@isomorphic/locatorGenerators'; import type { TreeState } from '@web/components/treeView'; import { TreeView } from '@web/components/treeView'; -import type { ActionTraceEventInContext, ActionTreeItem } from './modelUtil'; +import type { ActionTraceEventInContext, ActionTreeItem } from '@isomorphic/trace/traceModel'; import type { Boundaries } from './geometry'; import { ToolbarButton } from '@web/components/toolbarButton'; import { testStatusIcon } from './testUtils'; @@ -60,7 +60,7 @@ export const ActionList: React.FC = ({ revealActionAttachment, isLive, }) => { - const { rootItem, itemMap } = React.useMemo(() => modelUtil.buildActionTree(actions), [actions]); + const { rootItem, itemMap } = React.useMemo(() => buildActionTree(actions), [actions]); const { selectedItem } = React.useMemo(() => { const selectedItem = selectedAction ? itemMap.get(selectedAction.callId) : undefined; @@ -122,7 +122,7 @@ export const renderAction = ( showAttachments?: boolean, }) => { const { sdkLanguage, revealConsole, revealActionAttachment, isLive, showDuration, showBadges, showAttachments } = options; - const { errors, warnings } = modelUtil.stats(action); + const { errors, warnings } = stats(action); const locator = action.params.selector ? asLocatorDescription(sdkLanguage || 'javascript', action.params.selector) : undefined; diff --git a/packages/trace-viewer/src/ui/attachmentsTab.tsx b/packages/trace-viewer/src/ui/attachmentsTab.tsx index 1f7d81354213c..f7bdd6bc18c57 100644 --- a/packages/trace-viewer/src/ui/attachmentsTab.tsx +++ b/packages/trace-viewer/src/ui/attachmentsTab.tsx @@ -25,7 +25,7 @@ import { linkifyText } from '@web/renderUtils'; import { clsx, useFlash } from '@web/uiUtils'; import { useTraceModel } from './traceModelContext'; -import type { Attachment, MultiTraceModel } from './modelUtil'; +import type { Attachment, TraceModel } from '@isomorphic/trace/traceModel'; type ExpandableAttachmentProps = { attachment: Attachment; @@ -155,13 +155,13 @@ export const AttachmentsTab: React.FunctionComponent<{ ; }; -export function attachmentURL(model: MultiTraceModel | undefined, attachment: Attachment) { +export function attachmentURL(model: TraceModel | undefined, attachment: Attachment) { if (model && attachment.sha1) return model.createRelativeUrl(`sha1/${attachment.sha1}`) ; return `file?path=${encodeURIComponent(attachment.path!)}`; } -function downloadURL(model: MultiTraceModel | undefined, attachment: Attachment) { +function downloadURL(model: TraceModel | undefined, attachment: Attachment) { let suffix = attachment.contentType ? `&dn=${encodeURIComponent(attachment.name)}` : ''; if (attachment.contentType) suffix += `&dct=${encodeURIComponent(attachment.contentType)}`; diff --git a/packages/trace-viewer/src/ui/callTab.tsx b/packages/trace-viewer/src/ui/callTab.tsx index 5accfc860523f..223027fc8c01a 100644 --- a/packages/trace-viewer/src/ui/callTab.tsx +++ b/packages/trace-viewer/src/ui/callTab.tsx @@ -23,7 +23,7 @@ import { CopyToClipboard } from './copyToClipboard'; import { asLocator } from '@isomorphic/locatorGenerators'; import type { Language } from '@isomorphic/locatorGenerators'; import { PlaceholderPanel } from './placeholderPanel'; -import type { ActionTraceEventInContext } from './modelUtil'; +import type { ActionTraceEventInContext } from '@isomorphic/trace/traceModel'; import { renderTitleForCall } from './actionList'; export const CallTab: React.FunctionComponent<{ diff --git a/packages/trace-viewer/src/ui/consoleTab.tsx b/packages/trace-viewer/src/ui/consoleTab.tsx index f56005afdceb1..8194e973e4d44 100644 --- a/packages/trace-viewer/src/ui/consoleTab.tsx +++ b/packages/trace-viewer/src/ui/consoleTab.tsx @@ -17,7 +17,7 @@ import type * as channels from '@protocol/channels'; import * as React from 'react'; import './consoleTab.css'; -import type * as modelUtil from './modelUtil'; +import type { TraceModel } from '@isomorphic/trace/traceModel'; import { ListView } from '@web/components/listView'; import type { Boundaries } from './geometry'; import { clsx, msToString } from '@web/uiUtils'; @@ -47,7 +47,7 @@ type ConsoleTabModel = { const ConsoleListView = ListView; -export function useConsoleTabModel(model: modelUtil.MultiTraceModel | undefined, selectedTime: Boundaries | undefined): ConsoleTabModel { +export function useConsoleTabModel(model: TraceModel | undefined, selectedTime: Boundaries | undefined): ConsoleTabModel { const { entries } = React.useMemo(() => { if (!model) return { entries: [] }; diff --git a/packages/trace-viewer/src/ui/errorsTab.tsx b/packages/trace-viewer/src/ui/errorsTab.tsx index 21f12e83d4148..a93bcd1f82bae 100644 --- a/packages/trace-viewer/src/ui/errorsTab.tsx +++ b/packages/trace-viewer/src/ui/errorsTab.tsx @@ -16,7 +16,7 @@ import { ErrorMessage } from '@web/components/errorMessage'; import * as React from 'react'; -import type * as modelUtil from './modelUtil'; +import type { TraceModel, ErrorDescription } from '@isomorphic/trace/traceModel'; import { PlaceholderPanel } from './placeholderPanel'; import { renderAction } from './actionList'; import type { Language } from '@isomorphic/locatorGenerators'; @@ -41,21 +41,21 @@ const CopyPromptButton: React.FC<{ prompt: string }> = ({ prompt }) => { }; type ErrorsTabModel = { - errors: Map; + errors: Map; }; -export function useErrorsTabModel(model: modelUtil.MultiTraceModel | undefined): ErrorsTabModel { +export function useErrorsTabModel(model: TraceModel | undefined): ErrorsTabModel { return React.useMemo(() => { if (!model) return { errors: new Map() }; - const errors = new Map(); + const errors = new Map(); for (const error of model.errorDescriptors) errors.set(error.message, error); return { errors }; }, [model]); } -function ErrorView({ message, error, sdkLanguage, revealInSource }: { message: string, error: modelUtil.ErrorDescription, sdkLanguage: Language, revealInSource: (error: modelUtil.ErrorDescription) => void }) { +function ErrorView({ message, error, sdkLanguage, revealInSource }: { message: string, error: ErrorDescription, sdkLanguage: Language, revealInSource: (error: ErrorDescription) => void }) { let location: string | undefined; let longLocation: string | undefined; const stackFrame = error.stack?.[0]; @@ -88,7 +88,7 @@ export const ErrorsTab: React.FunctionComponent<{ errorsModel: ErrorsTabModel, wallTime: number, sdkLanguage: Language, - revealInSource: (error: modelUtil.ErrorDescription) => void, + revealInSource: (error: ErrorDescription) => void, testRunMetadata: MetadataWithCommitInfo | undefined, }> = ({ errorsModel, sdkLanguage, revealInSource, wallTime, testRunMetadata }) => { const model = useTraceModel(); @@ -99,7 +99,7 @@ export const ErrorsTab: React.FunctionComponent<{ return await fetch(attachmentURL(model, attachment)).then(r => r.text()); }, [model], undefined); - const buildCodeFrame = React.useCallback(async (error: modelUtil.ErrorDescription) => { + const buildCodeFrame = React.useCallback(async (error: ErrorDescription) => { const location = error.stack?.[0]; if (!location) return; diff --git a/packages/trace-viewer/src/ui/filmStrip.tsx b/packages/trace-viewer/src/ui/filmStrip.tsx index 935a205433a25..c3910767c1a2a 100644 --- a/packages/trace-viewer/src/ui/filmStrip.tsx +++ b/packages/trace-viewer/src/ui/filmStrip.tsx @@ -18,8 +18,8 @@ import './filmStrip.css'; import type { Boundaries, Size } from './geometry'; import * as React from 'react'; import { useMeasure, upperBound } from '@web/uiUtils'; -import type { PageEntry } from '../types/entries'; -import type { ActionTraceEventInContext } from './modelUtil'; +import type { PageEntry } from '@isomorphic/trace/entries'; +import type { ActionTraceEventInContext } from '@isomorphic/trace/traceModel'; import { renderAction } from './actionList'; import type { Language } from '@isomorphic/locatorGenerators'; import { useTraceModel } from './traceModelContext'; diff --git a/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx b/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx index d01b64e3c0110..10e98eb7a16c9 100644 --- a/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx +++ b/packages/trace-viewer/src/ui/liveWorkbenchLoader.tsx @@ -15,14 +15,14 @@ */ import * as React from 'react'; -import { MultiTraceModel } from './modelUtil'; +import { TraceModel } from '@isomorphic/trace/traceModel'; import './workbenchLoader.css'; import { Workbench } from './workbench'; -import type { ContextEntry } from '../types/entries'; +import type { ContextEntry } from '@isomorphic/trace/entries'; export const LiveWorkbenchLoader: React.FC<{ traceJson: string }> = ({ traceJson }) => { - const [model, setModel] = React.useState(undefined); + const [model, setModel] = React.useState(undefined); const [counter, setCounter] = React.useState(0); const pollTimer = React.useRef(null); @@ -36,7 +36,7 @@ export const LiveWorkbenchLoader: React.FC<{ traceJson: string }> = ({ traceJson const model = await loadSingleTraceFile(traceJson); setModel(model); } catch { - const model = new MultiTraceModel('', []); + const model = new TraceModel('', []); setModel(model); } finally { setCounter(counter + 1); @@ -51,10 +51,10 @@ export const LiveWorkbenchLoader: React.FC<{ traceJson: string }> = ({ traceJson return ; }; -async function loadSingleTraceFile(traceJson: string): Promise { +async function loadSingleTraceFile(traceJson: string): Promise { const params = new URLSearchParams(); params.set('trace', traceJson); const response = await fetch(`contexts?${params.toString()}`); const contextEntries = await response.json() as ContextEntry[]; - return new MultiTraceModel(traceJson, contextEntries); + return new TraceModel(traceJson, contextEntries); } diff --git a/packages/trace-viewer/src/ui/logTab.tsx b/packages/trace-viewer/src/ui/logTab.tsx index 89bf177461474..a98c433855ff0 100644 --- a/packages/trace-viewer/src/ui/logTab.tsx +++ b/packages/trace-viewer/src/ui/logTab.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { ActionTraceEventInContext } from './modelUtil'; +import type { ActionTraceEventInContext } from '@isomorphic/trace/traceModel'; import * as React from 'react'; import { ListView } from '@web/components/listView'; import { PlaceholderPanel } from './placeholderPanel'; diff --git a/packages/trace-viewer/src/ui/metadataView.tsx b/packages/trace-viewer/src/ui/metadataView.tsx index cb737a8e78584..20d3b6c5a9a27 100644 --- a/packages/trace-viewer/src/ui/metadataView.tsx +++ b/packages/trace-viewer/src/ui/metadataView.tsx @@ -16,11 +16,11 @@ import { msToString } from '@web/uiUtils'; import * as React from 'react'; -import type { MultiTraceModel } from './modelUtil'; +import type { TraceModel } from '@isomorphic/trace/traceModel'; import './callTab.css'; export const MetadataView: React.FunctionComponent<{ - model?: MultiTraceModel, + model?: TraceModel, }> = ({ model }) => { if (!model) return <>; diff --git a/packages/trace-viewer/src/ui/networkTab.tsx b/packages/trace-viewer/src/ui/networkTab.tsx index 24fe2034d99d8..6a6071b3ce40c 100644 --- a/packages/trace-viewer/src/ui/networkTab.tsx +++ b/packages/trace-viewer/src/ui/networkTab.tsx @@ -21,10 +21,11 @@ import './networkTab.css'; import { NetworkResourceDetails } from './networkResourceDetails'; import { bytesToString, msToString } from '@web/uiUtils'; import { PlaceholderPanel } from './placeholderPanel'; -import { context, type MultiTraceModel } from './modelUtil'; +import { context } from '@isomorphic/trace/traceModel'; +import type { TraceModel } from '@isomorphic/trace/traceModel'; import { GridView, type RenderedGridCell } from '@web/components/gridView'; import { SplitView } from '@web/components/splitView'; -import type { ContextEntry } from '../types/entries'; +import type { ContextEntry } from '@isomorphic/trace/entries'; import { NetworkFilters, defaultFilterState, type FilterState, type ResourceType } from './networkFilters'; import type { Language } from '@isomorphic/locatorGenerators'; @@ -50,7 +51,7 @@ type ColumnName = keyof RenderedEntry; type Sorting = { by: ColumnName, negate: boolean}; const NetworkGridView = GridView; -export function useNetworkTabModel(model: MultiTraceModel | undefined, selectedTime: Boundaries | undefined): NetworkTabModel { +export function useNetworkTabModel(model: TraceModel | undefined, selectedTime: Boundaries | undefined): NetworkTabModel { const resources = React.useMemo(() => { const resources = model?.resources || []; const filtered = resources.filter(resource => { @@ -218,7 +219,7 @@ class ContextIdMap { private _lastPageId = 0; private _lastApiRequestContextId = 0; - constructor(model: MultiTraceModel | undefined) {} + constructor(model: TraceModel | undefined) {} contextId(resource: Entry): string { if (resource.pageref) diff --git a/packages/trace-viewer/src/ui/snapshotTab.tsx b/packages/trace-viewer/src/ui/snapshotTab.tsx index 382e459829532..94cf2c1be40c8 100644 --- a/packages/trace-viewer/src/ui/snapshotTab.tsx +++ b/packages/trace-viewer/src/ui/snapshotTab.tsx @@ -17,7 +17,8 @@ import './snapshotTab.css'; import * as React from 'react'; import type { ActionTraceEvent } from '@trace/trace'; -import { type MultiTraceModel, nextActionByStartTime, previousActionByEndTime } from './modelUtil'; +import { nextActionByStartTime, previousActionByEndTime } from '@isomorphic/trace/traceModel'; +import type { TraceModel } from '@isomorphic/trace/traceModel'; import { Toolbar } from '@web/components/toolbar'; import { ToolbarButton } from '@web/components/toolbarButton'; import { clsx, useMeasure, useSetting } from '@web/uiUtils'; @@ -40,7 +41,7 @@ export type HighlightedElement = { export const SnapshotTabsView: React.FunctionComponent<{ action: ActionTraceEvent | undefined, - model?: MultiTraceModel, + model?: TraceModel, sdkLanguage: Language, testIdAttributeName: string, isInspecting: boolean, diff --git a/packages/trace-viewer/src/ui/sourceTab.tsx b/packages/trace-viewer/src/ui/sourceTab.tsx index 3799096cb1f4f..a1fb1bd0a31ab 100644 --- a/packages/trace-viewer/src/ui/sourceTab.tsx +++ b/packages/trace-viewer/src/ui/sourceTab.tsx @@ -21,7 +21,7 @@ import './sourceTab.css'; import { StackTraceView } from './stackTrace'; import { CodeMirrorWrapper } from '@web/components/codeMirrorWrapper'; import type { SourceHighlight } from '@web/components/codeMirrorWrapper'; -import type { SourceLocation, SourceModel } from './modelUtil'; +import type { SourceLocation, SourceModel } from '@isomorphic/trace/traceModel'; import type { StackFrame } from '@protocol/channels'; import { CopyToClipboard } from './copyToClipboard'; import { ToolbarButton } from '@web/components/toolbarButton'; diff --git a/packages/trace-viewer/src/ui/timeline.tsx b/packages/trace-viewer/src/ui/timeline.tsx index fe78c9f20f08e..c22bad94c78b2 100644 --- a/packages/trace-viewer/src/ui/timeline.tsx +++ b/packages/trace-viewer/src/ui/timeline.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import type { Boundaries } from './geometry'; import { FilmStrip } from './filmStrip'; import type { FilmStripPreviewPoint } from './filmStrip'; -import type { ActionTraceEventInContext, MultiTraceModel } from './modelUtil'; +import type { ActionTraceEventInContext, TraceModel } from '@isomorphic/trace/traceModel'; import './timeline.css'; import type { Language } from '@isomorphic/locatorGenerators'; import type { Entry } from '@trace/har'; @@ -40,7 +40,7 @@ type TimelineBar = { }; export const Timeline: React.FunctionComponent<{ - model: MultiTraceModel | undefined, + model: TraceModel | undefined, consoleEntries: ConsoleEntry[] | undefined, networkResources: Entry[] | undefined, boundaries: Boundaries, diff --git a/packages/trace-viewer/src/ui/traceModelContext.tsx b/packages/trace-viewer/src/ui/traceModelContext.tsx index 8e930ae7fab59..ab307147dc148 100644 --- a/packages/trace-viewer/src/ui/traceModelContext.tsx +++ b/packages/trace-viewer/src/ui/traceModelContext.tsx @@ -15,9 +15,9 @@ */ import * as React from 'react'; -import type { MultiTraceModel } from './modelUtil'; +import type { TraceModel } from '@isomorphic/trace/traceModel'; -export const TraceModelContext = React.createContext(undefined); +export const TraceModelContext = React.createContext(undefined); export const useTraceModel = () => { return React.useContext(TraceModelContext); diff --git a/packages/trace-viewer/src/ui/uiModeTestListView.tsx b/packages/trace-viewer/src/ui/uiModeTestListView.tsx index 0c900b0f3cc7e..fe76b8a744c03 100644 --- a/packages/trace-viewer/src/ui/uiModeTestListView.tsx +++ b/packages/trace-viewer/src/ui/uiModeTestListView.tsx @@ -25,7 +25,7 @@ import '@web/third_party/vscode/codicon.css'; import { msToString } from '@web/uiUtils'; import type * as reporterTypes from 'playwright/types/testReporter'; import React from 'react'; -import type { SourceLocation } from './modelUtil'; +import type { SourceLocation } from '@isomorphic/trace/traceModel'; import { testStatusIcon } from './testUtils'; import './uiModeTestListView.css'; import type { TestServerConnection } from '@testIsomorphic/testServerConnection'; diff --git a/packages/trace-viewer/src/ui/uiModeTraceView.tsx b/packages/trace-viewer/src/ui/uiModeTraceView.tsx index 211639103bd4c..9f618d892343c 100644 --- a/packages/trace-viewer/src/ui/uiModeTraceView.tsx +++ b/packages/trace-viewer/src/ui/uiModeTraceView.tsx @@ -20,9 +20,9 @@ import '@web/common.css'; import '@web/third_party/vscode/codicon.css'; import type * as reporterTypes from 'playwright/types/testReporter'; import React from 'react'; -import type { ContextEntry } from '../types/entries'; -import type { SourceLocation } from './modelUtil'; -import { MultiTraceModel } from './modelUtil'; +import type { ContextEntry } from '@isomorphic/trace/entries'; +import type { SourceLocation } from '@isomorphic/trace/traceModel'; +import { TraceModel } from '@isomorphic/trace/traceModel'; import { Workbench } from './workbench'; export const TraceView: React.FC<{ @@ -32,7 +32,7 @@ export const TraceView: React.FC<{ revealSource?: boolean, pathSeparator: string, }> = ({ item, rootDir, onOpenExternally, revealSource, pathSeparator }) => { - const [model, setModel] = React.useState<{ model: MultiTraceModel, isLive: boolean } | undefined>(undefined); + const [model, setModel] = React.useState<{ model: TraceModel, isLive: boolean } | undefined>(undefined); const [counter, setCounter] = React.useState(0); const pollTimer = React.useRef(null); @@ -75,7 +75,7 @@ export const TraceView: React.FC<{ const model = await loadSingleTraceFile(traceLocation); setModel({ model, isLive: true }); } catch { - const model = new MultiTraceModel('', []); + const model = new TraceModel('', []); model.errorDescriptors.push(...result.errors.flatMap(error => !!error.message ? [{ message: error.message }] : [])); setModel({ model, isLive: false }); } finally { @@ -110,10 +110,10 @@ const outputDirForTestCase = (testCase: reporterTypes.TestCase): string | undefi return undefined; }; -async function loadSingleTraceFile(url: string): Promise { +async function loadSingleTraceFile(url: string): Promise { const params = new URLSearchParams(); params.set('trace', url); const response = await fetch(`contexts?${params.toString()}`); const contextEntries = await response.json() as ContextEntry[]; - return new MultiTraceModel(url, contextEntries); + return new TraceModel(url, contextEntries); } diff --git a/packages/trace-viewer/src/ui/uiModeView.tsx b/packages/trace-viewer/src/ui/uiModeView.tsx index 227c0ef332a47..9725a49c974a3 100644 --- a/packages/trace-viewer/src/ui/uiModeView.tsx +++ b/packages/trace-viewer/src/ui/uiModeView.tsx @@ -22,7 +22,7 @@ import { TeleSuiteUpdater, type TeleSuiteUpdaterProgress, type TeleSuiteUpdaterT import type { TeleTestCase } from '@testIsomorphic/teleReceiver'; import type * as reporterTypes from 'playwright/types/testReporter'; import { SplitView } from '@web/components/splitView'; -import type { SourceLocation } from './modelUtil'; +import type { SourceLocation } from '@isomorphic/trace/traceModel'; import './uiModeView.css'; import { ToolbarButton } from '@web/components/toolbarButton'; import { Toolbar } from '@web/components/toolbar'; diff --git a/packages/trace-viewer/src/ui/workbench.tsx b/packages/trace-viewer/src/ui/workbench.tsx index 36a38d155ac29..1475eee86175c 100644 --- a/packages/trace-viewer/src/ui/workbench.tsx +++ b/packages/trace-viewer/src/ui/workbench.tsx @@ -21,7 +21,7 @@ import { CallTab } from './callTab'; import { LogTab } from './logTab'; import { ErrorsTab, useErrorsTabModel } from './errorsTab'; import { ConsoleTab, useConsoleTabModel } from './consoleTab'; -import type * as modelUtil from './modelUtil'; +import type { TraceModel, SourceLocation, ActionTraceEventInContext, SourceModel } from '@isomorphic/trace/traceModel'; import { NetworkTab, useNetworkTabModel } from './networkTab'; import { SnapshotTabsView } from './snapshotTab'; import { SourceTab } from './sourceTab'; @@ -48,16 +48,16 @@ import { TraceModelContext } from './traceModelContext'; import type { TreeState } from '@web/components/treeView'; export type WorkbenchProps = { - model: modelUtil.MultiTraceModel | undefined; + model: TraceModel | undefined; showSourcesFirst?: boolean; rootDir?: string; - fallbackLocation?: modelUtil.SourceLocation; + fallbackLocation?: SourceLocation; isLive?: boolean; hideTimeline?: boolean; status?: UITestStatus; annotations?: TestAnnotation[]; inert?: boolean; - onOpenExternally?: (location: modelUtil.SourceLocation) => void; + onOpenExternally?: (location: SourceLocation) => void; revealSource?: boolean; testRunMetadata?: MetadataWithCommitInfo; }; @@ -95,7 +95,7 @@ const PartitionedWorkbench: React.FunctionComponent({ lastEdited: 'none' }); const [isInspecting, setIsInspectingState] = React.useState(false); - const setSelectedAction = React.useCallback((action: modelUtil.ActionTraceEventInContext | undefined) => { + const setSelectedAction = React.useCallback((action: ActionTraceEventInContext | undefined) => { setSelectedCallId(action?.callId); setRevealedErrorKey(undefined); }, [setSelectedCallId, setRevealedErrorKey]); @@ -107,11 +107,11 @@ const PartitionedWorkbench: React.FunctionComponent a.callId === highlightedCallId); }, [actions, highlightedCallId]); - const setHighlightedAction = React.useCallback((highlightedAction: modelUtil.ActionTraceEventInContext | undefined) => { + const setHighlightedAction = React.useCallback((highlightedAction: ActionTraceEventInContext | undefined) => { setHighlightedCallId(highlightedAction?.callId); }, [setHighlightedCallId]); - const sources = React.useMemo(() => model?.sources || new Map(), [model]); + const sources = React.useMemo(() => model?.sources || new Map(), [model]); React.useEffect(() => { setSelectedTime(undefined); @@ -146,7 +146,7 @@ const PartitionedWorkbench: React.FunctionComponent { + const onActionSelected = React.useCallback((action: ActionTraceEventInContext) => { setSelectedAction(action); setHighlightedAction(undefined); }, [setSelectedAction, setHighlightedAction]); diff --git a/packages/trace-viewer/src/ui/workbenchLoader.tsx b/packages/trace-viewer/src/ui/workbenchLoader.tsx index a7773945121e4..4efc4ccf64594 100644 --- a/packages/trace-viewer/src/ui/workbenchLoader.tsx +++ b/packages/trace-viewer/src/ui/workbenchLoader.tsx @@ -15,7 +15,7 @@ */ import * as React from 'react'; -import { MultiTraceModel } from './modelUtil'; +import { TraceModel } from '@isomorphic/trace/traceModel'; import './workbenchLoader.css'; import { Workbench } from './workbench'; import { TestServerConnection, WebSocketTestServerTransport } from '@testIsomorphic/testServerConnection'; @@ -28,7 +28,7 @@ export const WorkbenchLoader: React.FunctionComponent<{ const [isServer, setIsServer] = React.useState(false); const [traceURL, setTraceURL] = React.useState(); const [uploadedTraceName, setUploadedTraceName] = React.useState(); - const [model, setModel] = React.useState(emptyModel); + const [model, setModel] = React.useState(emptyModel); const [progress, setProgress] = React.useState<{ done: number, total: number }>({ done: 0, total: 0 }); const [dragOver, setDragOver] = React.useState(false); const [processingErrorMessage, setProcessingErrorMessage] = React.useState(null); @@ -149,7 +149,7 @@ export const WorkbenchLoader: React.FunctionComponent<{ return; } const contextEntries = await response.json(); - const model = new MultiTraceModel(traceURL, contextEntries); + const model = new TraceModel(traceURL, contextEntries); setProgress({ done: 0, total: 0 }); setModel(model); } finally { @@ -228,4 +228,4 @@ export const WorkbenchLoader: React.FunctionComponent<{ ; }; -export const emptyModel = new MultiTraceModel('', []); +export const emptyModel = new TraceModel('', []); diff --git a/packages/trace/src/trace.ts b/packages/trace/src/trace.ts index d26a51717834b..3ffa6c4586874 100644 --- a/packages/trace/src/trace.ts +++ b/packages/trace/src/trace.ts @@ -15,7 +15,7 @@ */ import type { FrameSnapshot, ResourceSnapshot } from './snapshot'; -import type { Language } from '../../playwright-core/src/utils/isomorphic/locatorGenerators'; +import type { Language } from '@isomorphic/locatorGenerators'; import type { Point, SerializedError, StackFrame } from '@protocol/channels'; export type Size = { width: number, height: number }; diff --git a/tests/config/utils.ts b/tests/config/utils.ts index 20c7ef39fc148..3d6224841144b 100644 --- a/tests/config/utils.ts +++ b/tests/config/utils.ts @@ -16,12 +16,12 @@ import type { Frame, Page } from 'playwright-core'; import { ZipFile } from '../../packages/playwright-core/lib/server/utils/zipFile'; -import type { TraceModelBackend } from '../../packages/trace-viewer/src/sw/traceModel'; +import type { TraceLoaderBackend } from '../../packages/playwright-core/src/utils/isomorphic/trace/traceLoader'; import type { StackFrame } from '../../packages/protocol/src/channels'; import { parseClientSideCallMetadata } from '../../packages/playwright-core/lib/utils/isomorphic/traceUtils'; -import { TraceModel } from '../../packages/trace-viewer/src/sw/traceModel'; -import type { ActionTreeItem } from '../../packages/trace-viewer/src/ui/modelUtil'; -import { buildActionTree, MultiTraceModel } from '../../packages/trace-viewer/src/ui/modelUtil'; +import { TraceLoader } from '../../packages/playwright-core/src/utils/isomorphic/trace/traceLoader'; +import type { ActionTreeItem } from '../../packages/playwright-core/src/utils/isomorphic/trace/traceModel'; +import { buildActionTree, TraceModel } from '../../packages/playwright-core/src/utils/isomorphic/trace/traceModel'; import type { ActionTraceEvent, ConsoleMessageTraceEvent, EventTraceEvent, TraceEvent } from '@trace/trace'; import { renderTitleForCall } from '../../packages/playwright-core/lib/utils/isomorphic/protocolFormatter'; @@ -159,11 +159,11 @@ export async function parseTraceRaw(file: string): Promise<{ events: any[], reso }; } -export async function parseTrace(file: string): Promise<{ resources: Map, events: (EventTraceEvent | ConsoleMessageTraceEvent)[], actions: ActionTraceEvent[], titles: string[], traceModel: TraceModel, model: MultiTraceModel, actionTree: string[], errors: string[] }> { +export async function parseTrace(file: string): Promise<{ resources: Map, events: (EventTraceEvent | ConsoleMessageTraceEvent)[], actions: ActionTraceEvent[], titles: string[], loader: TraceLoader, model: TraceModel, actionTree: string[], errors: string[] }> { const backend = new TraceBackend(file); - const traceModel = new TraceModel(); - await traceModel.load(backend, () => {}); - const model = new MultiTraceModel(file, traceModel.contextEntries); + const loader = new TraceLoader(); + await loader.load(backend, () => {}); + const model = new TraceModel(file, loader.contextEntries); const actions = model.filteredActions([]); const { rootItem } = buildActionTree(actions); const actionTree: string[] = []; @@ -181,7 +181,7 @@ export async function parseTrace(file: string): Promise<{ resources: Map e.message), model, - traceModel, + loader, actionTree, }; } @@ -211,7 +211,7 @@ const ansiRegex = new RegExp('[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*( export function stripAnsi(str: string): string { return str.replace(ansiRegex, ''); } -class TraceBackend implements TraceModelBackend { +class TraceBackend implements TraceLoaderBackend { private _fileName: string; private _entriesPromise: Promise>; readonly entries = new Map(); diff --git a/tests/playwright-test/playwright.reuse.spec.ts b/tests/playwright-test/playwright.reuse.spec.ts index 6f863fd717fe5..1e3c1d797c3da 100644 --- a/tests/playwright-test/playwright.reuse.spec.ts +++ b/tests/playwright-test/playwright.reuse.spec.ts @@ -139,7 +139,7 @@ test('should reuse context with trace if mode=when-possible', async ({ runInline ' Fixture "page"', ' Fixture "context"', ]); - expect(trace1.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0); + expect(trace1.loader.storage().snapshotsForTest().length).toBeGreaterThan(0); expect(fs.existsSync(testInfo.outputPath('test-results', 'reuse-one', 'trace-1.zip'))).toBe(false); const trace2 = await parseTrace(testInfo.outputPath('test-results', 'reuse-two', 'trace.zip')); @@ -156,7 +156,7 @@ test('should reuse context with trace if mode=when-possible', async ({ runInline ' Fixture "context"', ' afterAll hook', ]); - expect(trace2.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0); + expect(trace2.loader.storage().snapshotsForTest().length).toBeGreaterThan(0); }); test('should work with manually closed pages', async ({ runInlineTest }) => { @@ -482,7 +482,7 @@ test('should reset tracing', async ({ runInlineTest }, testInfo) => { 'Set content', 'Click', ]); - expect(trace1.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0); + expect(trace1.loader.storage().snapshotsForTest().length).toBeGreaterThan(0); const trace2 = await parseTrace(traceFile2); expect(trace2.titles).toEqual([ @@ -490,7 +490,7 @@ test('should reset tracing', async ({ runInlineTest }, testInfo) => { 'Fill "value"', 'Click', ]); - expect(trace1.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0); + expect(trace1.loader.storage().snapshotsForTest().length).toBeGreaterThan(0); }); test('should not delete others contexts', async ({ runInlineTest }) => { diff --git a/tests/playwright-test/playwright.trace.spec.ts b/tests/playwright-test/playwright.trace.spec.ts index 82420aa520a64..acaed54aef31c 100644 --- a/tests/playwright-test/playwright.trace.spec.ts +++ b/tests/playwright-test/playwright.trace.spec.ts @@ -1331,7 +1331,7 @@ test('should record trace snapshot for more obscure commands', async ({ runInlin 'After Hooks', ]); - const snapshots = trace.traceModel.storage(); + const snapshots = trace.loader.storage(); const snapshotFrameOrPageId = snapshots.snapshotsForTest()[0]; const countAction = trace.actions.find(a => a.method === 'queryCount');