Skip to content

Commit

Permalink
test(): add text drag and drop e2e test (#9112)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Andrea Bogazzi <[email protected]>
  • Loading branch information
3 people authored Aug 30, 2023
1 parent 0287646 commit 14a4b7b
Show file tree
Hide file tree
Showing 20 changed files with 390 additions and 29 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ change-output.md
before_commit
/coverage/
.idea/
**/dist
**/dist/
/cli_output/
e2e/test-report/
e2e/test-results/
**/.cache/
docs/
7 changes: 4 additions & 3 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ change-output.md
before_commit
/coverage/
.idea/
/dist/fabric.require.js
/dist/fabric.min.js.gz
/cli_output/
/scripts/cli_cache.json
/dist/
**/dist/
/lib/
/test/
.next/
.parcel-cache/
/docs/
/e2e/test-results/
/e2e/test-report/
/e2e/tests/**/*-snapshots/*.json
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]

- test(e2e): Drag&Drop tests [#9112](https://github.com/fabricjs/fabric.js/pull/9112)
- fix(CanvasEvents): regression of `getPointer` usages + BREAKING: drop event data [#9186](https://github.com/fabricjs/fabric.js/pull/9186)
- feat(Object): BREAKING rm \_setOriginToCenter and \_resetOrigin unuseful methods [#9179](https://github.com/fabricjs/fabric.js/pull/9179)
- fix(ActiveSelection): reset positioning when cleared [#9088](https://github.com/fabricjs/fabric.js/pull/9088)
Expand Down
7 changes: 5 additions & 2 deletions e2e/.babelrc.js → e2e/.babelrc.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// https://github.com/viruscamp/babel-plugin-transform-imports#using-a-function-as-the-transformer

const path = require('path');
import path from 'path';
import { createRequire } from 'module';

const testsDir = path.resolve('./e2e/tests');
const testsBuiltDir = path.resolve('./e2e/dist');
const require = createRequire(process.cwd());

function resolve(file) {
const found = ['', '.ts', '/index.ts']
Expand All @@ -21,7 +24,7 @@ function resolve(file) {
return require.resolve(found).replace(/\.ts$/, '.js');
}

module.exports = {
export default {
extends: '../.babelrcAlt',
plugins: [
[
Expand Down
39 changes: 24 additions & 15 deletions e2e/setup/setupCoverage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,37 @@ import v8toIstanbul from 'v8-to-istanbul';

// https://playwright.dev/docs/api/class-coverage

const coverageIgnore = ['node_modules', 'e2e'];

test.beforeEach(async ({ page }) => {
await page.coverage.startJSCoverage({ reportAnonymousScripts: false });
});

test.afterEach(async ({ page }, { outputDir }) => {
const coverage = await page.coverage.stopJSCoverage();
const nyc = _.fromPairs(
await Promise.all(
coverage.map(async ({ url, source, functions }) => {
let pathname = url;
try {
// remove url origin
pathname = pathname.slice(new URL(url).origin.length + 1);
} catch (error) {}
const pathTo = path.resolve(process.cwd(), pathname);
const converter = v8toIstanbul(pathTo, 0, {
source: source!,
});
await converter.load();
converter.applyCoverage(functions);
return [pathTo, converter.toIstanbul()];
})
(
await Promise.all(
coverage.map(async ({ url, source, functions }) => {
let pathname = url;
try {
// remove url origin
pathname = pathname.slice(new URL(url).origin.length + 1);
} catch (error) {}
const pathTo = path.resolve(process.cwd(), pathname);
const converter = v8toIstanbul(pathTo, 0, {
source: source!,
});
await converter.load();
converter.applyCoverage(functions);
return [pathTo, converter.toIstanbul()];
})
)
).filter(
([pathTo]: [string]) =>
!coverageIgnore.some((ignore) =>
pathTo.startsWith(path.resolve(process.cwd(), ignore))
)
)
);
ensureDirSync(outputDir);
Expand Down
217 changes: 217 additions & 0 deletions e2e/tests/text/drag&drop/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import type { Locator, Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { binaryToBuffer } from '../../../utils/binaryToBuffer';

import '../../../setup';

const dragA = 'fabric';
const dragB = 'em ipsum\ndolor\nsit Amet2\nconsectge';

test('Drag & Drop', async ({ page }) => {
const canvas = page.locator('canvas').nth(1);
await test.step(`select "${dragA}" in A`, async () => {
await canvas.click({
position: {
x: 130,
y: 50,
},
});
await page.mouse.dblclick(130, 50);
await canvas.hover({
position: {
x: 130,
y: 40,
},
});
});
await test.step('drag & drop to end', async () => {
await page.mouse.down();
await page.mouse.move(0, 140, { steps: 40 });
await page.mouse.move(435, 55, { steps: 40 });
expect(
await canvas.screenshot(),
`1. drag "${dragA}" over "lor|em" (A => B)`
).toMatchSnapshot({
name: '1.drag-fabric-over-lor|em.png',
});
await page.mouse.move(240, 140, { steps: 40 });
expect(
await canvas.screenshot(),
`2. before dropping "${dragA}" => "sandbox|" (A => A)`
).toMatchSnapshot({
name: '2.before-drop-fabric-after-sandbox.png',
});
await page.mouse.up();
expect(
await canvas.screenshot(),
`3. drop "${dragA}" => "sandbox|${dragA}" (A => A)`
).toMatchSnapshot({
name: '3.drop-fabric-after-sandbox.png',
});
});

await test.step(`drag & drop to B(3) = "lor|${dragA}|em"`, async () => {
await canvas.dragTo(canvas, {
sourcePosition: {
x: 230,
y: 140,
},
targetPosition: {
x: 435,
y: 55,
},
});
expect(
await canvas.screenshot(),
`4. drag & drop "${dragA}" => "lor|${dragA}|em" (A => B(3))`
).toMatchSnapshot({
name: '4.drop--lor|fabric|em.png',
});
});

await test.step('select B', async () => {
await canvas.click({
position: {
x: 598,
y: 59,
},
});
await page.mouse.down();
await page.mouse.move(580, 300, { steps: 40 });
await page.mouse.up();
});

await test.step(`drag & drop to A(4) = ".js |${dragB}|sandbox"`, async () => {
await canvas.dragTo(canvas, {
sourcePosition: {
x: 580,
y: 280,
},
targetPosition: {
x: 120,
y: 55,
},
});
expect(
await canvas.screenshot(),
`5. drag & drop "${dragB}" => ".js |${dragB}|sandbox" (B => A(4))`
).toMatchSnapshot({
name: '5..js |em ips.png',
});
});
});

async function waitForDragImage(
page: Page,
canvas: Locator,
{ x, y }: { x: number; y: number }
) {
return test.step('initialize drag start', async () => {
await canvas.hover({
position: {
x,
y,
},
});
await page.mouse.down();
const dataTransfer = await page.evaluateHandle(() =>
Object.defineProperty(new DataTransfer(), 'setDragImage', {
value: (image, x, y) =>
window.dispatchEvent(
new CustomEvent('drag:image', { detail: { image, x, y } })
),
})
);
return [
{ dataTransfer },
page
.evaluate(
() =>
new Promise<{ image: string; x: number; y: number }>((resolve) =>
window.addEventListener(
'drag:image',
({ detail: { image, x, y } }) =>
resolve({
image: image.toDataURL(`image/png`, 1),
x,
y,
}),
{ once: true }
)
)
)
.then(({ x, y, image }) => {
return [binaryToBuffer(image), { x, y }] as const;
}),
] as const;
});
}

test('Drag Image A', async ({ page }) => {
const canvas = page.locator('canvas').nth(1);

await test.step('select word', async () => {
await canvas.click({
position: {
x: 130,
y: 50,
},
});
await page.mouse.dblclick(130, 50);
});

await test.step('start dragging', async () => {
const [dragEvent, trigger] = await waitForDragImage(page, canvas, {
x: 130,
y: 40,
});
await canvas.dispatchEvent('dragstart', dragEvent);
const [image, position] = await trigger;
expect(image, `drag image A: "${dragA}"`).toMatchSnapshot({
name: 'drag-image-fabric.png',
maxDiffPixelRatio: 0.03,
});
expect(
JSON.stringify(position, null, 2),
`drag image A position: "${dragA}"`
).toMatchSnapshot({
name: 'drag-image-fabric.json',
maxDiffPixelRatio: 0.03,
});
});
});

test('Drag Image B', async ({ page }) => {
const canvas = page.locator('canvas').nth(1);

await test.step('select word', async () => {
await page.mouse.dblclick(435, 55);
await canvas.click({
position: {
x: 435,
y: 55,
},
});
await page.mouse.down();
await page.mouse.move(580, 300, { steps: 40 });
await page.mouse.up();
});

await test.step('start dragging', async () => {
const [dragEvent, trigger] = await waitForDragImage(page, canvas, {
x: 500,
y: 280,
});
await canvas.dispatchEvent('dragstart', dragEvent);
const [image, position] = await trigger;
expect(image, `drag image B: "${dragB}"`).toMatchSnapshot({
name: 'drag-image-em---tge.png',
});
expect(
JSON.stringify(position, null, 2),
`drag image B position: "${dragB}"`
).toMatchSnapshot({
name: 'drag-image-em---tge.json',
});
});
});
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"x": -400,
"y": -20
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"x": -44.5,
"y": -20
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 14a4b7b

Please sign in to comment.