Skip to content

Commit 8f477aa

Browse files
committed
refactor(visual-regressions): use clack library
1 parent 076c0b8 commit 8f477aa

File tree

4 files changed

+297
-118
lines changed

4 files changed

+297
-118
lines changed

core/package-lock.json

Lines changed: 67 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@capacitor/haptics": "^6.0.0",
4242
"@capacitor/keyboard": "^6.0.0",
4343
"@capacitor/status-bar": "^6.0.0",
44+
"@clack/prompts": "^0.7.0",
4445
"@ionic/eslint-config": "^0.3.0",
4546
"@ionic/prettier-config": "^2.0.0",
4647
"@playwright/test": "^1.39.0",
@@ -100,7 +101,7 @@
100101
"test.e2e.docker": "npm run docker.build && node ./scripts/docker.mjs",
101102
"test.e2e.docker.update-snapshots": "npm run test.e2e.docker -- --update-snapshots",
102103
"test.e2e.docker.ci": "npm run docker.build && CI=true node ./scripts/docker.mjs",
103-
"test.e2e.script": "sh ./scripts/testing/e2e-script.sh"
104+
"test.e2e.script": "node scripts/testing/e2e-script.mjs"
104105
},
105106
"author": "Ionic Team",
106107
"license": "MIT",

core/scripts/testing/e2e-script.mjs

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
// The purpose of this script is to provide a way run the E2E tests
2+
// without having the developer to manually run multiple commands based
3+
// on the desired end result.
4+
// E.g. update the local ground truths for a specific component or
5+
// open the Playwright report after running the E2E tests.
6+
7+
import {
8+
intro,
9+
outro,
10+
confirm,
11+
spinner,
12+
isCancel,
13+
cancel,
14+
text,
15+
} from '@clack/prompts';
16+
import { exec } from 'child_process';
17+
import fs from 'node:fs';
18+
import { setTimeout as sleep } from 'node:timers/promises';
19+
import util from 'node:util';
20+
import color from 'picocolors';
21+
22+
async function main() {
23+
const execAsync = util.promisify(exec);
24+
const cleanUpFiles = async () => {
25+
// Clean up the local ground truths.
26+
const cleanUp = spinner();
27+
28+
// Inform the user that the local ground truths are being cleaned up.
29+
cleanUp.start('Restoring local ground truths');
30+
31+
// Reset the local ground truths.
32+
await execAsync('git reset -- src/**/*-linux.png').catch((error) => {
33+
cleanUp.stop('Failed to reset local ground truths');
34+
console.error(error);
35+
return process.exit(0);
36+
});
37+
38+
// Restore the local ground truths.
39+
await execAsync('git restore -- src/**/*-linux.png').catch((error) => {
40+
cleanUp.stop('Failed to restore local ground truths');
41+
console.error(error);
42+
return process.exit(0);
43+
});
44+
45+
// Inform the user that the local ground truths have been cleaned up.
46+
cleanUp.stop('Local ground truths have been restored to their original state in order to avoid committing them.');
47+
};
48+
49+
intro(color.inverse(' Update Local Ground Truths'));
50+
51+
// Ask user for the component name they want to test.
52+
const componentValue = await text({
53+
message: 'Enter the component or path you want to test (e.g. chip, src/components/chip)',
54+
placeholder: 'Empty for all components',
55+
});
56+
57+
// User cancelled the operation with `Ctrl+C` or `CMD+C`.
58+
if (isCancel(componentValue)) {
59+
cancel('Operation cancelled');
60+
return process.exit(0);
61+
}
62+
63+
// Ask user if they want to update their local ground truths.
64+
const shouldUpdateTruths = await confirm({
65+
message: 'Do you want to update your local ground truths?',
66+
});
67+
68+
// User cancelled the operation with `Ctrl+C` or `CMD+C`.
69+
if (isCancel(shouldUpdateTruths)) {
70+
cancel('Operation cancelled');
71+
return process.exit(0);
72+
}
73+
74+
if (shouldUpdateTruths) {
75+
const defaultBaseBranch = 'main';
76+
77+
// Ask user for the base branch.
78+
let baseBranch = await text({
79+
message: 'Enter the base branch name:',
80+
placeholder: `default: ${defaultBaseBranch}`,
81+
})
82+
83+
// User cancelled the operation with `Ctrl+C` or `CMD+C`.
84+
if (isCancel(baseBranch)) {
85+
cancel('Operation cancelled');
86+
return process.exit(0);
87+
}
88+
89+
// User didn't provide a base branch.
90+
if (!baseBranch) {
91+
baseBranch = defaultBaseBranch;
92+
}
93+
94+
const updateGroundTruth = spinner();
95+
96+
// Inform the user that the local ground truths are being updated.
97+
updateGroundTruth.start('Updating local ground truths');
98+
99+
// Check if user provided an existing file or directory.
100+
const isValidLocation = fs.existsSync(componentValue);
101+
102+
// User provided an existing file or directory.
103+
if (isValidLocation) {
104+
const stats = fs.statSync(componentValue);
105+
106+
// User provided a file as the component.
107+
// ex: `componentValue` = `src/components/chip/test/basic/chip.e2e.ts`
108+
if (stats.isFile()) {
109+
// Update the local ground truths for the provided path.
110+
await execAsync(`git checkout origin/${baseBranch} -- ${componentValue}-snapshots/*-linux.png`).catch((error) => {
111+
updateGroundTruth.stop('Failed to update local ground truths');
112+
console.error(error);
113+
return process.exit(0);
114+
});
115+
}
116+
117+
// User provided a directory as the component.
118+
// ex: `componentValue` = `src/components/chip`
119+
if (stats.isDirectory()) {
120+
// Update the local ground truths for the provided directory.
121+
await execAsync(`git checkout origin/${baseBranch} -- ${componentValue}/test/*/*.e2e.ts-snapshots/*-linux.png`).catch((error) => {
122+
updateGroundTruth.stop('Failed to update local ground truths');
123+
console.error(error);
124+
return process.exit(0);
125+
});
126+
}
127+
}
128+
// User provided a component name as the component.
129+
// ex: `componentValue` = `chip`
130+
else if (componentValue) {
131+
// Update the local ground truths for the provided component.
132+
await execAsync(`git checkout origin/${baseBranch} -- src/components/${componentValue}/test/*/${componentValue}.e2e.ts-snapshots/*-linux.png`).catch((error) => {
133+
updateGroundTruth.stop('Failed to update local ground truths');
134+
console.error(error);
135+
return process.exit(0);
136+
});
137+
}
138+
// User provided an empty string.
139+
else {
140+
// Update the local ground truths for all components.
141+
await execAsync(`git checkout origin/${baseBranch} -- src/components/*/test/*/*.e2e.ts-snapshots/*-linux.png`).catch((error) => {
142+
updateGroundTruth.stop('Failed to update local ground truths');
143+
console.error(error);
144+
return process.exit(0);
145+
});
146+
}
147+
148+
// Inform the user that the local ground truths have been updated.
149+
updateGroundTruth.stop('Updated local ground truths');
150+
}
151+
152+
const buildCore = spinner();
153+
154+
// Inform the user that the core is being built.
155+
buildCore.start('Building core');
156+
157+
/**
158+
* Build core
159+
* Otherwise, the uncommitted changes will not be reflected in the tests because:
160+
* - popping the stash doesn't trigger a re-render even if `npm start` is running
161+
* - app is not running the `npm start` command
162+
*/
163+
await execAsync('npm run build').catch((error) => {
164+
// Clean up the local ground truths.
165+
cleanUpFiles();
166+
167+
buildCore.stop('Failed to build core');
168+
console.error(error);
169+
return process.exit(0);
170+
});
171+
172+
buildCore.stop('Built core');
173+
174+
const runE2ETests = spinner();
175+
176+
// Inform the user that the E2E tests are being run.
177+
runE2ETests.start('Running E2E tests');
178+
179+
// User provided a component value.
180+
if (componentValue) {
181+
await execAsync(`npm run test.e2e.docker.ci ${componentValue}`).catch((error) => {
182+
// Clean up the local ground truths.
183+
cleanUpFiles();
184+
185+
runE2ETests.stop('Failed to run E2E tests');
186+
console.error(error);
187+
return process.exit(0);
188+
});
189+
} else {
190+
await execAsync('npm run test.e2e.docker.ci').catch((error) => {
191+
// Clean up the local ground truths.
192+
cleanUpFiles();
193+
194+
runE2ETests.stop('Failed to run E2E tests');
195+
console.error(error);
196+
return process.exit(0);
197+
});
198+
}
199+
200+
runE2ETests.stop('Ran E2E tests');
201+
202+
// Clean up the local ground truths.
203+
await cleanUpFiles();
204+
205+
// Ask user if they want to open the Playwright report.
206+
const shouldOpenReport = await confirm({
207+
message: 'Do you want to open the Playwright report?',
208+
});
209+
210+
// User cancelled the operation with `Ctrl+C` or `CMD+C`.
211+
if (isCancel(shouldOpenReport)) {
212+
cancel('Operation cancelled');
213+
return process.exit(0);
214+
}
215+
216+
// User chose to open the Playwright report.
217+
if (shouldOpenReport) {
218+
await execAsync('npx playwright show-report').catch(() => {
219+
console.error('Error: Failed to open the Playwright report or user closed the report');
220+
});
221+
}
222+
223+
outro("You're all set!");
224+
225+
await sleep(1000);
226+
}
227+
228+
main().catch(console.error);

0 commit comments

Comments
 (0)