Skip to content

Commit 05f5057

Browse files
authored
Merge branch 'master' into ci-upgrade-next
2 parents 1c5b890 + 8b8d309 commit 05f5057

37 files changed

+2134
-1297
lines changed

.codesandbox/templates/vanilla/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"devDependencies": {
1414
"@parcel/transformer-typescript-tsc": "^2.7.0",
1515
"open-cli": "^7.0.1",
16-
"parcel": "^2.7.0",
16+
"parcel": "^2.9.3",
1717
"typescript": "^5.0.2"
1818
},
1919
"keywords": [

.github/workflows/tests.yml

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ jobs:
6868
- name: Build fabric.js
6969
uses: ./.github/actions/build-fabric-cached
7070
- name: Run ${{ matrix.target }} ${{ matrix.suite }} headless test
71-
uses: coactions/setup-xvfb@v1
72-
with:
73-
run: npm run test -- -c ${{ matrix.target }} -s ${{ matrix.suite }}
71+
run: xvfb-run npm run test -- -c ${{ matrix.target }} -s ${{ matrix.suite }}
7472
node:
7573
needs: [prime-build]
7674
runs-on: ubuntu-latest
@@ -109,8 +107,33 @@ jobs:
109107
with:
110108
name: coverage-jest
111109
path: .nyc_output/*.json
110+
e2e:
111+
needs: [prime-build]
112+
name: Playwright tests
113+
runs-on: ubuntu-latest
114+
steps:
115+
- uses: actions/checkout@v3
116+
- uses: ./.github/actions/cached-install
117+
- name: Build fabric.js
118+
uses: ./.github/actions/build-fabric-cached
119+
# Playwright suggests against caching the browser install
120+
- name: Install Playwright Browsers
121+
run: npx playwright install --with-deps chromium
122+
- name: Run Playwright tests
123+
run: xvfb-run npm run test:e2e
124+
- name: Upload Test Output
125+
uses: actions/upload-artifact@v3
126+
if: failure()
127+
with:
128+
name: e2e-report
129+
path: ./e2e/test-report/
130+
- name: Upload test coverage
131+
uses: actions/upload-artifact@v3
132+
with:
133+
name: coverage-e2e
134+
path: ./e2e/test-results/**/coverage.json
112135
coverage:
113-
needs: [node-coverage]
136+
needs: [node-coverage, e2e]
114137
name: Coverage reporting
115138
runs-on: ubuntu-latest
116139
steps:
@@ -127,6 +150,10 @@ jobs:
127150
with:
128151
name: coverage-visual
129152
path: .nyc_output
153+
- uses: actions/download-artifact@v3
154+
with:
155+
name: coverage-e2e
156+
path: .nyc_output
130157
- run: ls -l .nyc_output
131158
- run: npm run coverage:report
132159
- uses: ShaMan123/[email protected]

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ change-output.md
77
before_commit
88
/coverage/
99
.idea/
10-
/dist
10+
**/dist
1111
/cli_output/
1212
e2e/test-report/
1313
e2e/test-results/

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ lib/*.png
77
coverage/
88
test/
99
test*
10+
e2e/
1011
.DS_Store
1112
.codesandbox/
1213
.devcontainer/

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## [next]
44

55
- ci(sandbox): bump next.js [#9100](https://github.com/fabricjs/fabric.js/pull/9100)
6+
- test(playwright): add snapshots, refactor utils, coverage [#9078](https://github.com/fabricjs/fabric.js/pull/9078)
67
- chore(TS) Add type-checking to files excluded with ts-nocheck ( Parser mostly ) [#9085](https://github.com/fabricjs/fabric.js/pull/9085)
78
- test(Text): Add some tests for text in Jest [#9083](https://github.com/fabricjs/fabric.js/pull/9083)
89
- ci(): Install system deps only when necessary [#9086](https://github.com/fabricjs/fabric.js/pull/9086)

e2e/imports.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { readJSONSync } from 'fs-extra';
2+
3+
/**
4+
* The import map used by `./utils/setupApp` to inject into the page
5+
* so test scripts can use modules (relative imports don't seem to work out of the box)
6+
*
7+
* **IMPORTANT**: be sure to update the paths field in `./tsconfig.json` to reflect imports correctly
8+
*/
9+
export default {
10+
fabric: readJSONSync('./package.json').module.slice(1),
11+
test: '/e2e/dist/test.js',
12+
};

e2e/setup/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// call first
2+
import './setupSelectors';
3+
// call before using fabric
4+
import './setupCoverage';
5+
// call at the end - navigates the page
6+
import './setupApp';

e2e/setup/setupApp.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { test } from '@playwright/test';
2+
import { existsSync, readFileSync } from 'fs';
3+
import path from 'path';
4+
import imports from '../imports';
5+
import { JSDOM } from 'jsdom';
6+
7+
test.beforeEach(async ({ page }, { file }) => {
8+
await page.goto('/e2e/site');
9+
// expose imports for consumption
10+
page.addScriptTag({
11+
type: 'importmap',
12+
content: JSON.stringify({
13+
imports,
14+
}),
15+
});
16+
// add test script
17+
const testDir = path.relative(
18+
path.resolve(process.cwd(), 'e2e', 'tests'),
19+
path.resolve(file, '..')
20+
);
21+
const pathToHTML = path.resolve(
22+
process.cwd(),
23+
'e2e',
24+
'tests',
25+
testDir,
26+
'index.html'
27+
);
28+
if (existsSync(pathToHTML)) {
29+
const doc = new JSDOM(readFileSync(pathToHTML).toString()).window.document;
30+
await page.evaluate((html) => {
31+
document.body.innerHTML = `${html}`;
32+
}, doc.body.innerHTML);
33+
}
34+
const pathToApp = path.resolve(
35+
process.cwd(),
36+
'e2e',
37+
'tests',
38+
testDir,
39+
'index.ts'
40+
);
41+
const pathToBuiltApp = path.resolve(
42+
process.cwd(),
43+
'e2e',
44+
'dist',
45+
testDir,
46+
'index.js'
47+
);
48+
const exists = existsSync(pathToBuiltApp);
49+
if (!exists && existsSync(pathToApp)) {
50+
throw new Error(
51+
`test script '${pathToBuiltApp}' not found: global setup script probably did not run`
52+
);
53+
} else if (exists) {
54+
// used to avoid a race condition that occurs because of script loading
55+
const trigger = page.evaluate(
56+
() =>
57+
new Promise((resolve) => {
58+
window.addEventListener('fabric:setup', resolve, { once: true });
59+
})
60+
);
61+
await page.addScriptTag({
62+
type: 'module',
63+
content: `${readFileSync(
64+
path.relative(process.cwd(), pathToApp)
65+
).toString()}
66+
window.dispatchEvent(new CustomEvent('fabric:setup'));
67+
`,
68+
});
69+
await trigger;
70+
await page.evaluate(() => window.__setupFabricHook());
71+
}
72+
});
73+
74+
test.afterEach(async ({ page }) => {
75+
await page.evaluate(() => window.__teardownFabricHook());
76+
});

e2e/setup/setupCoverage.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { test } from '@playwright/test';
2+
import { ensureDirSync, writeFileSync } from 'fs-extra';
3+
import _ from 'lodash';
4+
import path from 'path';
5+
import { URL } from 'url';
6+
import v8toIstanbul from 'v8-to-istanbul';
7+
8+
// https://playwright.dev/docs/api/class-coverage
9+
10+
test.beforeEach(async ({ page }) => {
11+
await page.coverage.startJSCoverage({ reportAnonymousScripts: false });
12+
});
13+
14+
test.afterEach(async ({ page }, { outputDir }) => {
15+
const coverage = await page.coverage.stopJSCoverage();
16+
const nyc = _.fromPairs(
17+
await Promise.all(
18+
coverage.map(async ({ url, source, functions }) => {
19+
let pathname = url;
20+
try {
21+
// remove url origin
22+
pathname = pathname.slice(new URL(url).origin.length + 1);
23+
} catch (error) {}
24+
const pathTo = path.resolve(process.cwd(), pathname);
25+
const converter = v8toIstanbul(pathTo, 0, {
26+
source: source!,
27+
});
28+
await converter.load();
29+
converter.applyCoverage(functions);
30+
return [pathTo, converter.toIstanbul()];
31+
})
32+
)
33+
);
34+
ensureDirSync(outputDir);
35+
writeFileSync(
36+
path.resolve(outputDir, 'coverage-v8.json'),
37+
JSON.stringify(coverage, null, 2)
38+
);
39+
writeFileSync(
40+
path.resolve(outputDir, 'coverage.json'),
41+
JSON.stringify(nyc, null, 2)
42+
);
43+
});

e2e/setup/setupSelectors.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { selectors, test } from '@playwright/test';
2+
3+
test.beforeAll(async () => {
4+
await selectors.register('canvas_wrapper', () => {
5+
return {
6+
query(root: Document, selector: string) {
7+
return root.querySelector(selector).parentElement;
8+
},
9+
10+
queryAll(root: Document, selector: string) {
11+
return Array.from(root.querySelectorAll(selector)).map(
12+
(el) => el.parentElement
13+
);
14+
},
15+
};
16+
});
17+
18+
await selectors.register('canvas_top', () => {
19+
return {
20+
query(root: Document, selector: string) {
21+
return root
22+
.querySelector(selector)
23+
.parentElement.querySelector('canvas.upper-canvas');
24+
},
25+
26+
queryAll(root: Document, selector: string) {
27+
return Array.from(root.querySelectorAll(selector)).map((el) =>
28+
el.parentElement.querySelector('canvas.upper-canvas')
29+
);
30+
},
31+
};
32+
});
33+
});

0 commit comments

Comments
 (0)