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

tests(): Start moving visual tests to playwright #9481

Merged
merged 12 commits into from
Jul 2, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- tests(): Start moving visual tests to playwrigth [#9481](https://github.com/fabricjs/fabric.js/pull/9481)
- fix(filters): Fix bugs in Pixelate and Blur filter [#9962](https://github.com/fabricjs/fabric.js/pull/9962)
- docs(): update README.md [#9957](https://github.com/fabricjs/fabric.js/pull/9957)

Expand Down
25 changes: 24 additions & 1 deletion e2e/tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import * as fabric from 'fabric';

const canvasMap = (window.canvasMap = new Map<HTMLCanvasElement, Canvas>());
const objectMap = (window.objectMap = new Map<string, FabricObject>());

const renderingTestMap = (window.renderingTestMap = new Map<
string,
() => void
>());
type AsyncReturnValue<T> = T | Promise<T>;

const setupTasks: Promise<void>[] = [];
Expand Down Expand Up @@ -53,6 +56,26 @@ export function before(
setupTasks.push(task);
}

export async function beforeRenderTest(
cb: (
canvas: Canvas
) => AsyncReturnValue<{ title: string; boundFunction: () => void }[]>,
options
) {
const el = document.querySelector<HTMLCanvasElement>('#canvas');
const canvas = new Canvas(el, options);
// cb has to bind the rendering test to the specific canvas and add a clear before the test
const renderingTests = await cb(canvas);
renderingTests.forEach((renderTest) => {
if (renderingTestMap.has(renderTest.title)) {
throw new Error(
`test identifiers must be unique: ${renderTest.title} is already defined`
);
}
renderingTestMap.set(renderTest.title, renderTest.boundFunction);
});
}

Comment on lines +59 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I under this.
Do you want to create a new canvas for every test?
Why? What is the gain?
What about simply resizing the canvas before the test and adding a canvas.clear() after the snapshot call?
Seems more straight forward, simpler and faster and can be exposed on the CanvasUtil.

/**
* Call this method **once** to initialize the default canvas
*
Expand Down
52 changes: 52 additions & 0 deletions e2e/tests/visual-output/rendering/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { expect, test } from '@playwright/test';
import setup from '../../../setup';
import { CanvasUtil } from '../../../utils/CanvasUtil';
import { TestingCanvas } from '../../../utils/createNodeSnapshot';
import { renderTests } from './renderingCases';
import * as fabric from 'fabric/node';

setup();

test('VISUAL RENDERING TESTS', async ({ page }, config) => {
for (const testCase of renderTests) {
if (testCase.disabled !== 'browser') {
await test.step(`browser - ${testCase.title}`, async () => {
// enable and disable this inside the loop
config.config.updateSnapshots = 'missing';
await page.evaluate(
(testTitle) => renderingTestMap.get(testTitle)(),
testCase.title
);
expect(
await new CanvasUtil(page).screenshot(),
`browser snapshot`
).toMatchSnapshot({
name: testCase.golden || `${testCase.title}.png`,
maxDiffPixelRatio: testCase.percentage,
});
});
}
if (testCase.disabled !== 'node') {
await test.step(`node - ${testCase.title}`, async () => {
// we want the browser snapshot of a test to be committed and not the node snapshot
config.config.updateSnapshots = 'none';
const canvas = new TestingCanvas(null, {
enableRetinaScaling: false,
renderOnAddRemove: false,
width: testCase.size[0],
height: testCase.size[1],
});
await testCase.renderFunction(canvas, fabric);
canvas.renderAll();
const buffer = await canvas.getNodeCanvas().toBuffer();
expect(
buffer,
`node snapshot should match browser snapshot`
).toMatchSnapshot({
name: testCase.golden || `${testCase.title}.png`,
maxDiffPixelRatio: testCase.percentage,
});
});
}
}
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions e2e/tests/visual-output/rendering/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Runs in the **BROWSER**
*/

import * as fabric from 'fabric';
import { renderTests } from './renderingCases';
import { beforeRenderTest } from '../../test';

beforeRenderTest(
(canvas) => {
const boundTests = renderTests.map((renderTest) => {
return {
boundFunction: async () => {
canvas.clear();
canvas.setDimensions({
width: renderTest.size[0],
height: renderTest.size[1],
});
await renderTest.renderFunction(canvas, fabric);
},
title: renderTest.title,
};
});
return boundTests;
},
{
enableRetinaScaling: false,
}
);
Loading
Loading