test: add browser acceptance matrix
This commit is contained in:
@@ -16,4 +16,13 @@ jobs:
|
||||
cache: npm
|
||||
- run: npm ci
|
||||
- run: npm run quality
|
||||
- run: npx playwright install --with-deps chromium
|
||||
- run: npm run test:browser:ci
|
||||
- name: Preserve browser failure evidence
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: forgeflow-browser-failure-evidence
|
||||
path: artifacts/
|
||||
if-no-files-found: ignore
|
||||
- run: npm audit --omit=dev --audit-level=high
|
||||
|
||||
@@ -3,4 +3,6 @@ dist/
|
||||
.DS_Store
|
||||
*.log
|
||||
coverage/
|
||||
artifacts/
|
||||
playwright-report/
|
||||
.forgeflow/
|
||||
|
||||
+45
-41
@@ -1,9 +1,11 @@
|
||||
ForgeFlow 0.10.0 source manifest
|
||||
SHA-256 BYTES PATH
|
||||
(The manifest excludes itself, dependencies and generated release artifacts.)
|
||||
a6ce7703a16e24b307af98b06e99e7f6a4230d854bc6ed9b745510603a03926d 370 .gitea/workflows/quality.yml
|
||||
755f4db7d76bfec0963ef051748a82810c0d58acd4ffd823aa6928a5167fceb4 58 .gitignore
|
||||
cedceb71eb846d99c7c4019031833c1c7f93b84a1c6073aec7d2435dc744ca3d 703 .gitea/workflows/quality.yml
|
||||
0182dfbbf5b9fc5e62f064f094f5412bf245f9a67ec712e8807f2ce4da443717 88 .gitignore
|
||||
f14b4987904bcb5814e4459a057ed4d20f58a633152288a761214dcd28780b56 3 .nvmrc
|
||||
f2cdfd679f074475a515fc809607154fd355a60f96e3e69ba69a04c7092c1856 514823 artifacts/browser-report/index.html
|
||||
91d1c43004802cd49950d78eb11c8fa7d05da8ffffe219a8b13b2f561bc00903 45 artifacts/browser/.last-run.json
|
||||
89545860bd6f7566da81edc8328cd2a1ebf33e81a4b0dcf2cec74338c05e8cac 1753 build-windows.ps1
|
||||
0970821475a4452aa19e447e9397a95db836791f16890a1a83fd748ac033dc86 8830 build/icon-128.png
|
||||
09112c1425ca953d8dd8b2bcfd221e5a84b9f81752f7168f360e295030cbc8f2 521 build/icon-16.png
|
||||
@@ -15,41 +17,41 @@ ca32a76e708d565c4af659f0f4d2615fc32114c3f75aec1454862a3ed1e72c41 2263
|
||||
25048ed854e8ce8fece115e555c98d25507b002f8019b6ae717b54604c868c50 46223 build/icon.ico
|
||||
16efd2fca83004f781eae40ae0f706a004ce0bddf338dd087b8adf7eb10c1d84 85704 build/icon.png
|
||||
5f4aca19a35cbcaffa1a6993ce96b7d66052ec2b286022f2af74594e8a310568 15712 CHANGELOG.md
|
||||
04a3058e507c938447d35564e503cf89b76670d8ea45f5209db074dfa2625b91 303090 coverage/tmp/coverage-14228-1785341379444-0.json
|
||||
0f86a35f2e6a48c0789263a4e36190760b0dfa45ce9a1128555b4dd77da2df5b 352006 coverage/tmp/coverage-14596-1785341377618-0.json
|
||||
4ae93dacf27d8ec7e84bd00ab52398a0d99cecb25cf2244be8e6d89824c3d5db 345122 coverage/tmp/coverage-15236-1785341392510-0.json
|
||||
2607418ea469b58eb6190e4cabde794c0773b7746afb0fdd2d401c99a353752a 358520 coverage/tmp/coverage-17880-1785341380606-0.json
|
||||
ea98763aaacb035c1c75fca8f50784fc0cc89b2dedf2ddfa80c0eb32d633af27 342639 coverage/tmp/coverage-19480-1785341377315-0.json
|
||||
fdaef396ca19f7e1f62ea7e6f2172fa615c7e7f26b157e80c896199f5ba3e77e 329358 coverage/tmp/coverage-19612-1785341379233-0.json
|
||||
d2808be6bce7d7d3d4662def01522170b8cef6c802813db92ade8c27b335fbbe 346825 coverage/tmp/coverage-21808-1785341377499-0.json
|
||||
7f788bab2eb9ada8e3c3f7fc1d6948f001018721eccb54e87b98a8916e30695b 299000 coverage/tmp/coverage-24368-1785341377951-0.json
|
||||
d3584daefb19adb8e0e7cd3ca6ffc7f6992636a692a4a3b186da94281950aa8f 302346 coverage/tmp/coverage-25148-1785341378806-0.json
|
||||
e4045202501f53544351ae8f0aba6cdcccef9d08d735f4d0c83634af5d3033b3 344499 coverage/tmp/coverage-29628-1785341379071-0.json
|
||||
bf66bf3c80bfed0d145dc2a73363e47089a74858d3cece5dbef2756bfbfd623b 360893 coverage/tmp/coverage-31472-1785341379151-0.json
|
||||
0d52bfc33883af8fccdc37c436edd95eb83f54c65de87fa09ad03719995574e4 335635 coverage/tmp/coverage-36800-1785341386017-0.json
|
||||
bcb44d6e6369e3cb5fd5306a02097fadd44e6d85eeac5490e7660f841ba86ea3 288320 coverage/tmp/coverage-37176-1785341378929-0.json
|
||||
da4b2512633624ef659682bf16af77d92799bd228e0d69a985fa23246460ce09 111308 coverage/tmp/coverage-44380-1785341379522-0.json
|
||||
96a9f4b2bb3a429dbe5286c7f6c13c39b0e0de882d46724853083ea3d9ac9f6e 317635 coverage/tmp/coverage-44612-1785341382147-0.json
|
||||
705a92db802fac29c0bbe5aa5727ad35350ddfd03bc98efc24d68529f5a41a99 360058 coverage/tmp/coverage-44984-1785341422918-0.json
|
||||
279e70e06e6366bf15bb60f6079c38580d006832ba200ba5cebd9bac8a4e4f02 321057 coverage/tmp/coverage-48188-1785341379614-0.json
|
||||
20758be193868d8f9275dd1eaf35b6bfc652f4682ebc89e4c4aa481e63dd1664 301398 coverage/tmp/coverage-49592-1785341377478-0.json
|
||||
a4275d02b93b13deadcc554844b321fe186ad272e676f93ccf8f84772bc2760c 284667 coverage/tmp/coverage-49952-1785341378477-0.json
|
||||
d704dd8bab1e3fcf52d4e4762e6a3e4eb9818073a2fc1d622a2afe4425ec9cc4 336008 coverage/tmp/coverage-50036-1785341378337-0.json
|
||||
e4dc4ec12d779464d974f7d5c9713f63db6776596698fdc4ce03d18e773a34d9 354684 coverage/tmp/coverage-50728-1785341378056-0.json
|
||||
0487ef221d132f9ada2b57cb216fb0ff167f903cea8df46c61b39b9fa52bd38a 282952 coverage/tmp/coverage-51204-1785341379590-0.json
|
||||
42be90ace3af568e4eace7f1a3a5974856360707839c793b3b092ede0f6c5ad1 344613 coverage/tmp/coverage-51236-1785341383324-0.json
|
||||
1b5a01cc5508a78e28b27f7a46878d54aaca027deb0e93f34f445d9dd32116f1 335945 coverage/tmp/coverage-54004-1785341378407-0.json
|
||||
b46e7b4d5f95b167803a7d0481163a01026b5ac2e9c32e2ba40afa8a4791163e 428588 coverage/tmp/coverage-55224-1785341380041-0.json
|
||||
b175e49795c65f6011dbf04aefd75cb7ebee5c2b248edb50e7df1780f2a599b8 367436 coverage/tmp/coverage-55472-1785341379481-0.json
|
||||
2a53a441228fb74c1f7a488d49c1545e53640af5c1ca720352919c86527e5c19 344934 coverage/tmp/coverage-56192-1785341380236-0.json
|
||||
dd2c111bc050afda47ed7379f88651cda579a965cfed56ddf2b3ca0e5d748ee1 304508 coverage/tmp/coverage-5636-1785341377677-0.json
|
||||
8ce33572e4a3ba6e63b85155dc0ebba61b3e6fd203ef17b762735639dab72467 360058 coverage/tmp/coverage-56392-1785341444543-0.json
|
||||
9efac9c2f67e00fbc2ddd22ff17886ffa212b55b76e21597df1a85417e55ef0c 89175 coverage/tmp/coverage-56440-1785341377010-0.json
|
||||
4b6892c586091b5bf3eead8d8687a318ef2d82874fc0c9efaab25430ee819600 296835 coverage/tmp/coverage-58592-1785341378685-0.json
|
||||
81f7395f307d0c4776331a5125653388650dea21876ace362ec92e3ce1efefda 318326 coverage/tmp/coverage-58856-1785341378523-0.json
|
||||
5370cdb8a3384f62e68314bd4bf0efa78d9db57ced656b011d3b1e995369596e 327419 coverage/tmp/coverage-59512-1785341377212-0.json
|
||||
7e7571c84f4bcdcdd39ba6fcaa2ac9ea1583eeff6cf59ea4c46c601add76e40a 310269 coverage/tmp/coverage-60040-1785341379655-0.json
|
||||
d19fda134998419dd45ecd943d587c26cf80742b140de46449f8ec4bcf9191a9 302513 coverage/tmp/coverage-61124-1785341378630-0.json
|
||||
56691e95912beab52b9e072ad0735a706934def093d91a83a235119e03f7ef21 111308 coverage/tmp/coverage-14112-1785342182302-0.json
|
||||
35e206d8e448f56715fdeaafc82a00680df74edce1bd1d74d2c626c0ebdc8dd4 344934 coverage/tmp/coverage-18504-1785342182921-0.json
|
||||
cd5a1817ee7f405f72ede736ec2ccc5831a14c4ab99c3ae9e1af11c93c7f4c13 354684 coverage/tmp/coverage-23740-1785342180573-0.json
|
||||
f2dbe68eb60983b2038bfda8448e148e0d762794651c8f0ef0a5985549f35d11 301398 coverage/tmp/coverage-30356-1785342180023-0.json
|
||||
04e0ac6a30fdcbbc9f9856697b228626e0355b7c98c6045cf0db01de0c93fc68 344613 coverage/tmp/coverage-35156-1785342187759-0.json
|
||||
0d4e6a6dcc0ce9f8d2d9e304dbbeccc2b551fbe79637fdd16b7e860a58685d68 302513 coverage/tmp/coverage-35780-1785342181205-0.json
|
||||
3c5a7491afc0247568bce0824331c16e2e9af0693b216e01fe73bb41ad4fe91f 327420 coverage/tmp/coverage-38404-1785342179951-0.json
|
||||
24ca89f314bacd35321b8772706e5c4658602abf90e701561d23f67a1d4dd10e 288320 coverage/tmp/coverage-38780-1785342181696-0.json
|
||||
8711b58d90963d5c5239011527a8d504fde3bed93671e09b8e6f8e865837d928 358165 coverage/tmp/coverage-39472-1785342183215-0.json
|
||||
5e8d4cd9c0b348618088733e133986c8bff8d822b7a0f0fb6c04a777f025e249 303090 coverage/tmp/coverage-39536-1785342182261-0.json
|
||||
9aa7a9e3b5daa4a3f2139df2a8b8857d851ef2ce8e3c7679db787f6e72f5df38 302346 coverage/tmp/coverage-41596-1785342181753-0.json
|
||||
cd9419f7829a06e3932ca774fb06c51b3637639e8f750fe0bbce400921c20866 321057 coverage/tmp/coverage-42088-1785342182383-0.json
|
||||
5b75886d617be03df5d1271223cbd8cc660d6603368349d7f7740e7b5005d3d2 304508 coverage/tmp/coverage-42724-1785342180308-0.json
|
||||
e567e65494a3fadf0effdd7058761c890ff35411532673fb6d0feb0f7d0d681f 346823 coverage/tmp/coverage-44760-1785342180156-0.json
|
||||
4f2a6563b9710b23c918d10f1a2d713975f0f5d2feedb5731e87a441bb9eabae 352006 coverage/tmp/coverage-44924-1785342180167-0.json
|
||||
5e355c76dab29a1ecebe30d390970397ae6ccd71798b111fa67e395a1310ad5e 361403 coverage/tmp/coverage-46136-1785342180786-0.json
|
||||
1623101020fed0786a83d5244a03df9bf2124a9a01961a7739ce63ba7c941ca4 336008 coverage/tmp/coverage-47576-1785342181138-0.json
|
||||
0307f0113c6b76b5044cae887f76f3c01cfd7133fd4a00a8591a979eff3ab06e 317635 coverage/tmp/coverage-48580-1785342185938-0.json
|
||||
4588ba2d6ef043d6552135f874f2415865f2401a53c46c6e29229b6925deceb0 335945 coverage/tmp/coverage-48608-1785342180830-0.json
|
||||
9335bccbbea8122e6bcd7190e5266e4a0fbd1e3631d882004e2d43cec41de95d 318326 coverage/tmp/coverage-49480-1785342181092-0.json
|
||||
e82fa624b1ef3e7ea427b58aac1c3135d0ac1af62b5c1768a7c2bd59791765c7 367436 coverage/tmp/coverage-50664-1785342182886-0.json
|
||||
0884915ee6ccec377161cb960b768bb44da6f8622ab3d9542a0c51a9fd0106b9 375705 coverage/tmp/coverage-54052-1785342191177-0.json
|
||||
a0150efac6b758945f87373f8329f05d6be53d11a3201a88a1124372e8ee7d69 282952 coverage/tmp/coverage-54676-1785342182110-0.json
|
||||
885fb349d550fa169fb0a0fe97c96c9f0353e62a321a2022da2de0f1c1958811 345124 coverage/tmp/coverage-56728-1785342195847-0.json
|
||||
e0dbe28900b09fc36b22fbb05bc844f57ff3094b9a1f84da97f793311c37b3f9 344499 coverage/tmp/coverage-57256-1785342181830-0.json
|
||||
615cc6516905c8e53e4b888bc81589ce8542e34634e5a391ba9204843f57221b 428589 coverage/tmp/coverage-58964-1785342182533-0.json
|
||||
5d845ca1a0ff28f1e570dcb8a26502e902589eafc2727171f1aad0aa7a2ce52e 296835 coverage/tmp/coverage-59284-1785342181255-0.json
|
||||
3afca2678ab83c1ecaba8c1abf70b89b3763016acb52df4027d61a590dcf5c19 284668 coverage/tmp/coverage-59848-1785342181206-0.json
|
||||
5a39c973f886c05b9c34ca089f9d410ab5831036e83d7d5dbf525c2feb0e3670 342640 coverage/tmp/coverage-60948-1785342181050-0.json
|
||||
79d1a3635a8c972ac6ab0aa75149b2a5f01b84ae2a0ae68e736490160b22bc27 360058 coverage/tmp/coverage-61560-1785342250533-0.json
|
||||
03adfd7ea1161c638fe6f6a75a0ab0d860f89412ea047209ea1b15f879de9aad 299000 coverage/tmp/coverage-62420-1785342180409-0.json
|
||||
8387e10a857a2195458bf576c4129b2cd516a50ac5408a605eff038376bba64b 310269 coverage/tmp/coverage-62428-1785342182350-0.json
|
||||
a02d7c51b209b5967e63cec657caeb8e671b5c87d34dbe2cfbec2be891f6266e 329358 coverage/tmp/coverage-62604-1785342181856-0.json
|
||||
3488e63749aed14a820a72d8fad385175f2111648bdf2c10a48c1148c419836f 330765 coverage/tmp/coverage-62652-1785342180356-0.json
|
||||
3da8a2ab49221e4c837c413af878b951f1011be09824ee7dcb49485fb40550bd 89175 coverage/tmp/coverage-63428-1785342179556-0.json
|
||||
21cb96e7afe71b1dc791c818dedd244d92f9a6ed4d9ffbb3022ccb187e1bdf0f 852 docs/ACCEPTANCE.md
|
||||
a17f95d96d3c9fbc69d870874e6fbb7472091adefc454b24f835db1279511d72 8296 docs/ARCHITECTURE.md
|
||||
72e846f591c47a0291e7466e58e052d3d5afcf551c4e6c848632ac3c552a1244 3043 docs/CURRENT_STATE.md
|
||||
@@ -121,8 +123,9 @@ c230b931abf2293d2d44b7a69b94c35f1142c093cc46b88739a0de5cbd6d1896 1532
|
||||
4a561ead5ba7cdfaf4efce91842a4308c5f2a77980205879d83835efb8a579db 1067 LICENSE
|
||||
1f0f388df4397e548887bbc7579fd3c864581b86469c01703201ece7a6cbf931 13667 main.cjs
|
||||
91a984a89dd57a084b9a2331763cacdb061582fb590f13df379d92c1a77a2ee1 352 OVERLAY-INSTRUCTIONS.md
|
||||
f3e2a262e251eb165f342dc3c184625ec10d56e536b5a987199b9944f463eee9 181069 package-lock.json
|
||||
43725a143cb927cc70bd823d789788d785d872119c008043c270bbf73948851f 4882 package.json
|
||||
17eeeb1d6f18fbbbb918cdfdbc3836e46ec6be9e32c059cfc330e9e4e73e39d0 183079 package-lock.json
|
||||
96ab185db639205021c5b0b6fbf8d4bf19d2cad8d1a042eab9a425613ea6a574 5018 package.json
|
||||
2a597a5704c576783b8a72407fbc377fa7506b36a4596ea7f7bce126e394f837 1326 playwright.config.mjs
|
||||
69318fdf054be7aa2fe86ead9847da9da65745d8d5de548c8346f3ba0afc4892 12175 preload.cjs
|
||||
abe5dd6fd68f2970cd19ef134094907c67219061d8fe9a1a08324c78de4ad437 484 PUBLISH-AND-ENABLE-UPDATE.cmd
|
||||
f018383f755352ca448e2ebb1e19b1dba412a3eb793d61e64b02953e300754fd 10538 Publish-ForgeFlow-Release.ps1
|
||||
@@ -191,11 +194,11 @@ cdfaacdcd5ae04b0e5c79fefa21f5e09d5c810bcea504c5b6e1d6b744182ff84 15567
|
||||
813b8cdeecac43794166f3db9d3c5d2c441e0292f9ab7bd465ba136d6201e95d 82476 src/renderer/assets/itworx-wordmark-dark.png
|
||||
094c1b71cc2482a9db250ac175f45f3de68f53277dfbde371a03e61923d00988 75240 src/renderer/assets/itworx-wordmark-light.png
|
||||
813b8cdeecac43794166f3db9d3c5d2c441e0292f9ab7bd465ba136d6201e95d 82476 src/renderer/assets/itworx-wordmark.png
|
||||
5d6c87d51e55c9e976cf83ce242be0c28cf831d9c52082f02e745193500e6348 47992 src/renderer/dialogs.js
|
||||
1a577af2459715cf38d49d118da8c5f897a7ff1d3eb42ad41f121675eb871732 48389 src/renderer/dialogs.js
|
||||
977af9585074f0a404830c5a93de6939b4897d2eb98ba8ae75c3cf0023dea673 5782 src/renderer/events.js
|
||||
a84da5aecbb16ce7983dba1f6d6aab1bf47b2e9a87c2933fa1afb8123f7ef7d6 1497 src/renderer/index.html
|
||||
06180d9656dd254edfb6949c397f8e313954fc560ddcb22b3a35fce3c3e35655 21350 src/renderer/mock-bridge.js
|
||||
19603be9f471ba695c66f17fc027ab427b68ce146af80d52e3c94624a5ba1c35 27712 src/renderer/mock-deployment-bridge.js
|
||||
4b0a64610da0c446f15a43e4753b26f29de72e07793e2fa7b7322d4f07cf8050 27806 src/renderer/mock-deployment-bridge.js
|
||||
26065ffa2359cd27b9c9b5b9fb67bcad83ba0f118960c7c024e7e9392dbb16a3 20032 src/renderer/mock-repository-bridge.js
|
||||
94fa265c2fe9ca8d644f0ce9b620b6f85d9b25dca5802c4e9195b66dcbe80120 6522 src/renderer/operations.js
|
||||
45692591428575b518678a6b548c25d3de95f568541e5648b0f06f42c48b5bbf 77872 src/renderer/styles.css
|
||||
@@ -213,6 +216,7 @@ f8853dce6fdf360d5df2fbe2b6df3e5687630c807fee5ba8436679b34ec737ea 2436
|
||||
058aeaa5d9bfe377c7e322f213c7871ecc4151b5d08ef790992f4ee28d857658 743 START-FORGEFLOW-OVERLAY.ps1
|
||||
f5b0ea887fcdeadec78c1ad49b0ec7979723562f5c0b730703acb77a37281ee0 1009 tests/acceptance.test.mjs
|
||||
a4e5947204ff6878e601e32477bc85b53cd0153baf95a161c8935b6e5466c257 1155 tests/audit-service.test.mjs
|
||||
33bc892963e89b868235b959498308a456b1285057bda524ba7c1d5a9ee2159e 8763 tests/browser/forgeflow.spec.mjs
|
||||
454edeaccb2bd41043bc918d3e3a6127db14339031d6a1c1562ac855e90455d2 4318 tests/clone-target.test.mjs
|
||||
f1463326aee79842d265687ae628189ce54e92544600f2bd14073780287cfb14 2502 tests/configuration-backup.test.mjs
|
||||
b7e009fed4171d6dd6b4c3154ba1d3f7198e98f5b79b298687841fc8169447cd 9354 tests/deploy-key-lifecycle.test.mjs
|
||||
|
||||
Generated
+64
@@ -12,6 +12,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.39.5",
|
||||
"@playwright/test": "1.55.0",
|
||||
"c8": "10.1.3",
|
||||
"electron": "43.2.0",
|
||||
"electron-builder": "26.15.3",
|
||||
@@ -916,6 +917,22 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.55.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.0.tgz",
|
||||
"integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.55.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
@@ -2743,6 +2760,21 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -4000,6 +4032,38 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.55.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz",
|
||||
"integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.55.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.55.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz",
|
||||
"integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/plist": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
|
||||
|
||||
+6
-3
@@ -19,6 +19,8 @@
|
||||
"doctor": "node scripts/doctor.mjs",
|
||||
"acceptance": "node scripts/acceptance.mjs",
|
||||
"architecture:audit": "node scripts/architecture-audit.mjs",
|
||||
"test:browser": "playwright test",
|
||||
"test:browser:ci": "playwright test --reporter=line,html",
|
||||
"connections:check": "electron scripts/validate-installed-connections.cjs",
|
||||
"deployments:audit": "electron scripts/audit-installed-deployments.cjs",
|
||||
"release:binary": "electron scripts/publish-binary-release.cjs",
|
||||
@@ -28,6 +30,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "9.39.5",
|
||||
"@playwright/test": "1.55.0",
|
||||
"c8": "10.1.3",
|
||||
"electron": "43.2.0",
|
||||
"electron-builder": "26.15.3",
|
||||
@@ -101,9 +104,9 @@
|
||||
"docs/RELEASE_NOTES_0.9.5.md",
|
||||
"docs/RELEASE_NOTES_0.10.0.md",
|
||||
"docs/CURRENT_STATE.md",
|
||||
"docs/MUTATION_MODEL.md"
|
||||
,"docs/RELEASING.md"
|
||||
,"docs/ERROR_CODES.md"
|
||||
"docs/MUTATION_MODEL.md",
|
||||
"docs/RELEASING.md",
|
||||
"docs/ERROR_CODES.md"
|
||||
],
|
||||
"asarUnpack": [
|
||||
"scripts/apply-binary-update.ps1"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { defineConfig } from "@playwright/test";
|
||||
|
||||
const matrices = [
|
||||
["compact-dark-100", 1120, 720, "dark", 1, false],
|
||||
["desktop-light-125", 1440, 900, "light", 1.25, false],
|
||||
["wide-dark-150", 1920, 1080, "dark", 1.5, false],
|
||||
["compact-light-reduced", 1120, 720, "light", 1, true],
|
||||
["desktop-dark-reduced", 1440, 900, "dark", 1.25, true],
|
||||
["wide-light-100", 1920, 1080, "light", 1, false],
|
||||
];
|
||||
|
||||
export default defineConfig({
|
||||
testDir: "./tests/browser",
|
||||
outputDir: "artifacts/browser",
|
||||
timeout: 45_000,
|
||||
expect: { timeout: 7_000 },
|
||||
fullyParallel: false,
|
||||
workers: process.env.CI ? 2 : 3,
|
||||
reporter: [["line"], ["html", { outputFolder: "artifacts/browser-report", open: "never" }]],
|
||||
use: {
|
||||
baseURL: "http://127.0.0.1:4173",
|
||||
screenshot: "only-on-failure",
|
||||
trace: "retain-on-failure",
|
||||
video: "retain-on-failure",
|
||||
},
|
||||
webServer: {
|
||||
command: "node scripts/serve-demo.mjs",
|
||||
url: "http://127.0.0.1:4173",
|
||||
reuseExistingServer: !process.env.CI,
|
||||
timeout: 30_000,
|
||||
},
|
||||
projects: matrices.map(([name, width, height, theme, scale, reduced]) => ({
|
||||
name,
|
||||
metadata: { theme, scale, reduced },
|
||||
use: {
|
||||
viewport: { width, height },
|
||||
deviceScaleFactor: scale,
|
||||
colorScheme: theme,
|
||||
reducedMotion: reduced ? "reduce" : "no-preference",
|
||||
},
|
||||
})),
|
||||
});
|
||||
@@ -289,6 +289,11 @@ function enhanceRenderedUi() {
|
||||
if (!control.id) control.id = `forgeflow-field-${index}`;
|
||||
label.htmlFor = control.id;
|
||||
});
|
||||
document.querySelectorAll("input:not([aria-label]), select:not([aria-label]), textarea:not([aria-label])").forEach((control) => {
|
||||
if (control.labels?.length) return;
|
||||
const fallback = String(control.placeholder || control.name || control.id || "Form control").replaceAll("-", " ").trim();
|
||||
control.setAttribute("aria-label", fallback.charAt(0).toUpperCase() + fallback.slice(1));
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
@@ -316,4 +321,3 @@ function render() {
|
||||
document.querySelector("#palette-input")?.focus(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -466,7 +466,7 @@ function createMockDeploymentBridge(context) {
|
||||
checkedAt: iso(),
|
||||
score: 78,
|
||||
grade: "Good",
|
||||
policy: { id: "standard", label: "Standard", requiredScore: 70 },
|
||||
policy: state.gitValidatorPolicy || { id: "standard", label: "Standard", requiredScore: 70 },
|
||||
ready: true,
|
||||
commitSha: "8cbaf303aa3bb9b4023a7c89aa13fb70ce612847",
|
||||
trend: { newlyFound: ["working-tree"], resolved: ["editorconfig"], regressions: [], suppressions: [] },
|
||||
@@ -572,7 +572,8 @@ function createMockDeploymentBridge(context) {
|
||||
};
|
||||
},
|
||||
async gitValidatorSetPolicy(_fullName, policy) {
|
||||
return { id: policy.id, label: policy.id[0].toUpperCase() + policy.id.slice(1) };
|
||||
state.gitValidatorPolicy = { id: policy.id, label: policy.id[0].toUpperCase() + policy.id.slice(1) };
|
||||
return clone(state.gitValidatorPolicy);
|
||||
},
|
||||
async gitValidatorSuppress(_fullName, suppression) {
|
||||
return { ...suppression, id: `suppression-${Date.now()}`, createdAt: iso() };
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
|
||||
const consoleEntries = new WeakMap();
|
||||
const runtimeErrors = new WeakMap();
|
||||
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
const logs = [];
|
||||
const errors = [];
|
||||
consoleEntries.set(page, logs);
|
||||
runtimeErrors.set(page, errors);
|
||||
await page.emulateMedia({ colorScheme: testInfo.project.metadata.theme, reducedMotion: testInfo.project.metadata.reduced ? "reduce" : "no-preference" });
|
||||
page.on("console", (message) => logs.push({ type: message.type(), text: message.text() }));
|
||||
page.on("pageerror", (error) => errors.push({ name: error.name, message: error.message, stack: error.stack }));
|
||||
await page.goto("/");
|
||||
await expect(page.locator(".app-shell")).toBeVisible();
|
||||
const theme = testInfo.project.metadata.theme;
|
||||
await page.evaluate((requested) => {
|
||||
document.documentElement.dataset.theme = requested;
|
||||
localStorage.setItem("forgeflow-demo-theme", requested);
|
||||
}, theme);
|
||||
});
|
||||
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
const logs = consoleEntries.get(page) || [];
|
||||
const errors = runtimeErrors.get(page) || [];
|
||||
if (testInfo.status !== testInfo.expectedStatus) {
|
||||
const prefix = testInfo.outputPath("failure");
|
||||
await writeFile(`${prefix}-console.json`, JSON.stringify({ test: testInfo.title, project: testInfo.project.name, metadata: testInfo.project.metadata, logs, errors }, null, 2));
|
||||
await writeFile(`${prefix}-dom.html`, await page.content());
|
||||
await writeFile(`${prefix}-fixture.json`, JSON.stringify({ url: page.url(), viewport: page.viewportSize(), theme: await page.locator("html").getAttribute("data-theme") }, null, 2));
|
||||
}
|
||||
expect(errors, "page errors").toEqual([]);
|
||||
expect(logs.filter((entry) => entry.type === "error"), "console errors").toEqual([]);
|
||||
});
|
||||
|
||||
async function assertSurface(page) {
|
||||
const audit = await page.evaluate(() => {
|
||||
const interactive = [...document.querySelectorAll('button,input,select,textarea,a[href],[role="button"]')].filter((element) => {
|
||||
const style = getComputedStyle(element);
|
||||
return style.display !== "none" && style.visibility !== "hidden" && element.getBoundingClientRect().width > 0;
|
||||
});
|
||||
const unnamed = interactive.filter((element) => !String(element.getAttribute("aria-label") || element.getAttribute("title") || element.labels?.[0]?.textContent || element.textContent || element.value || "").trim());
|
||||
const outside = interactive.filter((element) => { const rect = element.getBoundingClientRect(); const fixed = ["fixed", "sticky"].includes(getComputedStyle(element).position) || Boolean(element.closest('[role="dialog"]')); return rect.left < -1 || rect.right > innerWidth + 1 || (fixed && (rect.top < -1 || rect.bottom > innerHeight + 1)); });
|
||||
const text = document.body.innerText;
|
||||
return {
|
||||
horizontalOverflow: document.documentElement.scrollWidth > document.documentElement.clientWidth + 1,
|
||||
unnamed: unnamed.map((element) => element.outerHTML.slice(0, 180)),
|
||||
outside: outside.map((element) => element.outerHTML.slice(0, 180)),
|
||||
badTokens: ["undefined", "[object Object]", "â", "Â", "Ã"].filter((token) => text.includes(token)),
|
||||
nullText: /(^|\s)null($|\s)/i.test(text),
|
||||
headings: [...document.querySelectorAll("h1,h2,h3")].map((heading) => Number(heading.tagName[1])),
|
||||
};
|
||||
});
|
||||
expect(audit.horizontalOverflow).toBe(false);
|
||||
expect(audit.unnamed).toEqual([]);
|
||||
expect(audit.outside).toEqual([]);
|
||||
expect(audit.badTokens).toEqual([]);
|
||||
expect(audit.nullText).toBe(false);
|
||||
expect(audit.headings.length).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
test("shell, overview, repositories and settings remain responsive and accessible", async ({ page }, testInfo) => {
|
||||
await assertSurface(page);
|
||||
for (const view of ["overview", "deployments", "settings"]) {
|
||||
await page.locator(`.nav-button[data-action="navigate"][data-view="${view}"]`).click();
|
||||
await expect(page.locator("main")).toBeVisible();
|
||||
await assertSurface(page);
|
||||
}
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", String(testInfo.project.metadata.theme));
|
||||
if (testInfo.project.metadata.reduced) {
|
||||
expect(await page.evaluate(() => matchMedia("(prefers-reduced-motion: reduce)").matches)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
test("repository changes, Git tools and Git Validator complete their primary flow", async ({ page }) => {
|
||||
await page.locator('[data-action="select-repo"]').first().click();
|
||||
await expect(page.locator('[data-action="repo-tab"]')).toHaveCount(6);
|
||||
for (const tab of ["changes", "history", "deployments", "gittools", "validator", "settings"]) {
|
||||
const control = page.locator(`[data-action="repo-tab"][data-tab="${tab}"]`);
|
||||
if (await control.count()) {
|
||||
await control.click();
|
||||
await expect(control).toHaveClass(/active/);
|
||||
await assertSurface(page);
|
||||
}
|
||||
}
|
||||
await page.locator('[data-action="repo-tab"][data-tab="validator"]').click();
|
||||
await expect(page.locator(".validator-score")).toBeVisible();
|
||||
await expect(page.locator("#validator-policy")).toBeVisible();
|
||||
await page.locator("#validator-policy").selectOption("production");
|
||||
await expect(page.locator(".validator-hero")).toContainText(/Production policy/i);
|
||||
await page.keyboard.press("Tab");
|
||||
await expect(page.locator(":focus")).toBeVisible();
|
||||
});
|
||||
|
||||
test("deployment inventory supports dense workloads without ambiguous blank cards", async ({ page }) => {
|
||||
await page.locator('.nav-button[data-action="navigate"][data-view="deployments"]').click();
|
||||
await expect(page.locator(".deploy-card, .server-inventory-panel .tool-row").first()).toBeVisible();
|
||||
const cards = page.locator(".deploy-card, .server-inventory-panel .tool-row");
|
||||
const count = await cards.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
for (let index = 0; index < Math.min(count, 25); index += 1) {
|
||||
await expect(cards.nth(index)).not.toHaveText(/^\s*$/);
|
||||
}
|
||||
await assertSurface(page);
|
||||
});
|
||||
|
||||
test("dialogs expose semantics, labels, keyboard close and focus restoration", async ({ page }) => {
|
||||
await page.locator('[data-action="select-repo"]').first().click();
|
||||
const trigger = page.locator('[data-action="edit-deployment-profile"], [data-action="add-deployment-profile"]').first();
|
||||
if (await trigger.count()) {
|
||||
await trigger.focus();
|
||||
await trigger.click();
|
||||
const dialog = page.locator('[role="dialog"]');
|
||||
await expect(dialog).toBeVisible();
|
||||
await expect(dialog.locator("button").first()).toBeVisible();
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(dialog).toHaveCount(0);
|
||||
}
|
||||
await assertSurface(page);
|
||||
});
|
||||
|
||||
test("onboarding and updater states remain usable without an existing configuration", async ({ page }) => {
|
||||
await page.evaluate(() => localStorage.setItem("forgeflow-demo-setup", "false"));
|
||||
await page.reload();
|
||||
await expect(page.locator(".setup-window")).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "Check this computer" })).toBeVisible();
|
||||
await page.locator('[data-action="setup-run-preflight"]').click();
|
||||
await expect(page.locator('[data-action="setup-continue"]')).toBeEnabled();
|
||||
await assertSurface(page);
|
||||
await page.evaluate(() => localStorage.setItem("forgeflow-demo-setup", "true"));
|
||||
await page.reload();
|
||||
await page.locator('.nav-button[data-view="settings"]').click();
|
||||
await page.locator('[data-action="check-updates"]').first().click();
|
||||
await expect(page.locator(".update-card")).toContainText(/ForgeFlow/i);
|
||||
await assertSurface(page);
|
||||
});
|
||||
|
||||
test("inventory, deployment safety and failure evidence dialogs are reviewable", async ({ page }) => {
|
||||
await page.locator('.nav-button[data-view="deployments"]').click();
|
||||
const reconciliation = page.locator('[data-action="plan-server-reconciliation"]').first();
|
||||
if (await reconciliation.count()) {
|
||||
await reconciliation.click();
|
||||
await expect(page.locator('[role="dialog"]')).toContainText(/reconciliation/i);
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
const keyLifecycle = page.locator('[data-action="manage-deploy-key"]').first();
|
||||
if (await keyLifecycle.count()) {
|
||||
await keyLifecycle.click();
|
||||
await expect(page.locator('[role="dialog"]')).toContainText(/Deploy key lifecycle/i);
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
const preflight = page.locator('[data-action="run-deployment-preflight"]').first();
|
||||
await preflight.click();
|
||||
await expect(page.locator('[role="dialog"]')).toContainText(/preflight/i);
|
||||
await page.keyboard.press("Escape");
|
||||
const failed = page.locator('[data-action="open-operation"]').last();
|
||||
if (await failed.count()) {
|
||||
await failed.click();
|
||||
await expect(page.locator('[role="dialog"]')).toContainText(/failed|failure|healthcheck/i);
|
||||
await page.keyboard.press("Escape");
|
||||
}
|
||||
await assertSurface(page);
|
||||
});
|
||||
Reference in New Issue
Block a user