/** * @license * Copyright 2020 Google Inc. * SPDX-License-Identifier: Apache-2.0
*/
import fs from 'fs'; import path from 'path';
import {TestServer} from '@pptr/testserver'; import expect from 'expect'; import type * as MochaBase from 'mocha'; import puppeteer from 'puppeteer/lib/cjs/puppeteer/puppeteer.js'; import type {Browser} from 'puppeteer-core/internal/api/Browser.js'; import type {BrowserContext} from 'puppeteer-core/internal/api/BrowserContext.js'; import type {Page} from 'puppeteer-core/internal/api/Page.js'; import type {Cookie} from 'puppeteer-core/internal/common/Cookie.js'; import type {LaunchOptions} from 'puppeteer-core/internal/node/LaunchOptions.js'; import type {PuppeteerNode} from 'puppeteer-core/internal/node/PuppeteerNode.js'; import {rmSync} from 'puppeteer-core/internal/node/util/fs.js'; import {Deferred} from 'puppeteer-core/internal/util/Deferred.js'; import {isErrorLike} from 'puppeteer-core/internal/util/ErrorLike.js'; import sinon from 'sinon';
import {extendExpectWithToBeGolden} from './utils.js';
declare global { // eslint-disable-next-line @typescript-eslint/no-namespace
namespace Mocha {
export interface SuiteFunction { /** * Use it if you want to capture debug logs for a specitic test suite in CI. * This describe function enables capturing of debug logs and would print them * only if a test fails to reduce the amount of output.
*/
withDebugLogs: (
description: string,
body: (this: MochaBase.Suite) => void,
) => void;
}
export interface TestFunction { /* * Use to rerun the test and capture logs for the failed attempts * that way we don't push all the logs making it easier to read.
*/
deflake: (
repeats: number,
title: string,
fn: MochaBase.AsyncFunc,
) => void; /* * Use to rerun a single test and capture logs for the failed attempts
*/
deflakeOnly: (
repeats: number,
title: string,
fn: MochaBase.AsyncFunc,
) => void;
}
}
}
// Required by tests and cannot be overridden by EXTRA_LAUNCH_OPTIONS.
defaultBrowserOptions.extraPrefsFirefox!['network.dns.localDomains'] =
`domain1.test,domain2.test,domain3.test`;
defaultBrowserOptions.args!.push(
`--host-resolver-rules=MAP domain1.test 127.0.0.1,MAP domain2.test 127.0.0.1,MAP domain3.test 127.0.0.1`,
);
if (defaultBrowserOptions.executablePath) {
console.warn(
`WARN: running ${product} tests with ${defaultBrowserOptions.executablePath}`,
); if (!fs.existsSync(defaultBrowserOptions.executablePath)) { thrownew Error(
`Browser executable not found at ${defaultBrowserOptions.executablePath}`,
);
}
} else { const executablePath = puppeteer.executablePath(); if (!fs.existsSync(executablePath)) { thrownew Error(
`Browser is not downloaded at ${executablePath}. Run 'npm install' and try to re-run tests`,
);
}
}
state.browser = await browserPromise;
}
} catch (error) {
console.error(error); // Intentionally empty as `getTestState` will throw // if browser is not found
}
});
if (skipLaunch) { return state as PuppeteerTestState;
}
if (!state.browser) { thrownew Error('Browser was not set-up in time!');
} elseif (!state.browser.connected) { thrownew Error('Browser has disconnected!');
} if (state.context) { thrownew Error('Previous state was not cleared');
}
if (!skipContextCreation) {
state.context = await state.browser.createBrowserContext();
state.page = await state.context.newPage();
} return state as PuppeteerTestState;
};
return {
pass: false,
message: () => { return `"${actual}" didn't contain any of the strings ${JSON.stringify(
expected,
)}`;
},
};
},
});
export const expectCookieEquals = async (
cookies: Cookie[],
expectedCookies: Array<Partial<Cookie>>,
): Promise<void> => { if (!processVariables.isChrome) { // Only keep standard properties when testing on a browser other than Chrome.
expectedCookies = expectedCookies.map(cookie => { return Object.fromEntries(
Object.entries(cookie).filter(([key]) => { return [ 'domain', 'expires', 'httpOnly', 'name', 'path', 'secure', 'session', 'size', 'value',
].includes(key);
}),
);
});
}
expect(cookies).toHaveLength(expectedCookies.length); for (let i = 0; i < cookies.length; i++) {
expect(cookies[i]).toMatchObject(expectedCookies[i]!);
}
};
export const shortWaitForArrayToHaveAtLeastNElements = async (
data: unknown[],
minLength: number,
attempts = 3,
timeout = 50,
): Promise<void> => { for (let i = 0; i < attempts; i++) { if (data.length >= minLength) { break;
}
await new Promise(resolve => { return setTimeout(resolve, timeout);
});
}
};
const closeLaunched = (storage: Array<() => Promise<void>>) => { return async () => {
let cleanup = storage.pop(); try { while (cleanup) {
await cleanup();
cleanup = storage.pop();
}
} catch (error) { // If the browser was closed by other means, swallow the error // and mark the browser as closed. if ((error as Error)?.message.includes('Connection closed')) {
storage.splice(0, storage.length); return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.