Merge branch 'main' into ui-trace-not-found-path

This commit is contained in:
Simon Knott 2024-11-04 17:24:09 +01:00
commit b62c5694d4
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
7 changed files with 51 additions and 28 deletions

View file

@ -254,7 +254,7 @@ Note that by default `toPass` has timeout 0 and does not respect custom [expect
You can extend Playwright assertions by providing custom matchers. These matchers will be available on the `expect` object.
In this example we add a custom `toHaveAmount` function. Custom matcher should return a `message` callback and a `pass` flag indicating whether the assertion passed.
In this example we add a custom `toHaveAmount` function. Custom matcher should return a `pass` flag indicating whether the assertion passed, and a `message` callback that's used when the assertion fails.
```js title="fixtures.ts"
import { expect as baseExpect } from '@playwright/test';
@ -279,7 +279,7 @@ export const expect = baseExpect.extend({
? () => this.utils.matcherHint(assertionName, undefined, undefined, { isNot: this.isNot }) +
'\n\n' +
`Locator: ${locator}\n` +
`Expected: ${this.isNot ? 'not' : ''}${this.utils.printExpected(expected)}\n` +
`Expected: not ${this.utils.printExpected(expected)}\n` +
(matcherResult ? `Received: ${this.utils.printReceived(matcherResult.actual)}` : '')
: () => this.utils.matcherHint(assertionName, undefined, undefined, { isNot: this.isNot }) +
'\n\n' +

View file

@ -106,8 +106,17 @@ export async function installRootRedirect(server: HttpServer, traceUrls: string[
const params = new URLSearchParams();
if (path.sep !== path.posix.sep)
params.set('pathSeparator', path.sep);
for (const traceUrl of traceUrls)
params.append('trace', traceUrl);
for (const traceUrl of traceUrls) {
if (traceUrl.startsWith('http://') || traceUrl.startsWith('https://')) {
params.append('trace', traceUrl);
continue;
}
// <testServerOrigin>/trace/file?path=/path/to/trace.zip
const url = new URL('/trace/file', server.urlPrefix('precise'));
url.searchParams.set('path', traceUrl);
params.append('trace', url.toString());
}
if (server.wsGuid())
params.append('ws', server.wsGuid()!);
if (options?.isServer)

View file

@ -30,9 +30,8 @@ export class ZipTraceModelBackend implements TraceModelBackend {
constructor(traceURL: string, progress: Progress) {
this._traceURL = traceURL;
zipjs.configure({ baseURL: self.location.href } as any);
this._zipReader = new zipjs.ZipReader(
new zipjs.HttpReader(formatUrl(traceURL), { mode: 'cors', preventHeadRequest: true } as any),
new zipjs.HttpReader(traceURL, { mode: 'cors', preventHeadRequest: true } as any),
{ useWebWorkers: false });
this._entriesPromise = this._zipReader.getEntries({ onprogress: progress }).then(entries => {
const map = new Map<string, zip.Entry>();
@ -87,10 +86,9 @@ export class FetchTraceModelBackend implements TraceModelBackend {
constructor(traceURL: string) {
this._traceURL = traceURL;
this._entriesPromise = fetch('/trace/file?path=' + encodeURIComponent(traceURL)).then(async response => {
this._entriesPromise = fetch(traceURL).then(async response => {
if (response.status === 404)
throw new Error(`trace not found`);
const json = await response.json();
const entries = new Map<string, string>();
for (const entry of json.entries)
@ -129,17 +127,12 @@ export class FetchTraceModelBackend implements TraceModelBackend {
private async _readEntry(entryName: string): Promise<Response | undefined> {
const entries = await this._entriesPromise;
const fileName = entries.get(entryName);
if (!fileName)
const filePath = entries.get(entryName);
if (!filePath)
return;
return fetch('/trace/file?path=' + encodeURIComponent(fileName));
const url = new URL(this.traceURL());
url.searchParams.set('path', filePath);
return fetch(url);
}
}
function formatUrl(trace: string) {
let url = trace.startsWith('http') || trace.startsWith('blob') ? trace : `file?path=${encodeURIComponent(trace)}`;
// Dropbox does not support cors.
if (url.startsWith('https://www.dropbox.com/'))
url = 'https://dl.dropboxusercontent.com/' + url.substring('https://www.dropbox.com/'.length);
return url;
}

View file

@ -21,6 +21,7 @@ import './embeddedWorkbenchLoader.css';
import { Workbench } from './workbench';
import { currentTheme, toggleTheme } from '@web/theme';
import type { SourceLocation } from './modelUtil';
import { filePathToTraceURL } from './uiModeTraceView';
function openPage(url: string, target?: string) {
if (url)
@ -40,7 +41,15 @@ export const EmbeddedWorkbenchLoader: React.FunctionComponent = () => {
React.useEffect(() => {
window.addEventListener('message', async ({ data: { method, params } }) => {
if (method === 'loadTraceRequested') {
setTraceURLs(params.traceUrl ? [params.traceUrl] : []);
if (params.traceUrl) {
// the param is called URL, but VS Code sends a path
const url = params.traceUrl.startsWith('http')
? params.traceUrl
: filePathToTraceURL(params.traceUrl).toString();
setTraceURLs([url]);
} else {
setTraceURLs([]);
}
setProcessingErrorMessage(null);
} else if (method === 'applyTheme') {
if (currentTheme() !== params.theme)

View file

@ -53,7 +53,7 @@ export const TraceView: React.FC<{
// Test finished.
const attachment = result && result.duration >= 0 && result.attachments.find(a => a.name === 'trace');
if (attachment && attachment.path) {
loadSingleTraceFile(attachment.path).then(model => {
loadSingleTraceFile(filePathToTraceURL(attachment.path)).then(model => {
if (model)
setModel({ model, isLive: false });
});
@ -74,7 +74,7 @@ export const TraceView: React.FC<{
// Start polling running test.
pollTimer.current = setTimeout(async () => {
try {
const model = await loadSingleTraceFile(traceLocation);
const model = await loadSingleTraceFile(filePathToTraceURL(traceLocation));
if (model)
setModel({ model, isLive: true });
} catch {
@ -109,9 +109,9 @@ const outputDirForTestCase = (testCase: reporterTypes.TestCase): string | undefi
return undefined;
};
async function loadSingleTraceFile(url: string): Promise<MultiTraceModel | undefined> {
async function loadSingleTraceFile(traceURL: URL): Promise<MultiTraceModel | undefined> {
const params = new URLSearchParams();
params.set('trace', url);
params.set('trace', formatUrl(traceURL).toString());
params.set('limit', '1');
const response = await fetch(`contexts?${params.toString()}`);
if (response.status === 404)
@ -119,3 +119,17 @@ async function loadSingleTraceFile(url: string): Promise<MultiTraceModel | undef
const contextEntries = await response.json() as ContextEntry[];
return new MultiTraceModel(contextEntries);
}
function formatUrl(traceURL: URL) {
// Dropbox does not support cors.
if (traceURL.hostname === 'dropbox.com')
traceURL.hostname = 'dl.dropboxusercontent.com';
return traceURL;
}
export function filePathToTraceURL(path: string) {
const url = new URL('file', location.href);
url.searchParams.set('path', path);
return url;
}

View file

@ -104,8 +104,7 @@ it('should change document.activeElement', async ({ page, server }) => {
it('should not affect screenshots', async ({ page, server, browserName, headless, isWindows, channel }) => {
it.skip(browserName === 'webkit' && isWindows && !headless, 'WebKit/Windows/headed has a larger minimal viewport. See https://github.com/microsoft/playwright/issues/22616');
it.skip(browserName === 'firefox' && !headless, 'Firefox headed produces a different image');
// TODO: We want to see test results
// it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'https://github.com/microsoft/playwright/issues/33330');
it.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'https://github.com/microsoft/playwright/issues/33330');
const page2 = await page.context().newPage();
await Promise.all([

View file

@ -23,8 +23,7 @@ browserTest.describe('page screenshot', () => {
browserTest.skip(({ browserName, headless }) => browserName === 'firefox' && !headless, 'Firefox headed produces a different image.');
browserTest('should run in parallel in multiple pages', async ({ server, contextFactory, browserName, channel }) => {
// TODO: We want to see test results
// browserTest.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'https://github.com/microsoft/playwright/issues/33330');
browserTest.fixme(browserName === 'chromium' && channel !== 'chromium-headless-shell', 'https://github.com/microsoft/playwright/issues/33330');
const context = await contextFactory();
const N = 5;
const pages = await Promise.all(Array(N).fill(0).map(async () => {