Skip to content

Commit

Permalink
FI-705 fix: stricter type of expect function
Browse files Browse the repository at this point in the history
fix: support usual promises in `expect` function
feat: add field `maxIntervalBetweenRequestsInMs` ot abstract class `Page`
feat: add examples of `mapBackendResponseErrorToLog`/`mapBackendResponseToLog`
tests: more tests of types of selectors methods
chore: update nodejs to current LTS (20.10.0)
chore: update alpine to 3.18.5
fix: support new contributor in `updateChangelog` script
refactor: move selectors code to `utils/selectors`
refactor: remove `utils/locators`
fix: use default cursor for empty expanded steps
feat: add duration to backend response logs
refactor: rename function `it` to `test` in initial autotests examples
fix: print `message` and `cause` fields of `E2edError` in `replaceFields`
fix: reject stuck assertion of `expect` by timeout
tests: add separate tests for `expect` function
feat: add type `ResponseWithRequest` to public API
feat: use `ResponseWithRequest` for mapping backend responses to logs
chore: update devDependencies (typescript, eslint, @types/node, etc)
chore: update npm `lockfileVersion` (package-lock.json) from 2 to 3
chore: update github action and node version in ci.yaml
  • Loading branch information
uid11 committed Dec 7, 2023
1 parent 791ed2f commit 6b489b8
Show file tree
Hide file tree
Showing 89 changed files with 807 additions and 5,939 deletions.
18 changes: 9 additions & 9 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ jobs:
build-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: npm
node-version: 16.11.1
node-version: lts
- run: npm ci
- run: npm run build
- run: npm run build:docker

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: npm
node-version: 16.11.1
node-version: lts
- run: npm ci
- run: npm run build
- run: npm run lint

test-local:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: npm
node-version: 16.11.1
node-version: lts
- run: npm ci
- run: npm run build
- run: npm run test:local
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
FROM alpine:3.18.4
FROM node:20.10.0-alpine AS node

FROM alpine:3.18.5

COPY --from=node /usr/lib /usr/lib
COPY --from=node /usr/local/lib /usr/local/lib
COPY --from=node /usr/local/include /usr/local/include
COPY --from=node /usr/local/bin /usr/local/bin

RUN apk --no-cache upgrade && \
apk --no-cache add \
bash libevent nodejs npm chromium firefox xwininfo xvfb dbus eudev ttf-freefont fluxbox procps tzdata icu-data-full
bash libevent npm chromium firefox xwininfo xvfb dbus eudev ttf-freefont fluxbox procps tzdata icu-data-full

COPY ./build/node_modules/e2ed /node_modules/e2ed

