Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix MCR test on webkit, add pollForApproximate #4777

Merged
merged 1 commit into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 34 additions & 38 deletions test/playwright/SharedRendererTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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]);
});
});

Expand Down
67 changes: 55 additions & 12 deletions test/playwright/TestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,17 @@ export async function openTerminal(ctx: ITestContext, options: ITerminalOptions

export type MaybeAsync<T> = Promise<T> | T;

export async function pollFor<T>(page: playwright.Page, evalOrFn: string | (() => MaybeAsync<T>), val: T, preFn?: () => Promise<void>, maxDuration?: number, stack?: string): Promise<void> {
stack ??= new Error().stack;
interface IPollForOptions<T> {
equalityFn?: (a: T, b: T) => boolean;
maxDuration?: number;
stack?: string;
}

export async function pollFor<T>(page: playwright.Page, evalOrFn: string | (() => MaybeAsync<T>), val: T, preFn?: () => Promise<void>, options?: IPollForOptions<T>): Promise<void> {
if (!options) {
options = {};
}
options.stack ??= new Error().stack;
if (preFn) {
await preFn();
}
Expand All @@ -385,32 +394,66 @@ export async function pollFor<T>(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<void>(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<T>(page: playwright.Page, marginOfError: number, evalOrFn: string | (() => MaybeAsync<T>), val: T, preFn?: () => Promise<void>, maxDuration?: number, stack?: string): Promise<void> {
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<void> {
await page.evaluate(`
window.ready = false;
Expand Down