Skip to content

Commit

Permalink
FI-705 fix: stricter type of expect function
Browse files Browse the repository at this point in the history
feat: add field `maxIntervalBetweenRequestsInMs` ot abstract class `Page`
feat: add examples of `mapBackendResponseErrorToLog`/`mapBackendResponseToLog`
tests: more tests of types of selectors methods
  • Loading branch information
uid11 committed Nov 30, 2023
1 parent dc29643 commit 6ce1941
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 48 deletions.
2 changes: 2 additions & 0 deletions autotests/configurator/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export {doAfterPack} from './doAfterPack';
export {doBeforePack} from './doBeforePack';
export {mapBackendResponseErrorToLog} from './mapBackendResponseErrorToLog';
export {mapBackendResponseToLog} from './mapBackendResponseToLog';
export {mapLogPayloadInConsole} from './mapLogPayloadInConsole';
export {mapLogPayloadInLogFile} from './mapLogPayloadInLogFile';
export {mapLogPayloadInReport} from './mapLogPayloadInReport';
Expand Down
32 changes: 32 additions & 0 deletions autotests/configurator/mapBackendResponseErrorToLog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type {MapBackendResponseErrorToLog} from 'autotests/types/packSpecific';

/**
* Maps responses with errors from the backend to "red" logs (as errors) during the test.
* It is assumed that the function will select responses with
* statuse codes of 400 and higher (client and server errors).
* Backend responses with errors are accumulated in separate "red" log step
* (with `logEventStatus: 'failed'`).
* Log the `responseBody` field carefully, as the body of backend response can be very large.
* If the function returns `undefined`, the response is not logged (skipped).
*/
export const mapBackendResponseErrorToLog: MapBackendResponseErrorToLog = ({
request,
responseBody,
responseHeaders,
statusCode,
}) => {
if (statusCode < 400) {
return undefined;
}

const {requestBody, ...requestWithoutBody} = request ?? {};

return {
request: {
requestBody: requestBody instanceof Buffer ? String(requestBody) : requestBody,
...requestWithoutBody,
},
responseBody: responseBody instanceof Buffer ? String(responseBody) : responseBody,
responseHeaders,
};
};
29 changes: 29 additions & 0 deletions autotests/configurator/mapBackendResponseToLog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type {MapBackendResponseToLog} from 'autotests/types/packSpecific';