Expand Down
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
38 changes: 38 additions & 0 deletions autotests/configurator/mapBackendResponseErrorToLog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {getDurationWithUnits} from 'e2ed/utils';

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 = ({
completionTimeInMs,
request,
responseBody,
responseHeaders,
statusCode,
}) => {
if (statusCode < 400) {
return undefined;
}

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

const duration = getDurationWithUnits(completionTimeInMs - utcTimeInMs);

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

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 = ({
completionTimeInMs,
request,
responseBody,
responseHeaders,
statusCode,
}) => {
if (statusCode >= 400) {
return undefined;
}

if (request) {
const maybeWithDuration: {duration?: string} = {};

if (completionTimeInMs !== undefined && request.utcTimeInMs !== undefined) {
maybeWithDuration.duration = getDurationWithUnits(completionTimeInMs - request.utcTimeInMs);
}

return {...maybeWithDuration, statusCode, url: request?.url};
}

return {
responseBody: responseBody instanceof Buffer ? String(responseBody) : responseBody,
responseHeaders,
statusCode,
};
};
2 changes: 1 addition & 1 deletion autotests/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export {it} from './it';
export {test} from './test';
10 changes: 5 additions & 5 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 All @@ -30,7 +32,7 @@ const filterTestsIntoPack: FilterTestsIntoPack = ({options}) => options.meta.tes
*/
export const pack: Pack = {
ajaxRequestTimeout: 40_000,
assertionTimeout: 10_000,
assertionTimeout: 5_000,
browser: [browser, ...browserFlags].join(' '),
browserInitTimeout: 60_000,
concurrency: isLocalRun ? 1 : 2,
Expand All @@ -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
20 changes: 13 additions & 7 deletions autotests/pageObjects/pages/Main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,19 @@ 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/') ||
url.startsWith('https://play.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
2 changes: 1 addition & 1 deletion autotests/it.ts → autotests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ import type {Pack} from 'autotests/types/packSpecific';
* Test function that describes the test or the task
* (test does not necessarily contain checks).
*/
export const it = createTestFunction<Pack>(hooks);
export const test = createTestFunction<Pack>(hooks);
4 changes: 2 additions & 2 deletions autotests/tests/e2edReportExample/browserData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-console */

import {it} from 'autotests';
import {test} from 'autotests';
import {E2edReportExample} from 'autotests/pageObjects/pages';
import {createClientFunction, expect} from 'e2ed';
import {
Expand All @@ -11,7 +11,7 @@ import {
waitForInterfaceStabilization,
} from 'e2ed/actions';

it('correctly read data from browser', {meta: {testId: '14'}}, async () => {
test('correctly read data from browser', {meta: {testId: '14'}}, async () => {
await navigateToPage(E2edReportExample);

await setPageElementsIgnoredOnInterfaceStabilization(['.retry']);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {it} from 'autotests';
import {test} from 'autotests';
import {E2edReportExample} from 'autotests/pageObjects/pages';
import {expect} from 'e2ed';
import {click, navigateToPage} from 'e2ed/actions';

it('custom selector methods', {meta: {testId: '15'}}, async () => {
test('selector custom methods', {meta: {testId: '15'}}, async () => {
const reportPage = await navigateToPage(E2edReportExample);

await expect(reportPage.navigationRetries.exists, 'navigation retries exists').ok();
Expand Down
4 changes: 2 additions & 2 deletions autotests/tests/e2edReportExample/setPageCookies.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {it} from 'autotests';
import {test} from 'autotests';
import {E2edReportExample} from 'autotests/pageObjects/pages';
import {expect} from 'e2ed';
import {navigateToPage} from 'e2ed/actions';
Expand All @@ -14,7 +14,7 @@ const cookie = {
value: 'bar',
} as const;

it('set page cookies', {meta: {testId: '5'}, testIdleTimeout: 35_000}, async () => {
test('set page cookies correctly', {meta: {testId: '5'}, testIdleTimeout: 35_000}, async () => {
await navigateToPage(E2edReportExample, {pageCookies: [cookie]});

const documentCookie = await getDocumentCookie();
Expand Down
35 changes: 35 additions & 0 deletions autotests/tests/expect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {test} from 'autotests';
import {createSelectorByCss} from 'autotests/selectors';
import {expect} from 'e2ed';
import {assertFunctionThrows, getTimeoutPromise} from 'e2ed/utils';

test('expect function works correctly', {meta: {testId: '16'}}, async () => {
await assertFunctionThrows(async () => {
await expect(1, 'should throws').eql(2);
}, 'throws an error when actual value do not fit expected value');

await assertFunctionThrows(async () => {
await expect(getTimeoutPromise(5_100), 'should failed by timeout').ok();
}, 'throws an timeout error when actual value is a pending promise');

await expect(Promise.resolve('foo'), 'awaits usual promises').eql('foo');

await assertFunctionThrows(async () => {
await expect(
Promise.resolve('foo'),
'throws an error when comparing for equality of values of different types',
// @ts-expect-error: actual value and expected value has different types
).eql(3);
}, 'throws an error when actual value and expected value has different types');

// eslint-disable-next-line @typescript-eslint/no-floating-promises
expect(1, 'should be an eslint error when we call expect without await').eql(1);

// eslint-disable-next-line @typescript-eslint/await-thenable
await expect(1, 'should be an eslint error when we do not call the assertion method');

const htmlSelector = createSelectorByCss('html');

// @ts-expect-error: expect function should not accept a selector as a actual value
await expect(htmlSelector, 'should be type error when actual value is a selector').ok();
});
Loading

0 comments on commit 6b489b8

Please sign in to comment.