Skip to content

Commit 615dd6c

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

7 files changed

Lines changed: 101 additions & 20 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);
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
);
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/config.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ import {
2020
import {assertValueIsTrue} from './utils/asserts';
2121
// eslint-disable-next-line import/no-internal-modules
2222
import {assertUserlandPack} from './utils/config/assertUserlandPack';
23+
// eslint-disable-next-line import/no-internal-modules
24+
import {updateConfig} from './utils/config/updateConfig';
2325
import {getPathToPack} from './utils/environment';
2426
import {setCustomInspectOnFunction} from './utils/fn';
27+
// eslint-disable-next-line import/no-internal-modules
28+
import {readStartInfoSync} from './utils/fs/readStartInfoSync';
2529
import {setReadonlyProperty} from './utils/object';
2630
import {isUiMode} from './utils/uiMode';
2731
import {isLocalRun} from './configurator';
@@ -116,31 +120,27 @@ const playwrightConfig = defineConfig({
116120
pathTemplate: `${ABSOLUTE_PATH_TO_PROJECT_ROOT_DIRECTORY}/${EXPECTED_SCREENSHOTS_DIRECTORY_PATH}/{arg}.png`,
117121
},
118122
},
119-
120123
fullyParallel: true,
121-
122124
globalTimeout: userlandPack.packTimeout,
123-
124125
outputDir: join(relativePathFromInstalledE2edToRoot, INTERNAL_REPORTS_DIRECTORY_PATH),
125-
126126
projects: [{name: userlandPack.browserName, use: useOptions}],
127-
128127
retries: isLocalRun ? 0 : userlandPack.maxRetriesCountInDocker - 1,
129-
130128
testDir: join(relativePathFromInstalledE2edToRoot, TESTS_DIRECTORY_PATH),
131129
testIgnore: ['**/node_modules/**', '**/*.skip.ts'],
132130
testMatch: userlandPack.testFileGlobs as Mutable<typeof userlandPack.testFileGlobs>,
133-
134131
timeout: userlandPack.testTimeout,
135-
136132
workers: userlandPack.concurrency,
137-
138133
...userlandPack.overriddenConfigFields,
139-
140134
use: useOptions,
141135
});
142136

143137
const config: FullPackConfig = Object.assign(playwrightConfig, userlandPack);
144138

139+
try {
140+
const startInfo = readStartInfoSync();
141+
142+
updateConfig(config, startInfo);
143+
} catch {}
144+
145145
// eslint-disable-next-line import/no-default-export
146146
export default config;

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)