Skip to content

Commit

Permalink
FI-1011 fix: error with stabilizationInterval argument
Browse files Browse the repository at this point in the history
fix: by default open failed test in HTML report (if any)
fix: add timeout option to `takeScreenshot` action
  • Loading branch information
uid11 committed Nov 12, 2023
1 parent 9d10c04 commit 1c02a39
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 36 deletions.
37 changes: 31 additions & 6 deletions src/actions/takeScreenshot.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,46 @@
import {LogEventType} from '../constants/internal';
import {testController} from '../testController';
import {E2edError} from '../utils/error';
import {getDurationWithUnits} from '../utils/getDurationWithUnits';
import {log} from '../utils/log';
import {getPromiseWithResolveAndReject} from '../utils/promise';

import type {Inner} from 'testcafe-without-typecheck';

type TakeScreenshot = ((path?: string) => Promise<void>) &
((options: Inner.TakeScreenshotOptions) => Promise<void>);
((options: Inner.TakeScreenshotOptions & Readonly<{timeout?: number}>) => Promise<void>);

/**
* Takes a screenshot of the tested page.
*/
export const takeScreenshot: TakeScreenshot = (pathOrOptions) => {
const options: Inner.TakeScreenshotOptions | undefined =
typeof pathOrOptions === 'string' ? {path: pathOrOptions} : pathOrOptions;
const {fullPage, path: pathToScreenshot} = options ?? {};
const options = typeof pathOrOptions === 'string' ? {path: pathOrOptions} : pathOrOptions;
const {fullPage, path: pathToScreenshot, timeout = 10_0000} = options ?? {};

log('Take a screenshot of the page', {fullPage, pathToScreenshot}, LogEventType.InternalAction);
const timeoutWithUnits = getDurationWithUnits(timeout);

return testController.takeScreenshot(pathOrOptions as never);
log(
'Take a screenshot of the page',
{fullPage, pathToScreenshot, timeoutWithUnits},
LogEventType.InternalAction,
);

const {promise, reject, setRejectTimeoutFunction} = getPromiseWithResolveAndReject(timeout);

setRejectTimeoutFunction(() => {
const error = new E2edError(
`takeScreenshot promise rejected after ${timeoutWithUnits} timeout`,
{fullPage, pathToScreenshot},
);

reject(error);
});

return Promise.race([
promise,
testController.takeScreenshot({
fullPage,
path: pathToScreenshot,
} as Inner.TakeScreenshotOptions),
]) as Promise<void>;
};
4 changes: 2 additions & 2 deletions src/actions/waitFor/waitForInterfaceStabilization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ export const waitForInterfaceStabilization = async (
config;

// eslint-disable-next-line no-param-reassign
stabilizationInterval = stabilizationIntervalFromConfig;
stabilizationInterval ??= stabilizationIntervalFromConfig;
// eslint-disable-next-line no-param-reassign
timeout = timeoutFromConfig;
timeout ??= timeoutFromConfig;
}

