Skip to content

Commit

Permalink
FI-1072 fix: fail tests run if doAfterPack/doBeforePack throw an …
Browse files Browse the repository at this point in the history
…error

fix: do not lose error fields after `replaceFields`
refactor: turn on `@typescript-eslint/sort-type-constituents` rule
  • Loading branch information
uid11 committed Dec 13, 2023
1 parent 8795c2b commit 46d2e94
Show file tree
Hide file tree
Showing 35 changed files with 134 additions and 63 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ rules:
'@typescript-eslint/no-unnecessary-boolean-literal-compare': off
'@typescript-eslint/no-use-before-define': error
'@typescript-eslint/quotes': [error, single, {avoidEscape: true}]
'@typescript-eslint/sort-type-constituents': [error, {checkIntersections: false}]
settings:
import/extensions: [.ts]
import/resolver: {node: {extensions: [.ts]}}
2 changes: 1 addition & 1 deletion autotests/configurator/mapBackendResponseToLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import type {MapBackendResponseToLog} from 'autotests/types/packSpecific';
*/
export const mapBackendResponseToLog: MapBackendResponseToLog = ({
duration,
statusCode,
request,
statusCode,
}) => {
if (statusCode >= 400) {
return undefined;
Expand Down
29 changes: 14 additions & 15 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,22 @@ Modules in the dependency graph should only import the modules above them:
12. `utils/valueToString`
13. `utils/error`
14. `utils/asserts`
15. `utils/userlandHooks`
15. `utils/userland`
16. `utils/fn`
17. `utils/environment`
18. `utils/getFullPackConfig`
19. `utils/runLabel`
20. `utils/generalLog`
21. `utils/runArrayOfFunctionsSafely`
22. `utils/fs`
23. `selectors`
24. `Route`
25. `ApiRoute`
26. `PageRoute`
27. `testController`
28. `useContext`
29. `context`
30. `utils/log`
31. `utils/waitForEvents`
32. `utils/expect`
33. `expect`
34. ...
21. `utils/fs`
22. `selectors`
23. `Route`
24. `ApiRoute`
25. `PageRoute`
26. `testController`
27. `useContext`
28. `context`
29. `utils/log`
30. `utils/waitForEvents`
31. `utils/expect`
32. `expect`
33. ...
2 changes: 1 addition & 1 deletion src/actions/pages/navigateToPage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {LogEventType} from '../../constants/internal';
import {getDurationWithUnits} from '../../utils/getDurationWithUnits';
import {log} from '../../utils/log';
import {getUserlandHooks} from '../../utils/userlandHooks';
import {getUserlandHooks} from '../../utils/userland';

import {createPageInstance} from './createPageInstance';

Expand Down
2 changes: 1 addition & 1 deletion src/actions/setFilesToUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {Selector, TestCafeSelector} from '../types/internal';
*/
export const setFilesToUpload = (
selector: Selector,
filePath: string | string[],
filePath: string[] | string,
): Promise<void> => {
const hasManyFiles = Array.isArray(filePath) && filePath.length > 0;
const description = getDescriptionFromSelector(selector);
Expand Down
2 changes: 1 addition & 1 deletion src/actions/setNativeDialogHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {LogEventType} from '../constants/internal';
import {testController} from '../testController';
import {log} from '../utils/log';

type NativeDialogType = 'alert' | 'confirm' | 'beforeunload' | 'prompt';
type NativeDialogType = 'alert' | 'beforeunload' | 'confirm' | 'prompt';

/**
* Specifies handler function for the browser native dialogs
Expand Down
3 changes: 2 additions & 1 deletion src/configurator/getReplacedObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export const getReplacedObject = <Value extends object>(

const replacedObject = (Array.isArray(value) ? [] : {}) as Value;

const keys: PropertyKey[] = Object.keys(value);
const keys: PropertyKey[] =
value instanceof Error ? Object.getOwnPropertyNames(value) : Object.keys(value);

keys.push(...Object.getOwnPropertySymbols(value));

Expand Down
2 changes: 2 additions & 0 deletions src/constants/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ export const enum ExitCode {
HasErrors = 2,
NoRetries = 3,
NoReportData = 4,
HasErrorsInDoAfterPackFunctions = 5,
HasErrorsInDoBeforePackFunctions = 6,
}
2 changes: 1 addition & 1 deletion src/createTestFunction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {setUserlandHooks} from './utils/userlandHooks';
import {setUserlandHooks} from './utils/userland';
import {test} from './test';

import type {AnyPack, GetPackParameters, TestFunction, UserlandHooks} from './types/internal';
Expand Down
8 changes: 4 additions & 4 deletions src/types/clientFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ export type ClientFunctionState<Args extends readonly unknown[], Result> = {
* @internal
*/
export type ClientFunctionWrapperResult<Result = unknown> = Readonly<
| {
errorMessage: undefined;
result: Result;
}
| {
errorMessage: string;
result: undefined;
}
| {
errorMessage: undefined;
result: Result;
}
>;

/**
Expand Down
8 changes: 4 additions & 4 deletions src/types/http/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ export type Query =
| Readonly<
Record<
string,
| string
| number
| boolean
| readonly string[]
| readonly number[]
| number
| string
| readonly boolean[]
| readonly number[]
| readonly string[]
| null
| undefined
>
Expand Down
2 changes: 1 addition & 1 deletion src/types/mockApiRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type ApiMockFunction<
> = (
routeParams: RouteParams,
request: SomeRequest,
) => Promise<Partial<SomeResponse>> | Partial<SomeResponse>;
) => Partial<SomeResponse> | Promise<Partial<SomeResponse>>;

/**
* Internal state of mockApiRoute/unmockApiRoute.
Expand Down
2 changes: 1 addition & 1 deletion src/types/promise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type AsyncVoid = MaybePromise<void>;
/**
* A value of a type `Type` that may be wrapped in a promise.
*/
export type MaybePromise<Type> = Type | Promise<Type>;
export type MaybePromise<Type> = Promise<Type> | Type;

/**
* Reexecutable promise from TestCafe.
Expand Down
8 changes: 4 additions & 4 deletions src/types/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type DataPropertyDescriptor<Value> = Readonly<
GenericPropertyDescriptor;

type AccessorPropertyDescriptor<Value> = Readonly<
{get(): Value; set?(value: Value): void} | {get?(): Value; set(value: Value): void}
{get?(): Value; set(value: Value): void} | {get(): Value; set?(value: Value): void}
> &
GenericPropertyDescriptor;

Expand All @@ -31,15 +31,15 @@ export type FieldReplacer = (
/**
* Primitive value.
*/
export type PrimitiveValue = bigint | boolean | null | number | string | symbol | undefined;
export type PrimitiveValue = bigint | boolean | number | string | symbol | null | undefined;

/**
* Property descriptor.
*/
export type PropertyDescriptor<Value = unknown> =
| GenericPropertyDescriptor
| AccessorPropertyDescriptor<Value>
| DataPropertyDescriptor<Value>
| AccessorPropertyDescriptor<Value>;
| GenericPropertyDescriptor;

/**
* Property key.
Expand Down
2 changes: 1 addition & 1 deletion src/types/testRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type RejectTestRun = (error: E2edError) => void;
/**
* Test run error (in string presentation), if any.
*/
export type RunError = string | StringForLogs | undefined;
export type RunError = StringForLogs | string | undefined;

/**
* Hash string of each test run, generated by userland hook.
Expand Down
9 changes: 8 additions & 1 deletion src/utils/events/registerEndE2edRunEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {ExitCode} from '../../constants/internal';
import {processExit} from '../exit';
import {failMessage, generalLog, okMessage} from '../generalLog';
import {collectReportData, getLiteReport, writeHtmlReport, writeLiteJsonReport} from '../report';
import {setReadonlyProperty} from '../setReadonlyProperty';

import {collectFullEventsData} from './collectFullEventsData';
import {runAfterPackFunctions} from './runAfterPackFunctions';
Expand All @@ -29,7 +30,13 @@ export const registerEndE2edRunEvent = async (): Promise<void> => {

const liteReport = getLiteReport(reportData);

await runAfterPackFunctions(liteReport);
try {
await runAfterPackFunctions(liteReport);
} catch (error) {
generalLog('Caught an error on run "after pack" functions', {error});

setReadonlyProperty(reportData, 'exitCode', ExitCode.HasErrorsInDoAfterPackFunctions);
}

const {customReportProperties} = liteReport;

Expand Down
2 changes: 1 addition & 1 deletion src/utils/events/registerEndTestRunEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {cloneWithoutLogEvents} from '../clone';
import {getRunErrorFromError} from '../error';
import {writeTestRunToJsonFile} from '../fs';
import {generalLog, logEndTestRunEvent, writeLogsToFile} from '../generalLog';
import {getUserlandHooks} from '../userlandHooks';
import {getUserlandHooks} from '../userland';

import {calculateTestRunStatus} from './calculateTestRunStatus';
import {getTestRunEvent} from './getTestRunEvent';
Expand Down
12 changes: 10 additions & 2 deletions src/utils/events/registerStartE2edRunEvent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {RunEnvironment} from '../../configurator';
import {EVENTS_DIRECTORY_PATH, TMP_DIRECTORY_PATH} from '../../constants/internal';
import {EVENTS_DIRECTORY_PATH, ExitCode, TMP_DIRECTORY_PATH} from '../../constants/internal';

import {E2edError} from '../error';
import {setGlobalExitCode} from '../exit';
import {createDirectory, removeDirectory, writeStartInfo} from '../fs';
import {generalLog, writeLogsToFile} from '../generalLog';
import {getFullPackConfig, updateConfig} from '../getFullPackConfig';
Expand All @@ -21,7 +23,13 @@ export const registerStartE2edRunEvent = async (): Promise<void> => {

const startInfo = getStartInfo();

await runBeforePackFunctions(startInfo);
try {
await runBeforePackFunctions(startInfo);
} catch (cause) {
setGlobalExitCode(ExitCode.HasErrorsInDoBeforePackFunctions);

throw new E2edError('Caught an error on running "before pack" functions', {cause});
}

const fullPackConfig = getFullPackConfig();

Expand Down
12 changes: 10 additions & 2 deletions src/utils/events/runAfterPackFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {generalLog} from '../generalLog';
import {getFullPackConfig} from '../getFullPackConfig';
import {runArrayOfFunctionsSafely} from '../runArrayOfFunctionsSafely';
import {runArrayOfUserlandFunctions} from '../userland';

import type {CustomReportPropertiesPlaceholder, LiteReport, Void} from '../../types/internal';

Expand All @@ -19,5 +20,12 @@ export const runAfterPackFunctions = async (liteReport: LiteReport): Promise<voi
Object.assign<LiteReport, Partial<LiteReport>>(liteReport, {customReportProperties: result});
};

await runArrayOfFunctionsSafely(functions, () => args, processCurrentFunctionResult);
const message =
functions.length > 0
? `Will be run ${functions.length} after pack function${functions.length > 1 ? 's' : ''}`
: 'There are no after pack functions';

generalLog(message);

await runArrayOfUserlandFunctions(functions, () => args, processCurrentFunctionResult);
};
12 changes: 10 additions & 2 deletions src/utils/events/runBeforePackFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {runArrayOfFunctionsSafely} from '../runArrayOfFunctionsSafely';
import {generalLog} from '../generalLog';
import {runArrayOfUserlandFunctions} from '../userland';

import type {
FullPackConfig,
Expand Down Expand Up @@ -33,7 +34,14 @@ export const runBeforePackFunctions = async (startInfo: StartInfo): Promise<void
});
};

await runArrayOfFunctionsSafely(functions, () => args, processCurrentFunctionResult);
const message =
functions.length > 0
? `Will be run ${functions.length} before pack function${functions.length > 1 ? 's' : ''}`
: 'There are no before pack functions';

generalLog(message);

await runArrayOfUserlandFunctions(functions, () => args, processCurrentFunctionResult);

Object.assign<FullPackConfigWithoutDoBeforePack, Partial<FullPackConfig>>(
startInfo.fullPackConfig,
Expand Down
2 changes: 1 addition & 1 deletion src/utils/exit/getExitCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {assertValueIsDefined} from '../asserts';
import type {Retry} from '../../types/internal';

/**
* Get e2ed exit code by hasErrors flag and array of retries.
* Get e2ed exit code by `hasErrors` flag and array of retries.
* @internal
*/
export const getExitCode = (hasErrors: boolean, retries: readonly Retry[]): ExitCode => {
Expand Down
23 changes: 23 additions & 0 deletions src/utils/exit/globalExitCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {assertValueIsDefined, assertValueIsUndefined} from '../asserts';

import type {ExitCode} from '../../constants/internal';

let globalExitCode: ExitCode | undefined;

/**
* Get global exit code.
* @internal
*/
export const getGlobalExitCode = (): ExitCode | undefined => globalExitCode;

/**
* Set global exit code (once).
* @internal
*/
export const setGlobalExitCode = (exitCode: ExitCode): void => {
assertValueIsUndefined(globalExitCode, 'globalExitCode is not defined', {exitCode});

assertValueIsDefined(exitCode, 'exitCode is defined', {globalExitCode});

globalExitCode = exitCode;
};
2 changes: 2 additions & 0 deletions src/utils/exit/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/** @internal */
export {getExitCode} from './getExitCode';
/** @internal */
export {setGlobalExitCode} from './globalExitCode';
/** @internal */
export {processExit} from './processExit';
10 changes: 9 additions & 1 deletion src/utils/exit/processExit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import {ExitCode} from '../../constants/internal';

import {generalLog, writeLogsToFile} from '../generalLog';

import {getGlobalExitCode} from './globalExitCode';

/**
* Exit from e2ed process with correct exit code.
* @internal
*/
export const processExit = async (exitCode: ExitCode = ExitCode.NoReportData): Promise<void> => {
export const processExit = async (
exitCodeFromReport: ExitCode = ExitCode.NoReportData,
): Promise<void> => {
const globalExitCode = getGlobalExitCode();

const exitCode = globalExitCode === undefined ? exitCodeFromReport : globalExitCode;

generalLog(`Exit from e2ed with code ${exitCode}`);

await writeLogsToFile();
Expand Down
2 changes: 1 addition & 1 deletion src/utils/fn/getFunctionPresentationForLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {Fn, StringForLogs} from '../../types/internal';
/**
* Get custom function string presentation for logs.
*/
export const getFunctionPresentationForLogs = (fn: Fn): string | StringForLogs => {
export const getFunctionPresentationForLogs = (fn: Fn): StringForLogs | string => {
const {length, name} = fn;
const code = getFunctionCode(fn);
const withName = name ? `: ${name}` : '';
Expand Down
4 changes: 2 additions & 2 deletions src/utils/fn/setCustomInspectOnFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {getFunctionPresentationForLogs} from './getFunctionPresentationForLogs';

import type {Fn, StringForLogs} from '../../types/internal';

function getFunctionPresentationForThis(this: Fn): string | StringForLogs {
function getFunctionPresentationForThis(this: Fn): StringForLogs | string {
return getFunctionPresentationForLogs(this);
}

Expand All @@ -29,5 +29,5 @@ export const setCustomInspectOnFunction = <Args extends readonly unknown[], Retu

fn[inspect.custom] = getFunctionPresentationForThis;

(fn as unknown as {toJSON(): string | StringForLogs}).toJSON = getFunctionPresentationForThis;
(fn as unknown as {toJSON(): StringForLogs | string}).toJSON = getFunctionPresentationForThis;
};
2 changes: 1 addition & 1 deletion src/utils/generalLog/truncateArrayForLogs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {MAX_ELEMENTS_COUNT_IN_PRINTED_ARRAY} from '../../constants/internal';

type Return<Type> = readonly Type[] | Readonly<{firstElements: readonly Type[]; length: number}>;
type Return<Type> = Readonly<{firstElements: readonly Type[]; length: number}> | readonly Type[];

/**
* Truncate a long array for a short printout.
Expand Down
Loading

0 comments on commit 46d2e94

Please sign in to comment.