Skip to content

Commit

Permalink
feat(testing): allow to set screenshot timeout option in Jest v28+ (#…
Browse files Browse the repository at this point in the history
…5537)

* feat(testing): allow to set screenshot timeout option in Jest v28+

* prettier

* update docs
  • Loading branch information
christian-bromann committed Mar 27, 2024
1 parent 2851210 commit 6df12b2
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 5 deletions.
27 changes: 27 additions & 0 deletions src/compiler/config/test/validate-testing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,33 @@ describe('validateTesting', () => {
});
});

describe('screenshotTimeout', () => {
it('sets screenshotTimeout to null if not provided', () => {
userConfig.flags = { ...flags, e2e: true };
userConfig.testing = {};

const { config } = validateConfig(userConfig, mockLoadConfigInit());
expect(config.testing.screenshotTimeout).toEqual(null);
});

it('sets screenshotTimeout to null if it has an unexpected value', () => {
userConfig.flags = { ...flags, e2e: true };
// @ts-expect-error - the nature of this test requires a non-string value
userConfig.testing = { screenshotTimeout: '4s' };

const { config } = validateConfig(userConfig, mockLoadConfigInit());
expect(config.testing.screenshotTimeout).toEqual(null);
});

it('keeps the value if set correctly', () => {
userConfig.flags = { ...flags, e2e: true };
userConfig.testing = { screenshotTimeout: 4000 };

const { config } = validateConfig(userConfig, mockLoadConfigInit());
expect(config.testing.screenshotTimeout).toEqual(4000);
});
});

describe('testPathIgnorePatterns', () => {
it('does not alter a provided testPathIgnorePatterns', () => {
userConfig.flags = { ...flags, e2e: true };
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/config/validate-testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ export const validateTesting = (config: d.ValidatedConfig, diagnostics: d.Diagno
);
}

/**
* We only allow numbers or null for the screenshotTimeout, so if we detect anything
* else, we set it to null.
*/
if (typeof testing.screenshotTimeout != 'number') {
testing.screenshotTimeout = null;
}

if (!Array.isArray(testing.testPathIgnorePatterns)) {
testing.testPathIgnorePatterns = DEFAULT_IGNORE_PATTERNS.map((ignorePattern) => {
return join(testing.rootDir!, ignorePattern);
Expand Down
1 change: 1 addition & 0 deletions src/declarations/stencil-private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,7 @@ export interface E2EProcessEnv {

__STENCIL_SCREENSHOT__?: 'true';
__STENCIL_SCREENSHOT_BUILD__?: string;
__STENCIL_SCREENSHOT_TIMEOUT_MS__?: string;

__STENCIL_E2E_TESTS__?: 'true';
__STENCIL_E2E_DEVTOOLS__?: 'true';
Expand Down
6 changes: 6 additions & 0 deletions src/declarations/stencil-public-compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1984,6 +1984,12 @@ export interface TestingConfig extends JestConfig {
*/
screenshotConnector?: string;

/**
* Timeout for the pixelmatch worker to resolve (in ms).
* @default 2500
*/
screenshotTimeout?: number | null;

/**
* Amount of time in milliseconds to wait before a screenshot is taken.
*/
Expand Down
24 changes: 19 additions & 5 deletions src/screenshot/screenshot-compare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ import { join, relative } from 'path';

import { writeScreenshotData, writeScreenshotImage } from './screenshot-fs';

/**
* @see {@link d.TestingConfig.screenshotTimeout}
*/
const DEFAULT_SCREENSHOT_TIMEOUT = 2500;

export async function compareScreenshot(
emulateConfig: d.EmulateConfig,
screenshotBuildData: d.ScreenshotBuildData,
currentScreenshotBuf: Buffer,
screenshotTimeoutMs: number | null,
desc: string,
width: number,
height: number,
Expand Down Expand Up @@ -115,6 +121,7 @@ export async function compareScreenshot(
screenshot.diff.mismatchedPixels = await getMismatchedPixels(
screenshotBuildData.pixelmatchModulePath,
pixelMatchInput,
screenshotTimeoutMs,
);
}
}
Expand All @@ -124,19 +131,26 @@ export async function compareScreenshot(
return screenshot.diff;
}

async function getMismatchedPixels(pixelmatchModulePath: string, pixelMatchInput: d.PixelMatchInput) {
async function getMismatchedPixels(
pixelmatchModulePath: string,
pixelMatchInput: d.PixelMatchInput,
screenshotTimeoutMs: number | null,
) {
return new Promise<number>((resolve, reject) => {
/**
* When using screenshot functionality in a runner that is not Jasmine (e.g. Jest Circus), we need to set a default
* value for timeouts. There are runtime errors that occur if we attempt to use optional chaining + nullish
* coalescing with the `jasmine` global stating it's not defined. As a result, we use a ternary here.
*
* The '2500' value that we default to is the value of `jasmine.DEFAULT_TIMEOUT_INTERVAL` (5000) divided by 2.
* For Jest environments that don't use Jest Circus we define the timeout based on the
* `jasmine.DEFAULT_TIMEOUT_INTERVAL` (5000) divided by 2. Otherwise we use {@link d.TestingConfig.screenshotTimeout}.
*/
const timeout =
typeof jasmine !== 'undefined' && jasmine.DEFAULT_TIMEOUT_INTERVAL
? jasmine.DEFAULT_TIMEOUT_INTERVAL * 0.5
: 2500;
screenshotTimeoutMs !== null
? screenshotTimeoutMs
: typeof jasmine !== 'undefined' && jasmine.DEFAULT_TIMEOUT_INTERVAL
? jasmine.DEFAULT_TIMEOUT_INTERVAL * 0.5
: DEFAULT_SCREENSHOT_TIMEOUT;
const tmr = setTimeout(() => {
reject(`getMismatchedPixels timeout: ${timeout}ms`);
}, timeout);
Expand Down
6 changes: 6 additions & 0 deletions src/testing/puppeteer/puppeteer-screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ export async function pageCompareScreenshot(
throw new Error(`compareScreenshot, missing screen build env var`);
}

const screenshotTimeoutMs: number | null =
typeof env.__STENCIL_SCREENSHOT_TIMEOUT_MS__ === 'string'
? parseInt(env.__STENCIL_SCREENSHOT_TIMEOUT_MS__, 10)
: null;

const emulateConfig = JSON.parse(env.__STENCIL_EMULATE__) as EmulateConfig;
const screenshotBuildData = JSON.parse(env.__STENCIL_SCREENSHOT_BUILD__) as ScreenshotBuildData;

Expand Down Expand Up @@ -131,6 +136,7 @@ export async function pageCompareScreenshot(
emulateConfig,
screenshotBuildData,
screenshotBuf,
screenshotTimeoutMs,
desc,
width,
height,
Expand Down
3 changes: 3 additions & 0 deletions src/testing/testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ export const createTesting = async (config: ValidatedConfig): Promise<Testing> =
doScreenshots = !!(opts.e2e && opts.screenshot);
if (doScreenshots) {
env.__STENCIL_SCREENSHOT__ = 'true';
if (config.testing.screenshotTimeout != null) {
env.__STENCIL_SCREENSHOT_TIMEOUT_MS__ = config.testing.screenshotTimeout.toString();
}

if (opts.updateScreenshot) {
config.logger.info(config.logger.magenta(`updating master screenshots`));
Expand Down

0 comments on commit 6df12b2

Please sign in to comment.