if (!(stabilizationInterval > 0) || !(timeout > 0)) {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/report/client/addDomContentLoadedHandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Adds DOMContentloaded handler for report page.
* Adds `DOMContentLoaded` handler for report page.
* If the page is already loaded, then call the handler immediately.
* This client function should not use scope variables (except global functions).
* @internal
Expand Down
2 changes: 1 addition & 1 deletion src/utils/report/client/chooseTestRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ declare const e2edTestRunDetailsContainer: HTMLElement;
declare const reportClientState: ReportClientState;

/**
* Choose TestRun (render chosen TestRun in right panel).
* Chooses TestRun (render chosen TestRun in right panel).
* This base client function should not use scope variables (except other base functions).
* @internal
*/
Expand Down
6 changes: 5 additions & 1 deletion src/utils/report/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ export {clickOnStep} from './clickOnStep';
/** @internal */
export {clickOnTestRun} from './clickOnTestRun';
/** @internal */
export {domContentLoadedHandler} from './domContentLoadedHandler';
export {onDomContentLoad} from './onDomContentLoad';
/** @internal */
export {onFirstJsonReportDataLoad} from './onFirstJsonReportDataLoad';
/** @internal */
export {initialScript} from './initialScript';
/** @internal */
export {parseMarkdownLinks} from './parseMarkdownLinks';
/** @internal */
export {readJsonReportData} from './readJsonReportData';
/** @internal */
export {readPartOfJsonReportData} from './readPartOfJsonReportData';
/** @internal */
export {
renderDatesInterval,
renderDuration,
Expand Down
6 changes: 3 additions & 3 deletions src/utils/report/client/initialScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import {addOnClickOnClass as clientAddOnClickOnClass} from './addOnClickOnClass'
import {clickOnRetry as clientClickOnRetry} from './clickOnRetry';
import {clickOnStep as clientClickOnStep} from './clickOnStep';
import {clickOnTestRun as clientClickOnTestRun} from './clickOnTestRun';
import {domContentLoadedHandler as clientDomContentLoadedHandler} from './domContentLoadedHandler';
import {onDomContentLoad as clientOnDomContentLoad} from './onDomContentLoad';
import {setReadJsonReportDataObservers as clientSetReadJsonReportDataObservers} from './setReadJsonReportDataObservers';

const addDomContentLoadedHandler = clientAddDomContentLoadedHandler;
const addOnClickOnClass = clientAddOnClickOnClass;
const clickOnRetry = clientClickOnRetry;
const clickOnStep = clientClickOnStep;
const clickOnTestRun = clientClickOnTestRun;
const domContentLoadedHandler = clientDomContentLoadedHandler;
const onDomContentLoad = clientOnDomContentLoad;
const setReadJsonReportDataObservers = clientSetReadJsonReportDataObservers;

/**
Expand All @@ -26,5 +26,5 @@ export const initialScript = (): void => {

setReadJsonReportDataObservers();

addDomContentLoadedHandler(domContentLoadedHandler);
addDomContentLoadedHandler(onDomContentLoad);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ declare const reportClientState: ReportClientState;
const readJsonReportData = clientReadJsonReportData;

/**
* DOMContentloaded handler for report page.
* `DOMContentLoaded` handler for report page.
* This client function should not use scope variables (except global functions).
* @internal
*/
export function domContentLoadedHandler(): void {
export function onDomContentLoad(): void {
readJsonReportData(true);

for (const observer of reportClientState.readJsonReportDataObservers) {
Expand Down
36 changes: 36 additions & 0 deletions src/utils/report/client/onFirstJsonReportDataLoad.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {clickOnTestRun as clientClickOnTestRun} from './clickOnTestRun';

const clickOnTestRun = clientClickOnTestRun;

declare const e2edTestRunDetailsContainer: HTMLElement;

/**
* Handler of loading first part of JSON report data for report page.
* This client function should not use scope variables (except global functions).
* @internal
*/
export function onFirstJsonReportDataLoad(): void {
if (window.location.hash !== '') {
return;
}

const buttonForFailedTestRun = document.querySelector(
'.retry:not([hidden]) .test-button_status_failed',
);

if (!buttonForFailedTestRun) {
return;
}

clickOnTestRun(buttonForFailedTestRun as HTMLElement);

const buttonOfOpenStep = document.querySelector('.step-expanded[aria-expanded="true"]');

if (buttonOfOpenStep) {
const {top} = buttonOfOpenStep.getBoundingClientRect();

setTimeout(() => {
e2edTestRunDetailsContainer.scrollTop = top;
}, 8);
}
}
36 changes: 18 additions & 18 deletions src/utils/report/client/readJsonReportData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type {FullTestRun, ReportClientState} from '../../../types/internal';
import {onFirstJsonReportDataLoad as clientOnFirstJsonReportDataLoad} from './onFirstJsonReportDataLoad';
import {readPartOfJsonReportData as clientReadPartOfJsonReportData} from './readPartOfJsonReportData';

import type {ReportClientState} from '../../../types/internal';

const onFirstJsonReportDataLoad = clientOnFirstJsonReportDataLoad;
const readPartOfJsonReportData = clientReadPartOfJsonReportData;

declare const reportClientState: ReportClientState;

Expand All @@ -9,7 +15,7 @@ declare const reportClientState: ReportClientState;
* This client function should not use scope variables (except global functions).
* @internal
*/
export function readJsonReportData(areAllScriptsLoaded?: boolean): void {
export function readJsonReportData(areAllScriptsLoaded = false): void {
const {lengthOfReadedJsonReportDataParts} = reportClientState;
const scripts = document.querySelectorAll('body > script.e2edJsonReportData');
const {length} = scripts;
Expand All @@ -18,26 +24,20 @@ export function readJsonReportData(areAllScriptsLoaded?: boolean): void {
return;
}

let hasParseErrorForLastScript = false;
let isLastReadSuccessful = true;

for (let i = lengthOfReadedJsonReportDataParts; i < length; i += 1) {
try {
const fullTestRuns = JSON.parse(scripts[i]?.textContent ?? '') as readonly FullTestRun[];
for (let index = lengthOfReadedJsonReportDataParts; index < length; index += 1) {
isLastReadSuccessful = readPartOfJsonReportData({
scriptToRead: scripts[index],
shouldLogError: index < length - 1 || areAllScriptsLoaded,
});
}

(reportClientState.fullTestRuns as FullTestRun[]).push(...fullTestRuns);
} catch (error) {
if (i < length - 1 || areAllScriptsLoaded) {
// eslint-disable-next-line no-console
console.error(`Cannot parse JSON report data from script number ${i}`);
}
const newLength = areAllScriptsLoaded || isLastReadSuccessful ? length : length - 1;

if (i === length - 1) {
hasParseErrorForLastScript = true;
}
}
if (reportClientState.lengthOfReadedJsonReportDataParts === 0 && newLength > 0) {
onFirstJsonReportDataLoad();
}

const newLength = !areAllScriptsLoaded && hasParseErrorForLastScript ? length - 1 : length;

reportClientState.lengthOfReadedJsonReportDataParts = newLength;
}
31 changes: 31 additions & 0 deletions src/utils/report/client/readPartOfJsonReportData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type {FullTestRun, ReportClientState} from '../../../types/internal';

declare const reportClientState: ReportClientState;

type Options = Readonly<{
scriptToRead: Element | undefined;
shouldLogError: boolean;
}>;

/**
* Reads part of JSON report data from script tag.
* Returns `true` if read successfully, and `false` if it has parse errors.
* This client function should not use scope variables (except global functions).
* @internal
*/
export function readPartOfJsonReportData({scriptToRead, shouldLogError}: Options): boolean {
try {
const fullTestRuns = JSON.parse(scriptToRead?.textContent ?? '') as readonly FullTestRun[];

(reportClientState.fullTestRuns as FullTestRun[]).push(...fullTestRuns);
} catch (error) {
if (shouldLogError) {
// eslint-disable-next-line no-console
console.error('Cannot parse JSON report data from script', error);
}

return false;
}

return true;
}
8 changes: 6 additions & 2 deletions src/utils/report/render/renderScriptFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import {
clickOnStep,
clickOnTestRun,
createSafeHtmlWithoutSanitize,
domContentLoadedHandler,
onDomContentLoad,
onFirstJsonReportDataLoad,
parseMarkdownLinks,
readJsonReportData,
readPartOfJsonReportData,
renderDatesInterval,
renderDuration,
renderStep,
Expand Down Expand Up @@ -39,10 +41,12 @@ ${createSafeHtmlWithoutSanitize.toString()}
${clickOnRetry.toString()}
${clickOnStep.toString()}
${clickOnTestRun.toString()}
${domContentLoadedHandler.toString()}
${onDomContentLoad.toString()}
${onFirstJsonReportDataLoad.toString()}
${getDurationWithUnits.toString()}
${parseMarkdownLinks.toString()}
${readJsonReportData.toString()}
${readPartOfJsonReportData.toString()}
${renderDatesInterval.toString()}
${renderDuration.toString()}
${renderStep.toString()}
Expand Down

0 comments on commit 1c02a39

Please sign in to comment.