import fs from 'node:fs'; import path from 'node:path';
import {TestServer} from '@pptr/testserver'; import expect from 'expect'; import type * as MochaBase from 'mocha'; import puppeteer, {TimeoutError} from 'puppeteer/internal/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 {ConnectionClosedError} from 'puppeteer-core/internal/common/Errors.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';
// 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`,
);
defaultBrowserOptions.args!.push(`--force-device-scale-factor=1`);
let executableExists = false; function verifyExecutable() { if (executableExists) { return;
}
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`,
);
}
}
executableExists = true;
}
/** *AdjustsMocha.Contexttimeoutandreturnslaunchparamswithtimeoutsset.
*/ function adjustBrowserLaunchTimeout(context: Mocha.Context): {
timeout: number;
protocolTimeout: number;
} {
let defaultTimeout = context.timeout() || 10_000; if (isFirefox) {
defaultTimeout += 5_000;
} // Let mocha fail after the 1s of timeout.
context.timeout(defaultTimeout + 1_000); return {
timeout: defaultTimeout, // Commands should fail before Mocha timeouts
protocolTimeout: defaultTimeout - 1_000,
};
}
let browserPromise: Promise<Browser> | null = null;
export const setupTestBrowserHooks = (): void => {
before(async function () { const {timeout, protocolTimeout} = adjustBrowserLaunchTimeout(this); const defaultTimeout = this.timeout() || 10_000; // Let mocha fail after the 1s of timeout. this.timeout(defaultTimeout + 1_000);
verifyExecutable(); try { if (!state.browser) { if (!browserPromise) {
browserPromise = (puppeteer as unknown as PuppeteerNode).launch({
...processVariables.defaultBrowserOptions,
timeout,
protocolTimeout,
});
}
state.browser = await browserPromise;
}
} catch (error) { if (error instanceof TimeoutError) { // If we get a Puppeteer Timeout Error the browser in not usable
browserPromise = null;
} else {
console.error(error);
}
}
});
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 instanceof ConnectionClosedError) {
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.