Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions autotests/tests/switchingPagesForResponses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ test(

await expect(
numberOfSentRequests === numberOfCaughtResponses ||
numberOfSentRequests === numberOfCaughtResponses + 2 ||
numberOfSentRequests === numberOfCaughtResponses + 1 ||
numberOfSentRequests === numberOfCaughtResponses - 1,
`almost all responses were caught (${numberOfCaughtResponses} of ${numberOfSentRequests})`,
Expand Down
1,204 changes: 838 additions & 366 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,26 @@
"url": "git+https://github.com/joomcode/e2ed.git"
},
"dependencies": {
"@playwright/test": "1.52.0",
"@playwright/test": "1.53.2",
"create-locator": "0.0.27",
"get-modules-graph": "0.0.11",
"sort-json-keys": "1.0.3"
},
"devDependencies": {
"@playwright/browser-chromium": "1.52.0",
"@types/node": "22.15.21",
"@playwright/browser-chromium": "1.53.2",
"@types/node": "24.0.8",
"@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.18.0",
"assert-modules-support-case-insensitive-fs": "1.0.1",
"assert-package-lock-is-consistent": "1.0.0",
"eslint": "8.57.1",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "10.1.5",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"eslint-plugin-typescript-sort-keys": "3.3.0",
"husky": "9.1.7",
"prettier": "3.5.3",
"prettier": "3.6.2",
"typescript": "5.8.3"
},
"peerDependencies": {
Expand Down
6 changes: 2 additions & 4 deletions src/ApiRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ export abstract class ApiRoute<
/**
* Request type of API route.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
declare readonly __REQUEST_KEY: SomeRequest;
declare readonly Request: SomeRequest;

/**
* Response type of API route.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
declare readonly __RESPONSE_KEY: SomeResponse;
declare readonly Response: SomeResponse;

/**
* Returns `true`, if the request body is in JSON format.
Expand Down
6 changes: 2 additions & 4 deletions src/WebSocketRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ export abstract class WebSocketRoute<
/**
* Request type of WebSocket route.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
declare readonly __REQUEST_KEY: SomeRequest;
declare readonly Request: SomeRequest;

/**
* Response type of WebSocket route.
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
declare readonly __RESPONSE_KEY: SomeResponse;
declare readonly Response: SomeResponse;

/**
* Returns `true`, if the request body is in JSON format.
Expand Down
4 changes: 2 additions & 2 deletions src/actions/setHeadersAndNavigateToUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export const setHeadersAndNavigateToUrl = async (
return route.fallback();
}

const {navigationTimeout} = getFullPackConfig();
const timeout = navigateToUrlOptions?.timeout ?? getFullPackConfig().navigationTimeout;

const response = await route.fetch({timeout: navigationTimeout});
const response = await route.fetch({timeout});
const headers = response.headers();

applyHeadersMapper(headers, mapResponseHeaders);
Expand Down
3 changes: 2 additions & 1 deletion src/constants/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export {
EVENTS_DIRECTORY_PATH,
EXPECTED_SCREENSHOTS_DIRECTORY_PATH,
GLOBAL_ERRORS_PATH,
GLOBAL_WARNINGS_PATH,
INSTALLED_E2ED_DIRECTORY_PATH,
INTERNAL_DIRECTORY_NAME,
INTERNAL_REPORTS_DIRECTORY_PATH,
Expand All @@ -63,7 +64,7 @@ export {
TMP_DIRECTORY_PATH,
} from './paths';
/** @internal */
export {TEST_ENDED_ERROR_MESSAGE} from './playwright';
export {TARGET_CLOSED_ERROR_MESSAGE, TEST_ENDED_ERROR_MESSAGE} from './playwright';
/** @internal */
export {RESOLVED_PROMISE} from './promise';
/** @internal */
Expand Down
9 changes: 9 additions & 0 deletions src/constants/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ export const EXPECTED_SCREENSHOTS_DIRECTORY_PATH = join(
*/
export const GLOBAL_ERRORS_PATH = join(TMP_DIRECTORY_PATH, 'globalErrors.txt') as FilePathFromRoot;

/**
* Relative (from root) path to file with global warnings of run.
* @internal
*/
export const GLOBAL_WARNINGS_PATH = join(
TMP_DIRECTORY_PATH,
'globalWarnings.txt',
) as FilePathFromRoot;

/**
* Relative (from root) path to directory with tests screenshots.
* @internal
Expand Down
6 changes: 6 additions & 0 deletions src/constants/playwright.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* Playwright error message for already closed target (`TargetClosedError`).
* @internal
*/
export const TARGET_CLOSED_ERROR_MESSAGE = 'Target page, context or browser has been closed';

/**
* Playwright error message for already ended test.
* @internal
Expand Down
9 changes: 4 additions & 5 deletions src/createClientFunction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {TEST_ENDED_ERROR_MESSAGE} from './constants/internal';
import {TARGET_CLOSED_ERROR_MESSAGE, TEST_ENDED_ERROR_MESSAGE} from './constants/internal';
import {getTestIdleTimeout} from './context/testIdleTimeout';
import {E2edError} from './utils/error';
import {setCustomInspectOnFunction} from './utils/fn';
Expand All @@ -13,7 +13,6 @@ import type {ClientFunction} from './types/internal';
type Options = Readonly<{name?: string; retries?: number; timeout?: number}>;

const contextErrorMessage = 'Execution context was destroyed';
const targetErrorMessage = 'Target page, context or browser has been closed';

/**
* Creates a client function.
Expand Down Expand Up @@ -48,7 +47,7 @@ export const createClientFunction = <Args extends readonly unknown[], Result>(

if (
errorString.includes(contextErrorMessage) ||
errorString.includes(targetErrorMessage) ||
errorString.includes(TARGET_CLOSED_ERROR_MESSAGE) ||
errorString.includes(TEST_ENDED_ERROR_MESSAGE)
) {
await page.waitForLoadState();
Expand All @@ -58,7 +57,7 @@ export const createClientFunction = <Args extends readonly unknown[], Result>(

if (
suberrorString.includes(contextErrorMessage) ||
suberrorString.includes(targetErrorMessage) ||
suberrorString.includes(TARGET_CLOSED_ERROR_MESSAGE) ||
suberrorString.includes(TEST_ENDED_ERROR_MESSAGE)
) {
return new Promise(() => {});
Expand All @@ -80,7 +79,7 @@ export const createClientFunction = <Args extends readonly unknown[], Result>(

if (
suberrorString.includes(contextErrorMessage) ||
suberrorString.includes(targetErrorMessage) ||
suberrorString.includes(TARGET_CLOSED_ERROR_MESSAGE) ||
suberrorString.includes(TEST_ENDED_ERROR_MESSAGE)
) {
return new Promise(() => {});
Expand Down
7 changes: 4 additions & 3 deletions src/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// eslint-disable-next-line import/no-unused-modules
import type {SafeHtml} from './html';
import type {Any, ZeroOrOneArg} from './utils';

/**
* Extends global namespaces.
Expand All @@ -19,9 +20,9 @@ declare global {
* JSX functional component.
* @internal
*/
type Component<Props extends Properties = Properties> = (
type Component<Props extends object | undefined = Properties | undefined> = (
this: void,
properties?: Props,
...args: ZeroOrOneArg<Props>
) => Element;

/**
Expand All @@ -38,7 +39,7 @@ declare global {

type ElementChildrenAttribute = {children: {}};

type ElementType = Component | HtmlTag;
type ElementType = Component<Any> | HtmlTag;

/**
* Creates fragment (`<>...</>`).
Expand Down
2 changes: 2 additions & 0 deletions src/types/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export type LiteReport<
FullPackConfig<CustomPackProperties, CustomReportProperties, SkipTests, TestMeta>
>;
summaryPackResults: string;
warnings: readonly string[];
}>;

/**
Expand Down Expand Up @@ -76,6 +77,7 @@ export type ReportData = Readonly<{
retries: readonly Retry[];
startInfo: StartInfo;
summaryPackResults: string;
warnings: readonly string[];
}>;

/**
Expand Down
6 changes: 1 addition & 5 deletions src/utils/expect/createExpectMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,7 @@ export const createExpectMethod = (
}

return runAssertion(this.actualValue);
}).catch((error: Error) => ({
actualValue: this.actualValue,
description: this.description,
error,
}));
});

return assertionPromise.then(({actualValue, additionalLogFields, error}) => {
const logMessage = `Assert: ${this.description}`;
Expand Down
4 changes: 4 additions & 0 deletions src/utils/fs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export {readEventsFromFiles} from './readEventsFromFiles';
/** @internal */
export {readGlobalErrors} from './readGlobalErrors';
/** @internal */
export {readGlobalWarnings} from './readGlobalWarnings';
/** @internal */
export {readStartInfo} from './readStartInfo';
/** @internal */
export {removeDirectory} from './removeDirectory';
Expand All @@ -24,6 +26,8 @@ export {writeFile} from './writeFile';
/** @internal */
export {writeGlobalError} from './writeGlobalError';
/** @internal */
export {writeGlobalWarning} from './writeGlobalWarning';
/** @internal */
export {writeStartInfo} from './writeStartInfo';
/** @internal */
export {writeTestRunToJsonFile} from './writeTestRunToJsonFile';
15 changes: 15 additions & 0 deletions src/utils/fs/readGlobalWarnings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {readFile} from 'node:fs/promises';

import {GLOBAL_WARNINGS_PATH, READ_FILE_OPTIONS} from '../../constants/internal';

/**
* Reads global warnings of run from directory.
* @internal
*/
export const readGlobalWarnings = async (): Promise<readonly string[]> => {
const globalWarningsJsonString = await readFile(GLOBAL_WARNINGS_PATH, READ_FILE_OPTIONS).catch(
() => '',
);

return JSON.parse(`[${globalWarningsJsonString.slice(0, -2)}]`) as string[];
};
13 changes: 13 additions & 0 deletions src/utils/fs/writeGlobalWarning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {appendFile} from 'node:fs/promises';

import {GLOBAL_WARNINGS_PATH} from '../../constants/internal';

/**
* Writes single global warning of run to common file.
* @internal
*/
export const writeGlobalWarning = async (globalWarning: string): Promise<void> => {
const globalWarningJsonString = JSON.stringify(globalWarning);

await appendFile(GLOBAL_WARNINGS_PATH, `${globalWarningJsonString},\n`);
};
25 changes: 21 additions & 4 deletions src/utils/getGlobalErrorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {TARGET_CLOSED_ERROR_MESSAGE, TEST_ENDED_ERROR_MESSAGE} from '../constants/internal';

import {E2edError} from './error';
import {writeGlobalError} from './fs';
import {writeGlobalError, writeGlobalWarning} from './fs';
import {writeLogsToFile} from './generalLog';

import type {GlobalErrorType} from '../types/internal';
Expand All @@ -11,8 +13,23 @@ import type {GlobalErrorType} from '../types/internal';
export const getGlobalErrorHandler =
(type: GlobalErrorType) =>
(cause: unknown): void => {
const error = new E2edError(`Caught ${type}`, {cause});
try {
const error = new E2edError(`Caught ${type}`, {cause});
const errorString = error.toString();

if (
errorString.includes(TARGET_CLOSED_ERROR_MESSAGE) ||
errorString.includes(TEST_ENDED_ERROR_MESSAGE)
) {
return;
}

if (type === 'TestUnhandledRejection') {
void writeGlobalWarning(errorString).catch(() => {});
} else {
void writeGlobalError(errorString).catch(() => {});
}

void writeGlobalError(error.toString()).catch(() => {});
void writeLogsToFile().catch(() => {});
void writeLogsToFile().catch(() => {});
} catch {}
};
7 changes: 6 additions & 1 deletion src/utils/report/client/chooseTestRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ export function chooseTestRun(runHash: RunHash): void {

const {testRunDetailsElementsByHash} = reportClientState;

const previousTestRunDetailsElement = e2edRightColumnContainer.firstElementChild as HTMLElement;
const previousTestRunDetailsElement =
e2edRightColumnContainer.firstElementChild as HTMLElement | null;

if (!previousTestRunDetailsElement) {
return;
}

if (
!(previousHash in testRunDetailsElementsByHash) &&
Expand Down
2 changes: 1 addition & 1 deletion src/utils/report/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export {readJsonReportData} from './readJsonReportData';
export {readPartOfJsonReportData} from './readPartOfJsonReportData';
/** @internal */
export {
ApiStatisticsItem,
renderApiStatistics,
renderApiStatisticsItem,
renderAttributes,
renderDatesInterval,
renderDuration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const renderDuration = clientRenderDuration;

declare const jsx: JSX.Runtime;

type Options = Readonly<{
type Props = Readonly<{
count: number;
duration: number;
isHeader?: boolean;
Expand All @@ -20,14 +20,14 @@ type Options = Readonly<{
* This base client function should not use scope variables (except other base functions).
* @internal
*/
export function renderApiStatisticsItem({
export const ApiStatisticsItem: JSX.Component<Props> = ({
count,
duration,
isHeader,
name,
size,
url,
}: Options): SafeHtml {
}) => {
const bytesInKiB = 1_024;
const durationHtml = renderDuration(duration / count);
const countHtml = `${count}x`;
Expand Down Expand Up @@ -56,4 +56,4 @@ export function renderApiStatisticsItem({
</span>
</span>
);
}
};
4 changes: 2 additions & 2 deletions src/utils/report/client/render/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @internal */
export {renderApiStatistics} from './renderApiStatistics';
export {ApiStatisticsItem} from './ApiStatisticsItem';
/** @internal */
export {renderApiStatisticsItem} from './renderApiStatisticsItem';
export {renderApiStatistics} from './renderApiStatistics';
/** @internal */
export {renderAttributes} from './renderAttributes';
/** @internal */
Expand Down
Loading