/**
* Maps responses from the backend to logs during the test.
* Backend responses received during a certain test step are accumulated
* in an array in the `backendResponses` field of the log of this step.
* Log the `responseBody` field carefully, as the body of backend response can be very large.
* If the function returns `undefined`, the response is not logged (skipped).
*/
export const mapBackendResponseToLog: MapBackendResponseToLog = ({
request,
responseBody,
responseHeaders,
statusCode,
}) => {
if (statusCode >= 400) {
return undefined;
}

if (request) {
return {statusCode, url: request?.url};
}

return {
responseBody: responseBody instanceof Buffer ? String(responseBody) : responseBody,
responseHeaders,
statusCode,
};
};
8 changes: 4 additions & 4 deletions autotests/packs/allTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {RunEnvironment, runEnvironment} from 'e2ed/configurator';
import {
doAfterPack,
doBeforePack,
mapBackendResponseErrorToLog,
mapBackendResponseToLog,
mapLogPayloadInConsole,
mapLogPayloadInLogFile,
mapLogPayloadInReport,
Expand Down Expand Up @@ -42,10 +44,8 @@ export const pack: Pack = {
filterTestsIntoPack,
liteReportFileName: 'lite-report.json',
logFileName: 'pack-logs.log',
mapBackendResponseErrorToLog: ({request, responseHeaders, statusCode}) =>
statusCode >= 400 ? {request, responseHeaders, statusCode} : undefined,
mapBackendResponseToLog: ({request, statusCode}) =>
statusCode < 400 ? {statusCode, url: request?.url} : undefined,
mapBackendResponseErrorToLog,
mapBackendResponseToLog,
mapLogPayloadInConsole,
mapLogPayloadInLogFile,
mapLogPayloadInReport,
Expand Down
17 changes: 10 additions & 7 deletions autotests/pageObjects/pages/Main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,16 @@ export class Main extends Page<CustomPageParams> {
}

override async waitForPageLoaded(): Promise<void> {
await waitForAllRequestsComplete(({url}) => {
if (url.startsWith('https://adservice.google.com/')) {
return false;
}

return true;
});
await waitForAllRequestsComplete(
({url}) => {
if (url.startsWith('https://adservice.google.com/')) {
return false;
}

return true;
},
{maxIntervalBetweenRequestsInMs: this.maxIntervalBetweenRequestsInMs},
);

await waitForInterfaceStabilization(this.pageStabilizationInterval);
}
Expand Down
27 changes: 15 additions & 12 deletions autotests/pageObjects/pages/Search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ export class Search extends MobilePage<CustomPageParams> {
}

override async waitForPageLoaded(): Promise<void> {
await waitForAllRequestsComplete(({url}) => {
if (
url.startsWith('https://adservice.google.com/') ||
url.startsWith('https://googleads.g.doubleclick.net/') ||
url.startsWith('https://play.google.com/') ||
url.startsWith('https://static.doubleclick.net/')
) {
return false;
}

return true;
});
await waitForAllRequestsComplete(
({url}) => {
if (
url.startsWith('https://adservice.google.com/') ||
url.startsWith('https://googleads.g.doubleclick.net/') ||
url.startsWith('https://play.google.com/') ||
url.startsWith('https://static.doubleclick.net/')
) {
return false;
}

return true;
},
{maxIntervalBetweenRequestsInMs: this.maxIntervalBetweenRequestsInMs},
);

await waitForInterfaceStabilization(this.pageStabilizationInterval);
}
Expand Down
51 changes: 28 additions & 23 deletions autotests/tests/internalTypeTests/selectors.skip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@ import {
locatorIdSelector,
} from 'autotests/selectors';

import type {Selector} from 'e2ed/types';

// @ts-expect-error: wrong number of arguments
htmlElementSelector.findByLocatorId();
// @ts-expect-error: wrong type of arguments
htmlElementSelector.findByLocatorId(0);
// ok
htmlElementSelector.findByLocatorId('id');
htmlElementSelector.findByLocatorId('id') satisfies Selector;
// ok
htmlElementSelector.findByLocatorId('id').findByLocatorId('id2');
htmlElementSelector.findByLocatorId('id').findByLocatorId('id2') satisfies Selector;
// ok
htmlElementSelector.findByLocatorId('id').find('.test-children');
htmlElementSelector.findByLocatorId('id').find('.test-children') satisfies Selector;
// ok
htmlElementSelector.find('body').findByLocatorId('id');
htmlElementSelector.find('body').findByLocatorId('id') satisfies Selector;

// ok
createSelector('id').findByLocatorId('id').find('body').findByLocatorId('id');
createSelector('id').findByLocatorId('id').find('body').findByLocatorId('id') satisfies Selector;
// ok
createSelectorByCss('id').findByLocatorId('id').find('body').findByLocatorId('id');
createSelectorByCss('id')
.findByLocatorId('id')
.find('body')
.findByLocatorId('id') satisfies Selector;
// ok
locatorIdSelector('id').findByLocatorId('id').find('body').findByLocatorId('id');
locatorIdSelector('id').findByLocatorId('id').find('body').findByLocatorId('id') satisfies Selector;

// @ts-expect-error: wrong number of arguments
locatorIdSelector();
Expand All @@ -32,32 +37,32 @@ locatorIdSelector();
locatorIdSelector(3);

// ok
htmlElementSelector.filterByLocatorId('id');
htmlElementSelector.filterByLocatorId('id') satisfies Selector;
// ok
htmlElementSelector.parentByLocatorId('id');
htmlElementSelector.parentByLocatorId('id') satisfies Selector;
// ok
htmlElementSelector.childByLocatorId('id');
htmlElementSelector.childByLocatorId('id') satisfies Selector;
// ok
htmlElementSelector.siblingByLocatorId('id');
htmlElementSelector.siblingByLocatorId('id') satisfies Selector;
// ok
htmlElementSelector.nextSiblingByLocatorId('id');
htmlElementSelector.nextSiblingByLocatorId('id') satisfies Selector;
// ok
htmlElementSelector.prevSiblingByLocatorId('id');
htmlElementSelector.prevSiblingByLocatorId('id') satisfies Selector;

// ok
htmlElementSelector.filterByLocatorParameter('prop', 'value');
htmlElementSelector.filterByLocatorParameter('prop', 'value') satisfies Selector;
// ok
htmlElementSelector.findByLocatorParameter('prop', 'value');
htmlElementSelector.findByLocatorParameter('prop', 'value') satisfies Selector;
// ok
htmlElementSelector.parentByLocatorParameter('prop', 'value');
htmlElementSelector.parentByLocatorParameter('prop', 'value') satisfies Selector;
// ok
htmlElementSelector.childByLocatorParameter('prop', 'value');
htmlElementSelector.childByLocatorParameter('prop', 'value') satisfies Selector;
// ok
htmlElementSelector.siblingByLocatorParameter('prop', 'value');
htmlElementSelector.siblingByLocatorParameter('prop', 'value') satisfies Selector;
// ok
htmlElementSelector.nextSiblingByLocatorParameter('prop', 'value');
htmlElementSelector.nextSiblingByLocatorParameter('prop', 'value') satisfies Selector;
// ok
htmlElementSelector.prevSiblingByLocatorParameter('prop', 'value');
htmlElementSelector.prevSiblingByLocatorParameter('prop', 'value') satisfies Selector;

// ok
void htmlElementSelector.getLocatorId();
Expand All @@ -66,7 +71,7 @@ void htmlElementSelector.getLocatorId();
void htmlElementSelector.getLocatorId('foo');

// ok
void htmlElementSelector.hasLocatorId();
void htmlElementSelector.hasLocatorId() satisfies Promise<boolean>;

Check failure on line 74 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / test-local

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

Check failure on line 74 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / build-docker

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

Check failure on line 74 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

Check failure on line 74 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

// TODO: should be an error "wrong number of arguments"
void htmlElementSelector.hasLocatorId('foo');
Expand All @@ -78,9 +83,9 @@ void htmlElementSelector.hasLocatorParameter();
void htmlElementSelector.getLocatorParameter();

// ok
void htmlElementSelector.getLocatorParameter('prop');
void htmlElementSelector.getLocatorParameter('prop') satisfies Promise<string>;

Check failure on line 86 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / test-local

Type 'undefined' does not satisfy the expected type 'Promise<string>'.

Check failure on line 86 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / build-docker

Type 'undefined' does not satisfy the expected type 'Promise<string>'.

Check failure on line 86 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'undefined' does not satisfy the expected type 'Promise<string>'.

Check failure on line 86 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'undefined' does not satisfy the expected type 'Promise<string>'.
// ok
void htmlElementSelector.hasLocatorParameter('prop');
void htmlElementSelector.hasLocatorParameter('prop') satisfies Promise<boolean>;

Check failure on line 88 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / test-local

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

Check failure on line 88 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / build-docker

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

Check failure on line 88 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

Check failure on line 88 in autotests/tests/internalTypeTests/selectors.skip.ts

View workflow job for this annotation

GitHub Actions / lint

Type 'undefined' does not satisfy the expected type 'Promise<boolean>'.

// ok
htmlElementSelector.getDescription() satisfies string | undefined;
21 changes: 19 additions & 2 deletions src/Page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,25 @@ export abstract class Page<PageParams = undefined> {

this.pageParams = pageParams as PageParams;

const {pageStabilizationInterval} = getFullPackConfig();
const {
pageStabilizationInterval,
waitForAllRequestsComplete: {maxIntervalBetweenRequestsInMs},
} = getFullPackConfig();

this.maxIntervalBetweenRequestsInMs = maxIntervalBetweenRequestsInMs;
this.pageStabilizationInterval = pageStabilizationInterval;
}

/**
* Default maximum interval (in milliseconds) between requests.
* After navigating to the page, `e2ed` will wait until
* all requests will complete, and only after that it will consider the page loaded.
* If there are no new requests for more than this interval,
* then we will consider that all requests completes
* The default value is taken from the corresponding field of the pack config.
*/
readonly maxIntervalBetweenRequestsInMs: number;

/**
* Immutable page parameters.
*/
Expand All @@ -40,6 +54,7 @@ export abstract class Page<PageParams = undefined> {
* After navigating to the page, `e2ed` will wait until
* the page is stable for the specified time in millisecond,
* and only after that it will consider the page loaded.
* The default value is taken from the corresponding field of the pack config.
*/
readonly pageStabilizationInterval: number;

Expand Down Expand Up @@ -80,7 +95,9 @@ export abstract class Page<PageParams = undefined> {
abstract getRoute(): PageRoute<unknown>;

async waitForPageLoaded(): Promise<void> {
await waitForAllRequestsComplete(() => true);
await waitForAllRequestsComplete(() => true, {
maxIntervalBetweenRequestsInMs: this.maxIntervalBetweenRequestsInMs,
});

await waitForInterfaceStabilization(this.pageStabilizationInterval);
}
Expand Down
1 change: 1 addition & 0 deletions src/types/config/ownE2edConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export type OwnE2edConfig<
* Default maximum interval (in milliseconds) between requests.
* If there are no new requests for more than this interval, then the promise
* returned by the `waitForAllRequestsComplete` function will be successfully resolved.
* This parameter can be overridden on a specific page instance.
*/
maxIntervalBetweenRequestsInMs: number;

Expand Down

0 comments on commit 6ce1941

Please sign in to comment.