From 1792eaf05fe32c855231edd9e8986433206bbe43 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 9 Sep 2023 07:45:31 -0700 Subject: [PATCH] Fix MCR test on webkit, add pollForApproximate Fixes #4769 --- test/playwright/SharedRendererTests.ts | 72 ++++++++++++-------------- test/playwright/TestUtils.ts | 67 +++++++++++++++++++----- 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/test/playwright/SharedRendererTests.ts b/test/playwright/SharedRendererTests.ts index e19ff14664..889bfc40e2 100644 --- a/test/playwright/SharedRendererTests.ts +++ b/test/playwright/SharedRendererTests.ts @@ -6,7 +6,7 @@ import { IImage32, decodePng } from '@lunapaint/png-codec'; import { LocatorScreenshotOptions, test } from '@playwright/test'; import { ITheme } from 'xterm'; -import { ITestContext, MaybeAsync, pollFor } from './TestUtils'; +import { ITestContext, MaybeAsync, pollFor, pollForApproximate } from './TestUtils'; export interface ISharedRendererTestContext { value: ITestContext; @@ -863,11 +863,6 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void }); test('should enforce half the contrast for dim cells', async () => { - // TODO: This test fails on webkit - if (ctx.value.browser.browserType().name() === 'webkit') { - test.skip(); - return; - } const theme: ITheme = { background: '#ffffff', black: '#2e3436', @@ -897,43 +892,44 @@ export function injectSharedRendererTests(ctx: ISharedRendererTestContext): void `\x1b[90m■\x1b[91m■\x1b[92m■\x1b[93m■\x1b[94m■\x1b[95m■\x1b[96m■\x1b[97m■` ); // Validate before minimumContrastRatio is applied - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [Math.floor((255 + 0x2e) / 2), Math.floor((255 + 0x34) / 2), Math.floor((255 + 0x36) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 2, 1), [Math.floor((255 + 0xcc) / 2), Math.floor((255 + 0x00) / 2), Math.floor((255 + 0x00) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 3, 1), [Math.floor((255 + 0x4e) / 2), Math.floor((255 + 0x9a) / 2), Math.floor((255 + 0x06) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 4, 1), [Math.floor((255 + 0xc4) / 2), Math.floor((255 + 0xa0) / 2), Math.floor((255 + 0x00) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 5, 1), [Math.floor((255 + 0x34) / 2), Math.floor((255 + 0x65) / 2), Math.floor((255 + 0xa4) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 6, 1), [Math.floor((255 + 0x75) / 2), Math.floor((255 + 0x50) / 2), Math.floor((255 + 0x7b) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 7, 1), [Math.floor((255 + 0x06) / 2), Math.floor((255 + 0x98) / 2), Math.floor((255 + 0x9a) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 8, 1), [Math.floor((255 + 0xd3) / 2), Math.floor((255 + 0xd7) / 2), Math.floor((255 + 0xcf) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 2), [Math.floor((255 + 0x55) / 2), Math.floor((255 + 0x57) / 2), Math.floor((255 + 0x53) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 2, 2), [Math.floor((255 + 0xef) / 2), Math.floor((255 + 0x29) / 2), Math.floor((255 + 0x29) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 3, 2), [Math.floor((255 + 0x8a) / 2), Math.floor((255 + 0xe2) / 2), Math.floor((255 + 0x34) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 4, 2), [Math.floor((255 + 0xfc) / 2), Math.floor((255 + 0xe9) / 2), Math.floor((255 + 0x4f) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 5, 2), [Math.floor((255 + 0x72) / 2), Math.floor((255 + 0x9f) / 2), Math.floor((255 + 0xcf) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 6, 2), [Math.floor((255 + 0xad) / 2), Math.floor((255 + 0x7f) / 2), Math.floor((255 + 0xa8) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 7, 2), [Math.floor((255 + 0x34) / 2), Math.floor((255 + 0xe2) / 2), Math.floor((255 + 0xe2) / 2), 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 8, 2), [Math.floor((255 + 0xee) / 2), Math.floor((255 + 0xee) / 2), Math.floor((255 + 0xec) / 2), 255]); + const marginOfError = 1; + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 1, 1), [Math.floor((255 + 0x2e) / 2), Math.floor((255 + 0x34) / 2), Math.floor((255 + 0x36) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 2, 1), [Math.floor((255 + 0xcc) / 2), Math.floor((255 + 0x00) / 2), Math.floor((255 + 0x00) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 3, 1), [Math.floor((255 + 0x4e) / 2), Math.floor((255 + 0x9a) / 2), Math.floor((255 + 0x06) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 4, 1), [Math.floor((255 + 0xc4) / 2), Math.floor((255 + 0xa0) / 2), Math.floor((255 + 0x00) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 5, 1), [Math.floor((255 + 0x34) / 2), Math.floor((255 + 0x65) / 2), Math.floor((255 + 0xa4) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 6, 1), [Math.floor((255 + 0x75) / 2), Math.floor((255 + 0x50) / 2), Math.floor((255 + 0x7b) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 7, 1), [Math.floor((255 + 0x06) / 2), Math.floor((255 + 0x98) / 2), Math.floor((255 + 0x9a) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 8, 1), [Math.floor((255 + 0xd3) / 2), Math.floor((255 + 0xd7) / 2), Math.floor((255 + 0xcf) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 1, 2), [Math.floor((255 + 0x55) / 2), Math.floor((255 + 0x57) / 2), Math.floor((255 + 0x53) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 2, 2), [Math.floor((255 + 0xef) / 2), Math.floor((255 + 0x29) / 2), Math.floor((255 + 0x29) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 3, 2), [Math.floor((255 + 0x8a) / 2), Math.floor((255 + 0xe2) / 2), Math.floor((255 + 0x34) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 4, 2), [Math.floor((255 + 0xfc) / 2), Math.floor((255 + 0xe9) / 2), Math.floor((255 + 0x4f) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 5, 2), [Math.floor((255 + 0x72) / 2), Math.floor((255 + 0x9f) / 2), Math.floor((255 + 0xcf) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 6, 2), [Math.floor((255 + 0xad) / 2), Math.floor((255 + 0x7f) / 2), Math.floor((255 + 0xa8) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 7, 2), [Math.floor((255 + 0x34) / 2), Math.floor((255 + 0xe2) / 2), Math.floor((255 + 0xe2) / 2), 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 8, 2), [Math.floor((255 + 0xee) / 2), Math.floor((255 + 0xee) / 2), Math.floor((255 + 0xec) / 2), 255]); // Setting and check for minimum contrast values, note that these are not // exact to the contrast ratio, if the increase luminance algorithm // changes then these will probably fail await ctx.value.page.evaluate(`window.term.options.minimumContrastRatio = 10;`); frameDetails = undefined; - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 1), [150, 153, 154, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 2, 1), [229, 127, 127, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 3, 1), [63, 124, 4, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 4, 1), [127, 104, 0, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 5, 1), [153, 178, 209, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 6, 1), [186, 167, 189, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 7, 1), [4, 122, 124, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 8, 1), [110, 112, 108, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 1, 2), [170, 171, 169, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 2, 2), [215, 36, 36, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 3, 2), [72, 117, 25, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 4, 2), [117, 109, 36, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 5, 2), [72, 103, 135, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 6, 2), [125, 91, 121, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 7, 2), [25, 117, 117, 255]); - await pollFor(ctx.value.page, () => getCellColor(ctx.value, 8, 2), [111, 111, 110, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 1, 1), [150, 153, 154, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 2, 1), [229, 127, 127, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 3, 1), [63, 124, 4, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 4, 1), [127, 104, 0, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 5, 1), [153, 178, 209, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 6, 1), [186, 167, 189, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 7, 1), [4, 122, 124, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 8, 1), [110, 112, 108, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 1, 2), [170, 171, 169, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 2, 2), [215, 36, 36, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 3, 2), [72, 117, 25, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 4, 2), [117, 109, 36, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 5, 2), [72, 103, 135, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 6, 2), [125, 91, 121, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 7, 2), [25, 117, 117, 255]); + await pollForApproximate(ctx.value.page, marginOfError, () => getCellColor(ctx.value, 8, 2), [111, 111, 110, 255]); }); }); diff --git a/test/playwright/TestUtils.ts b/test/playwright/TestUtils.ts index 02a08907d2..18a1f1bba9 100644 --- a/test/playwright/TestUtils.ts +++ b/test/playwright/TestUtils.ts @@ -374,8 +374,17 @@ export async function openTerminal(ctx: ITestContext, options: ITerminalOptions export type MaybeAsync = Promise | T; -export async function pollFor(page: playwright.Page, evalOrFn: string | (() => MaybeAsync), val: T, preFn?: () => Promise, maxDuration?: number, stack?: string): Promise { - stack ??= new Error().stack; +interface IPollForOptions { + equalityFn?: (a: T, b: T) => boolean; + maxDuration?: number; + stack?: string; +} + +export async function pollFor(page: playwright.Page, evalOrFn: string | (() => MaybeAsync), val: T, preFn?: () => Promise, options?: IPollForOptions): Promise { + if (!options) { + options = {}; + } + options.stack ??= new Error().stack; if (preFn) { await preFn(); } @@ -385,32 +394,66 @@ export async function pollFor(page: playwright.Page, evalOrFn: string | (() = console.log('pollFor\n actual: ', JSON.stringify(result), ' expected: ', JSON.stringify(val)); } - let equalityCheck = true; - try { - deepStrictEqual(result, val); - } catch (e) { - equalityCheck = false; + let equalityCheck: boolean; + if (options.equalityFn) { + equalityCheck = options.equalityFn(result as T, val); + } else { + equalityCheck = true; + try { + deepStrictEqual(result, val); + } catch (e) { + equalityCheck = false; + } } if (!equalityCheck) { - if (maxDuration === undefined) { - maxDuration = 2000; + if (options.maxDuration === undefined) { + options.maxDuration = 2000; } - if (maxDuration <= 0) { + if (options.maxDuration <= 0) { deepStrictEqual(result, val, ([ `pollFor max duration exceeded.`, (`Last comparison: ` + `${typeof result === 'object' ? JSON.stringify(result) : result} (actual) !== ` + `${typeof val === 'object' ? JSON.stringify(val) : val} (expected)`), - `Stack: ${stack}` + `Stack: ${options.stack}` ].join('\n'))); } return new Promise(r => { - setTimeout(() => r(pollFor(page, evalOrFn, val, preFn, maxDuration! - 10, stack)), 10); + setTimeout(() => r(pollFor(page, evalOrFn, val, preFn, { + ...options, + maxDuration: options!.maxDuration! - 10, + stack: options!.stack + })), 10); }); } } +export async function pollForApproximate(page: playwright.Page, marginOfError: number, evalOrFn: string | (() => MaybeAsync), val: T, preFn?: () => Promise, maxDuration?: number, stack?: string): Promise { + await pollFor(page, evalOrFn, val, preFn, { + maxDuration, + stack, + equalityFn: (a, b) => { + if (a === b) { + return true; + } + if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) { + let success = true; + for (let i = 0 ; i < a.length; i++) { + if (Math.abs(a[i] - b[i]) > marginOfError) { + success = false; + break; + } + } + if (success) { + return true; + } + } + return false; + } + }); +} + export async function writeSync(page: playwright.Page, data: string): Promise { await page.evaluate(` window.ready = false;