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
13 changes: 11 additions & 2 deletions autotests/actions/setPageCookiesAndNavigateToUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import {getHeaderValue, log, replaceSetCookie} from 'e2ed/utils';

import type {Cookie, NavigationReturn, SetCookieHeaderString, StringHeaders, Url} from 'e2ed/types';

type Options = Readonly<{
pageCookies: readonly Cookie[];
timeout?: number;
}>;

/**
* Navigates to the url and set custom page cookies.
*/
export const setPageCookiesAndNavigateToUrl = (
url: Url,
pageCookies: readonly Cookie[],
{pageCookies, timeout}: Options,
): Promise<NavigationReturn> => {
const mapResponseHeaders = (headers: StringHeaders): StringHeaders => {
const setCookies = getHeaderValue(headers, 'set-cookie');
Expand All @@ -28,5 +33,9 @@ export const setPageCookiesAndNavigateToUrl = (

log(`Navigate to ${url} and set page cookie`, {pageCookies, url}, LogEventType.Action);

return setHeadersAndNavigateToUrl(url, {mapResponseHeaders});
return setHeadersAndNavigateToUrl(
url,
{mapResponseHeaders},
timeout !== undefined ? {timeout} : undefined,
);
};
13 changes: 11 additions & 2 deletions autotests/actions/setPageRequestHeadersAndNavigateToUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import {log} from 'e2ed/utils';

import type {NavigationReturn, StringHeaders, Url} from 'e2ed/types';

type Options = Readonly<{
pageRequestHeaders: StringHeaders;
timeout?: number;
}>;

/**
* Navigates to the url and set additional page request headers.
*/
export const setPageRequestHeadersAndNavigateToUrl = (
url: Url,
pageRequestHeaders: StringHeaders,
{pageRequestHeaders, timeout}: Options,
): Promise<NavigationReturn> => {
const mapRequestHeaders = (): StringHeaders => pageRequestHeaders;

Expand All @@ -19,5 +24,9 @@ export const setPageRequestHeadersAndNavigateToUrl = (
LogEventType.Action,
);

return setHeadersAndNavigateToUrl(url, {mapRequestHeaders});
return setHeadersAndNavigateToUrl(
url,
{mapRequestHeaders},
timeout !== undefined ? {timeout} : undefined,
);
};
2 changes: 0 additions & 2 deletions autotests/configurator/regroupSteps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import type {LogEvent, Mutable} from 'e2ed/types';

/**
* Regroup log events (for grouping of `TestRun` steps).
* This base client function should not use scope variables (except other base functions).
* @internal
*/
export const regroupSteps = (logEvents: readonly LogEvent[]): readonly LogEvent[] => {
const topLevelTypes: readonly LogEventType[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,16 @@ export class E2edReportExample extends Page<CustomPageParams> {

override navigateToPage(url: Url): Promise<NavigationReturn> {
if (this.pageRequestHeaders) {
return setPageRequestHeadersAndNavigateToUrl(url, this.pageRequestHeaders);
return setPageRequestHeadersAndNavigateToUrl(url, {
pageRequestHeaders: this.pageRequestHeaders,
timeout: E2edReportExample.navigationTimeout,
});
}

return setPageCookiesAndNavigateToUrl(url, this.pageCookies);
return setPageCookiesAndNavigateToUrl(url, {
pageCookies: this.pageCookies,
timeout: E2edReportExample.navigationTimeout,
});
}

override async waitForPageLoaded(): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion autotests/tests/main/exists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {assertFunctionThrows, getDocumentUrl} from 'e2ed/utils';
import type {Url} from 'e2ed/types';

// eslint-disable-next-line max-statements
test('exists', {meta: {testId: '1'}, testIdleTimeout: 10_000, testTimeout: 20_000}, async () => {
test('exists', {meta: {testId: '1'}, testIdleTimeout: 12_000, testTimeout: 20_000}, async () => {
const language = 'en';
const searchQuery = 'foo';
const testScrollValue = 200;
Expand Down
1 change: 1 addition & 0 deletions src/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export abstract class Page<PageParams = undefined> {

await waitForAllRequestsComplete(() => true, {
maxIntervalBetweenRequestsInMs: this.maxIntervalBetweenRequestsInMs,
timeout: (this.constructor as typeof Page).navigationTimeout,
});
}

Expand Down
81 changes: 41 additions & 40 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,44 @@ Modules in the dependency graph should only import the modules above them:
8. `utils/getHash`
9. `generators`
10. `utils/headers`
11. `utils/viewport`
12. `utils/parse`
13. `utils/distanceBetweenSelectors`
14. `utils/getDurationWithUnits`
15. `utils/valueToString`
16. `utils/error`
17. `utils/asserts`
18. `utils/object`
19. `utils/uiMode`
20. `utils/runLabel`
21. `utils/clone`
22. `utils/notIncludedInPackTests`
23. `utils/userland`
24. `utils/fn`
25. `utils/environment`
26. `utils/packCompiler`
27. `config`
28. `utils/config`
29. `utils/generalLog`
30. `utils/testFilePaths`
31. `utils/exit`
32. `utils/promise`
33. `utils/resourceUsage`
34. `utils/fs`
35. `utils/getGlobalErrorHandler`
36. `utils/tests`
37. `utils/end`
38. `utils/pack`
39. `useContext`
40. `context`
41. `utils/step`
42. `utils/apiStatistics`
43. `utils/selectors`
44. `selectors`
45. `utils/log`
46. `step`
47. `utils/waitForEvents`
48. `utils/expect`
49. `expect`
50. ...
11. `utils/screenshot`
12. `utils/viewport`
13. `utils/parse`
14. `utils/distanceBetweenSelectors`
15. `utils/getDurationWithUnits`
16. `utils/valueToString`
17. `utils/error`
18. `utils/asserts`
19. `utils/object`
20. `utils/uiMode`
21. `utils/runLabel`
22. `utils/clone`
23. `utils/notIncludedInPackTests`
24. `utils/userland`
25. `utils/fn`
26. `utils/environment`
27. `utils/packCompiler`
28. `config`
29. `utils/config`
30. `utils/generalLog`
31. `utils/testFilePaths`
32. `utils/exit`
33. `utils/promise`
34. `utils/resourceUsage`
35. `utils/fs`
36. `utils/getGlobalErrorHandler`
37. `utils/tests`
38. `utils/end`
39. `utils/pack`
40. `useContext`
41. `context`
42. `utils/step`
43. `utils/apiStatistics`
44. `utils/selectors`
45. `selectors`
46. `utils/log`
47. `step`
48. `utils/waitForEvents`
49. `utils/expect`
50. `expect`
51. ...
7 changes: 5 additions & 2 deletions src/actions/pages/reloadPage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {LogEventType} from '../../constants/internal';
import {ADDITIONAL_STEP_TIMEOUT, LogEventType} from '../../constants/internal';
import {step} from '../../step';

import type {AnyPageClassType} from '../../types/internal';
Expand All @@ -18,5 +18,8 @@ export const reloadPage = (page: InstanceType<AnyPageClassType>): Promise<void>

await page.afterReloadPage?.();
},
{type: LogEventType.InternalAction},
{
timeout: (page.constructor as AnyPageClassType).navigationTimeout + ADDITIONAL_STEP_TIMEOUT,
type: LogEventType.InternalAction,
},
);
14 changes: 12 additions & 2 deletions src/actions/takeElementScreenshot.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import {join} from 'node:path';

import {LogEventType, SCREENSHOTS_DIRECTORY_PATH} from '../constants/internal';
import {
ADDITIONAL_STEP_TIMEOUT,
LogEventType,
SCREENSHOTS_DIRECTORY_PATH,
} from '../constants/internal';
import {step} from '../step';
import {getDimensionsString, getPngDimensions} from '../utils/screenshot';

import type {Locator} from '@playwright/test';

Expand All @@ -17,6 +22,7 @@ export const takeElementScreenshot = async (
options: Options = {},
): Promise<void> => {
const {path: pathToScreenshot, ...optionsWithoutPath} = options;
const {timeout} = options;

await step(
'Take a screenshot of the element',
Expand All @@ -26,10 +32,14 @@ export const takeElementScreenshot = async (
options.path = join(SCREENSHOTS_DIRECTORY_PATH, pathToScreenshot);
}

await selector.getPlaywrightLocator().screenshot(options);
const screenshot = await selector.getPlaywrightLocator().screenshot(options);
const dimensions = getDimensionsString(getPngDimensions(screenshot));

return {dimensions};
},
{
payload: {pathToScreenshot, ...optionsWithoutPath, selector},
...(timeout !== undefined ? {timeout: timeout + ADDITIONAL_STEP_TIMEOUT} : undefined),
type: LogEventType.InternalAction,
},
);
Expand Down
19 changes: 16 additions & 3 deletions src/actions/takeScreenshot.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import {join} from 'node:path';

import {LogEventType, SCREENSHOTS_DIRECTORY_PATH} from '../constants/internal';
import {
ADDITIONAL_STEP_TIMEOUT,
LogEventType,
SCREENSHOTS_DIRECTORY_PATH,
} from '../constants/internal';
import {step} from '../step';
import {getPlaywrightPage} from '../useContext';
import {getDimensionsString, getPngDimensions} from '../utils/screenshot';

import type {Page} from '@playwright/test';

Expand All @@ -13,6 +18,7 @@ type Options = Parameters<Page['screenshot']>[0];
*/
export const takeScreenshot = async (options: Options = {}): Promise<void> => {
const {path: pathToScreenshot, ...optionsWithoutPath} = options;
const {timeout} = options;

await step(
'Take a screenshot of the page',
Expand All @@ -24,8 +30,15 @@ export const takeScreenshot = async (options: Options = {}): Promise<void> => {

const page = getPlaywrightPage();

await page.screenshot(options);
const screenshot = await page.screenshot(options);
const dimensions = getDimensionsString(getPngDimensions(screenshot));

return {dimensions};
},
{
payload: {pathToScreenshot, ...optionsWithoutPath},
...(timeout !== undefined ? {timeout: timeout + ADDITIONAL_STEP_TIMEOUT} : undefined),
type: LogEventType.InternalAction,
},
{payload: {pathToScreenshot, ...optionsWithoutPath}, type: LogEventType.InternalAction},
);
};
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export type {
export type {KeyboardPressKey} from './keyboard';
export type {Log, LogContext, LogParams, LogPayload, LogTag} from './log';
export type {
Dimensions,
DimensionsString,
MatchScreenshotConfig,
ScreenshotMeta,
ToMatchScreenshotOptions,
Expand Down
4 changes: 4 additions & 0 deletions src/types/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,14 @@ export type {
Payload,
} from './log';
export type {
Dimensions,
DimensionsString,
MatchScreenshotConfig,
ScreenshotMeta,
ToMatchScreenshotOptions,
} from './matchScreenshot';
/** @internal */
export type {ScreenshotLogFields} from './matchScreenshot';
export type {ApiMockFunction} from './mockApiRoute';
/** @internal */
export type {ApiMockState} from './mockApiRoute';
Expand Down
24 changes: 24 additions & 0 deletions src/types/matchScreenshot.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import type {Brand} from './brand';
import type {Url} from './http';
import type {RunLabel} from './runLabel';
import type {Selector} from './selectors';
import type {TestStaticOptions} from './testRun';
import type {TestMetaPlaceholder} from './userland';

/**
* Dimensions of screenshot image.
*/
export type Dimensions = Readonly<{
height: number;
width: number;
}>;

/**
* String with dimensions of screenshot, like `320x108`.
*/
export type DimensionsString = Brand<string, 'DimensionsString'>;

/**
* Functions that describe the `toMatchScreenshot` assert (in `expect`).
*/
Expand Down Expand Up @@ -32,6 +46,16 @@ export type MatchScreenshotConfig<TestMeta = TestMetaPlaceholder> = Readonly<{
) => Promise<string>;
}>;

/**
* Log fields for single screenshot.
* @internal
*/
export type ScreenshotLogFields = {
dimensions: DimensionsString;
readonly screenshotId: string;
url: Url;
};

/**
* General screenshot metadata (like test name, assert description, etc.).
*/
Expand Down
17 changes: 17 additions & 0 deletions src/utils/expect/getEmptyAdditionalLogFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {AdditionalLogFields} from './types';

type Options = Readonly<{
expectedScreenshotId: string;
}>;

/**
* Get empty additional log fields object for `toMatchScreenshot` assertion.
* @internal
*/
export const getEmptyAdditionalLogFields = ({
expectedScreenshotId,
}: Options): AdditionalLogFields => ({
actual: undefined,
diff: undefined,
expected: {dimensions: undefined, screenshotId: expectedScreenshotId, url: undefined},
});
Loading