Skip to content

Commit d3f3d63

Browse files
committed
PRO-10170 feat: supporting switching of tabs in network actions
1 parent 076051b commit d3f3d63

7 files changed

Lines changed: 92 additions & 11 deletions

File tree

autotests/entities/worker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export const addUser: ClientFunction<[UserWorker, number?], Promise<object>> = c
2626
/**
2727
* Get list of user-workers.
2828
*/
29-
export const getUsers = (delay: number): Promise<unknown> => {
29+
export const getUsers = (delay: number = 0): Promise<unknown> => {
3030
log(`Send API request with delay = ${delay}s`);
3131

3232
return clientGetUsers(delay);

autotests/packs/allTests.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export const pack: Pack = {
8080
skipTests,
8181
takeFullPageScreenshotOnError: false,
8282
takeViewportScreenshotOnError: true,
83-
testFileGlobs: ['**/autotests/tests/**/*.ts'],
83+
testFileGlobs: ['**/autotests/tests/**/switchingPages.ts'],
8484
testIdleTimeout: 8_000,
8585
testTimeout: 15_000,
8686
userAgent,
Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
import {ApiRoute} from 'autotests/routes';
2+
import {assertValueIsTrue} from 'e2ed/utils';
23

34
import type {ApiGetUsersRequest, ApiGetUsersResponse} from 'autotests/types';
45
import type {Url} from 'e2ed/types';
56

7+
type Params = Readonly<{delay?: number}> | undefined;
8+
9+
const pathStart = '/api/users';
10+
611
/**
712
* Client API route for getting users list.
813
*/
9-
export class GetUsers extends ApiRoute<undefined, ApiGetUsersRequest, ApiGetUsersResponse> {
14+
export class GetUsers extends ApiRoute<Params, ApiGetUsersRequest, ApiGetUsersResponse> {
15+
static override getParamsFromUrlOrThrow(url: Url): Params {
16+
const urlObject = new URL(url);
17+
18+
assertValueIsTrue(
19+
urlObject.pathname.startsWith(pathStart),
20+
'url pathname starts with correct path',
21+
{urlObject},
22+
);
23+
24+
const delay = Number(urlObject.searchParams.get('delay'));
25+
26+
if (delay >= 0) {
27+
assertValueIsTrue(Number.isInteger(delay), 'url has correct delay', {delay, urlObject});
28+
29+
return {delay};
30+
}
31+
32+
return {};
33+
}
34+
1035
getMethod(): 'GET' {
1136
return 'GET';
1237
}
@@ -16,6 +41,8 @@ export class GetUsers extends ApiRoute<undefined, ApiGetUsersRequest, ApiGetUser
1641
}
1742

1843
getPath(): string {
19-
return '/api/users?delay=3';
44+
const {delay} = this.routeParams ?? {};
45+
46+
return delay !== undefined ? `${pathStart}?delay=${delay}` : pathStart;
2047
}
2148
}

autotests/tests/request.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ test(
99
async () => {
1010
const {
1111
responseBody: {data},
12-
} = await request(GetUsers);
12+
} = await request(GetUsers, {routeParams: {delay: 3}});
1313

1414
await expect(data.length, 'request returns some users').gt(0);
1515

1616
await assertFunctionThrows(async () => {
17-
await request(GetUsers, {maxRetriesCount: 1, timeout: 2_000});
17+
await request(GetUsers, {maxRetriesCount: 1, routeParams: {delay: 3}, timeout: 2_000});
1818
}, 'request function throws an error on timeout');
1919
},
2020
);

autotests/tests/switchingPages.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {test} from 'autotests';
2+
import {getUsers} from 'autotests/entities';
3+
import {E2edReportExample} from 'autotests/pageObjects/pages';
4+
import {GetUsers} from 'autotests/routes/apiRoutes';
5+
import {expect} from 'e2ed';
6+
import {navigateToPage, waitForRequestToRoute, waitForTimeout} from 'e2ed/actions';
7+
import {log} from 'e2ed/utils';
8+
9+
const maxNumberOfRequests = 10;
10+
11+
const timeout = (maxNumberOfRequests + 2) * 1_000;
12+
13+
test('support switching of pages and tabs', {meta: {testId: '21'}}, async () => {
14+
let numberOfCaughtRequests = 0;
15+
let numberOfSentRequests = 0;
16+
17+
setInterval(() => {
18+
if (numberOfSentRequests < maxNumberOfRequests) {
19+
numberOfSentRequests += 1;
20+
21+
void getUsers();
22+
}
23+
}, 1_000);
24+
25+
void waitForRequestToRoute(GetUsers, {
26+
predicate: (routeParams, request) => {
27+
numberOfCaughtRequests += 1;
28+
29+
log(`Caught request number ${numberOfCaughtRequests}`, {routeParams, request});
30+
31+
return false;
32+
},
33+
timeout,
34+
});
35+
36+
await waitForTimeout(maxNumberOfRequests * 500);
37+
38+
await navigateToPage(E2edReportExample);
39+
40+
await waitForTimeout(maxNumberOfRequests * 500 + 1_000);
41+
42+
await expect(numberOfSentRequests, 'all requests were caught').eql(numberOfCaughtRequests);
43+
});

src/actions/waitFor/waitForRequest.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {AsyncLocalStorage} from 'node:async_hooks';
2+
13
import {LogEventType, MAX_TIMEOUT_IN_MS} from '../../constants/internal';
24
import {getTestRunPromise} from '../../context/testRunPromise';
35
import {getPlaywrightPage} from '../../useContext';
@@ -9,6 +11,8 @@ import {log} from '../../utils/log';
911
import {addTimeoutToPromise} from '../../utils/promise';
1012
import {getRequestFromPlaywrightRequest} from '../../utils/requestHooks';
1113

14+
import type {Request as PlaywrightRequest} from '@playwright/test';
15+
1216
import type {
1317
Request,
1418
RequestPredicate,
@@ -65,7 +69,7 @@ export const waitForRequest = (async <SomeRequest extends Request>(
6569

6670
const promise = addTimeoutToPromise(
6771
page.waitForRequest(
68-
async (playwrightRequest) => {
72+
AsyncLocalStorage.bind(async (playwrightRequest: PlaywrightRequest) => {
6973
try {
7074
const request = getRequestFromPlaywrightRequest(playwrightRequest);
7175

@@ -79,15 +83,17 @@ export const waitForRequest = (async <SomeRequest extends Request>(
7983
trigger,
8084
});
8185
}
82-
},
86+
}),
8387
{timeout: MAX_TIMEOUT_IN_MS},
8488
),
8589
timeout,
8690
new E2edError(`waitForRequest promise rejected after ${timeoutWithUnits} timeout`),
8791
)
8892
.then(
89-
(playwrightRequest) =>
90-
getRequestFromPlaywrightRequest(playwrightRequest) as RequestWithUtcTimeInMs<SomeRequest>,
93+
AsyncLocalStorage.bind(
94+
(playwrightRequest: PlaywrightRequest) =>
95+
getRequestFromPlaywrightRequest(playwrightRequest) as RequestWithUtcTimeInMs<SomeRequest>,
96+
),
9197
)
9298
.catch((error: unknown) => {
9399
if (isTestRunCompleted) {

src/utils/config/updateConfig.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const skippedFields: readonly (keyof FullPackConfig)[] = [
1414
* @internal
1515
*/
1616
export const updateConfig = (fullPackConfig: FullPackConfig, startInfo: StartInfo): void => {
17-
for (const field of getKeys(fullPackConfig)) {
17+
for (const field of new Set([...getKeys(fullPackConfig), ...getKeys(startInfo.fullPackConfig)])) {
1818
if (skippedFields.includes(field)) {
1919
continue;
2020
}
@@ -26,4 +26,9 @@ export const updateConfig = (fullPackConfig: FullPackConfig, startInfo: StartInf
2626
// @ts-expect-error: full pack config have different types of field values
2727
fullPackConfig[field] = startInfo.fullPackConfig[field]; // eslint-disable-line no-param-reassign
2828
}
29+
30+
Object.assign(fullPackConfig, {
31+
...fullPackConfig.overriddenConfigFields,
32+
use: {...fullPackConfig.use, ...fullPackConfig.overriddenConfigFields?.use},
33+
});
2934
};

0 commit comments

Comments
 (0)