Skip to content

Commit

Permalink
chore: fix ui mode to show screenshots (#26563)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Aug 20, 2023
1 parent 3ac61f5 commit 41c312c
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 34 deletions.
28 changes: 11 additions & 17 deletions packages/trace-viewer/src/sw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,11 @@ async function doFetch(event: FetchEvent): Promise<Response> {
return new Response(null, { status: 200 });
}

const traceUrl = url.searchParams.get('trace')!;
const { snapshotServer } = loadedTraces.get(traceUrl) || {};
const traceUrl = url.searchParams.get('trace');

if (relativePath === '/contexts') {
try {
const traceModel = await loadTrace(traceUrl, url.searchParams.get('traceFileName'), event.clientId, (done: number, total: number) => {
const traceModel = await loadTrace(traceUrl!, url.searchParams.get('traceFileName'), event.clientId, (done: number, total: number) => {
client.postMessage({ method: 'progress', params: { done, total } });
});
return new Response(JSON.stringify(traceModel!.contextEntries), {
Expand All @@ -101,12 +100,14 @@ async function doFetch(event: FetchEvent): Promise<Response> {
}

if (relativePath.startsWith('/snapshotInfo/')) {
const { snapshotServer } = loadedTraces.get(traceUrl!) || {};
if (!snapshotServer)
return new Response(null, { status: 404 });
return snapshotServer.serveSnapshotInfo(relativePath, url.searchParams);
}

if (relativePath.startsWith('/snapshot/')) {
const { snapshotServer } = loadedTraces.get(traceUrl!) || {};
if (!snapshotServer)
return new Response(null, { status: 404 });
const response = snapshotServer.serveSnapshot(relativePath, url.searchParams, url.href);
Expand All @@ -116,13 +117,13 @@ async function doFetch(event: FetchEvent): Promise<Response> {
}

if (relativePath.startsWith('/sha1/')) {
const download = url.searchParams.has('download');
// Sha1 for sources is based on the file path, can't load it of a random model.
const traceUrls = clientIdToTraceUrls.get(event.clientId);
for (const [trace, { traceModel }] of loadedTraces) {
// We will accept explicit ?trace= value as well as the clientId associated with the trace.
if (traceUrl !== trace && !traceUrls.includes(trace))
continue;
return await serveResource(traceModel, relativePath.slice('/sha1/'.length));
const sha1 = relativePath.slice('/sha1/'.length);
for (const trace of loadedTraces.values()) {
const blob = await trace.traceModel.resourceForSha1(sha1);
if (blob)
return new Response(blob, { status: 200, headers: download ? downloadHeadersForAttachment(trace.traceModel, sha1) : undefined });
}
return new Response(null, { status: 404 });
}
Expand All @@ -143,14 +144,7 @@ async function doFetch(event: FetchEvent): Promise<Response> {
return snapshotServer.serveResource(lookupUrls, request.method, snapshotUrl);
}

async function serveResource(traceModel: TraceModel, sha1: string): Promise<Response> {
const blob = await traceModel!.resourceForSha1(sha1);
if (blob)
return new Response(blob, { status: 200, headers: headersForResource(traceModel, sha1) });
return new Response(null, { status: 404 });
}

function headersForResource(traceModel: TraceModel, sha1: string): Headers | undefined {
function downloadHeadersForAttachment(traceModel: TraceModel, sha1: string): Headers | undefined {
const attachment = traceModel.attachmentForSha1(sha1);
if (!attachment)
return;
Expand Down
7 changes: 4 additions & 3 deletions packages/trace-viewer/src/ui/attachmentsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@ export const AttachmentsSection: React.FunctionComponent<{
}} />}
{screenshots.size ? <div className='attachments-section'>Screenshots</div> : undefined}
{[...screenshots].map((a, i) => {
const url = attachmentURL(traceUrl, a);
return <div className='attachment-item' key={`screenshot-${i}`}>
<div><img draggable='false' src={attachmentURL(traceUrl, a)} /></div>
<div><a href={attachmentURL(traceUrl, a)}>{a.name}</a></div>
<div><img draggable='false' src={url} /></div>
<div><a target='_blank' href={url}>{a.name}</a></div>
</div>;
})}
{otherAttachments.size ? <div className='attachments-section'>Attachments</div> : undefined}
{[...otherAttachments].map((a, i) => {
return <div className='attachment-item' key={`attachment-${i}`}>
<a href={attachmentURL(traceUrl, a)}>{a.name}</a>
<a href={attachmentURL(traceUrl, a) + '&download'}>{a.name}</a>
</div>;
})}
</>;
Expand Down
4 changes: 4 additions & 0 deletions packages/trace-viewer/src/ui/workbench.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ export const Workbench: React.FunctionComponent<{

const sources = React.useMemo(() => model?.sources || new Map(), [model]);

React.useEffect(() => {
setSelectedTime(undefined);
}, [model]);

React.useEffect(() => {
if (selectedAction && model?.actions.includes(selectedAction))
return;
Expand Down
4 changes: 4 additions & 0 deletions packages/web/src/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ body {
-webkit-font-smoothing: antialiased;
}

a {
color: var(--vscode-textLink-foreground);
}

* {
box-sizing: border-box;
min-width: 0;
Expand Down
27 changes: 13 additions & 14 deletions tests/playwright-test/ui-mode-test-attachments.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
* limitations under the License.
*/

import fs from 'fs';
import { test, expect, retries } from './ui-mode-fixtures';

test.describe.configure({ mode: 'parallel', retries });

test('should contain file attachment', async ({ runUITest }) => {
test('should contain text attachment', async ({ runUITest }) => {
const { page } = await runUITest({
'a.test.ts': `
import { test } from '@playwright/test';
Expand All @@ -40,46 +39,46 @@ test('should contain file attachment', async ({ runUITest }) => {
expect((await readAllFromStream(await download.createReadStream())).toString()).toContain('attach test');
});

test('should contain string attachment', async ({ runUITest }) => {
test('should contain binary attachment', async ({ runUITest }) => {
const { page } = await runUITest({
'a.test.ts': `
import { test } from '@playwright/test';
test('attach test', async () => {
await test.info().attach('note', { body: 'text42' });
await test.info().attach('data', { body: Buffer.from([1, 2, 3]), contentType: 'application/octet-stream' });
});
`,
});
await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
await page.getByText('Attachments').click();
await page.getByText('attach "note"', { exact: true }).click();
await page.getByText('attach "data"', { exact: true }).click();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: 'note' }).click();
await page.getByRole('link', { name: 'data' }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe('note');
expect((await readAllFromStream(await download.createReadStream())).toString()).toEqual('text42');
expect(download.suggestedFilename()).toBe('data');
expect(await readAllFromStream(await download.createReadStream())).toEqual(Buffer.from([1, 2, 3]));
});

test('should contain attachment with filename and extension', async ({ runUITest, asset }) => {
test('should contain string attachment', async ({ runUITest }) => {
const { page } = await runUITest({
'a.test.ts': `
import { test } from '@playwright/test';
test('attach test', async () => {
await test.info().attach('screenshot.png', { path: ${JSON.stringify(asset('pptr.png'))} });
await test.info().attach('note', { body: 'text42' });
});
`,
});
await page.getByText('attach test').click();
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)');
await page.getByText('Attachments').click();
await page.getByText('attach "screenshot.png"', { exact: true }).click();
await page.getByText('attach "note"', { exact: true }).click();
const downloadPromise = page.waitForEvent('download');
await page.getByRole('link', { name: 'screenshot.png' }).click();
await page.getByRole('link', { name: 'note' }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe('screenshot.png');
expect(await readAllFromStream(await download.createReadStream())).toEqual(fs.readFileSync(asset('pptr.png')));
expect(download.suggestedFilename()).toBe('note');
expect((await readAllFromStream(await download.createReadStream())).toString()).toEqual('text42');
});

function readAllFromStream(stream: NodeJS.ReadableStream): Promise<Buffer> {
Expand Down
49 changes: 49 additions & 0 deletions tests/playwright-test/ui-mode-test-screencast.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { test, expect, retries } from './ui-mode-fixtures';

test.describe.configure({ mode: 'parallel', retries });

test('should show screenshots', async ({ runUITest }) => {
const { page } = await runUITest({
'a.test.ts': `
import { test } from '@playwright/test';
test('test 1', async ({ page }) => {
await page.setContent('<div style="background: red; width: 100%; height: 100%"></div>');
await page.waitForTimeout(1000);
});
test('test 2', async ({ page }) => {
await page.setContent('<div style="background: blue; width: 100%; height: 100%"></div>');
await page.waitForTimeout(1000);
});
`,
});
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('2/2 passed (100%)');

await page.getByText('test 1', { exact: true }).click();
await expect(
page.locator('.CodeMirror .source-line-running'),
).toContainText(`test('test 1', async ({ page }) => {`);
await expect(page.locator('.film-strip-frame')).toBeVisible();

await page.getByText('test 2', { exact: true }).click();
await expect(
page.locator('.CodeMirror .source-line-running'),
).toContainText(`test('test 2', async ({ page }) => {`);
await expect(page.locator('.film-strip-frame')).toBeVisible();
});

0 comments on commit 41c312c

Please sign in to comment.