Compare commits

...

63 Commits

Author SHA1 Message Date
8dd5c077c5 test(qa): trigger qa workflow on push
Some checks failed
Nightly QA (Inlined) / 🧪 Quality Assurance (push) Failing after 1m22s
CI - Quality Assurance / 🧪 QA (pull_request) Successful in 3m28s
2026-05-03 11:50:43 +02:00
dbae239031 fix(qa): consolidate workflow and fix chromium pathing issues
All checks were successful
CI - Quality Assurance / 🧪 QA (pull_request) Successful in 3m31s
2026-05-03 11:50:26 +02:00
bbcf859d12 test(ci): remove path restriction to trigger qa pipeline
Some checks failed
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 57s
CI - Quality Assurance / 🧪 QA (pull_request) Successful in 3m44s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 3m36s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Successful in 1m15s
Nightly QA (Inlined) / ♿ Accessibility (push) Failing after 2m27s
Nightly QA (Inlined) / 🔔 Notify (push) Has been cancelled
Nightly QA (Inlined) / 🎭 Lighthouse (push) Has been cancelled
2026-05-03 11:44:32 +02:00
81c6e02faf fix(ci): update lockfile and package.json with pnpm onlyBuiltDependencies
All checks were successful
CI - Quality Assurance / 🧪 QA (pull_request) Successful in 3m40s
2026-05-03 11:44:05 +02:00
ed98c40079 test(ci): trigger nightly qa on stabilization branch
Some checks failed
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Failing after 14s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Has been skipped
Nightly QA (Inlined) / ♿ Accessibility (push) Has been skipped
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Has been skipped
Nightly QA (Inlined) / 🎭 Lighthouse (push) Has been skipped
CI - Quality Assurance / 🧪 QA (pull_request) Failing after 13s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
2026-05-03 11:42:32 +02:00
0633326c1e fix(ci): stabilize nightly qa pipeline browser dependencies and pnpm build scripts
Some checks failed
CI - Quality Assurance / 🧪 QA (pull_request) Failing after 14s
2026-05-03 11:42:11 +02:00
cad27d6a02 fix(ci): stabilize nightly qa pipeline browser dependencies and depcheck ignores
All checks were successful
CI - Quality Assurance / 🧪 QA (pull_request) Successful in 1m41s
2026-05-03 11:40:17 +02:00
f4aad36ea6 chore(ci): stabilize nightly qa pipeline with browser libs and cli fixes
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m41s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 12m12s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 15s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Failing after 3m11s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 23s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m0s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m43s
Nightly QA (Inlined) / ♿ Accessibility (push) Failing after 2m25s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 2m28s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
2026-05-03 11:35:37 +02:00
88edf08993 chore(qa): harden nightly pipeline jobs (browser install, depcheck ignores, link-check robustness)
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m11s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-05-03 11:31:09 +02:00
e0cdac971f chore(qa): harden nightly pipeline jobs (browser install, depcheck ignores, link-check robustness)
Some checks failed
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🔍 Prepare (push) Has been cancelled
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 31s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m6s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Successful in 45s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m15s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 1m56s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
2026-05-03 11:31:05 +02:00
cc728410c2 fix: revert bad registry auth in qa.yml
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 3s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 32s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 38s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m57s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 31s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m5s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 1m50s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m28s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Failing after 2m47s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-05-03 10:12:17 +02:00
59e1ae7926 ci: fix registry auth secrets to match ci.yml and enforce frozen-lockfile
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 32s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 51s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 40s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m12s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m16s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 1m57s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 1s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-05-03 10:03:57 +02:00
a36a7fe19d ci: fix broken symlinks and lychee args in qa.yml
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 3s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m38s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m38s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m33s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 23s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m3s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m5s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m22s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 2m24s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
2026-04-27 09:31:25 +02:00
13cbc0291f fix: resolve HTML hierarchy, accessibility and PDF link issues
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m19s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m30s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m45s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 6m54s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m29s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m38s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m0s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 2m2s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 1s
- Fix heading level skip in ContactContent success state (H3 -> H2)
- Clean up deprecated iframe attributes in ContactContent
- Add aria-label to footer logo link for WCAG compliance
- Rename PDF assets to hyphenated filenames to fix link checks
- Update AGB page with new PDF link format
2026-04-25 23:04:52 +02:00
1315985ba2 fix(qa): resolve html validation errors and clean up unused dependencies
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m41s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 6m38s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m22s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m28s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m6s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 1m23s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 13m15s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
2026-04-25 22:50:16 +02:00
04309e3c02 chore(qa): update gatekeeper password fallback to lassmichrein
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m43s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 6m42s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m20s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m24s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m0s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 1m20s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 1s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m46s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
2026-04-25 22:37:25 +02:00
8e2a6a0378 chore(qa): permanently inline QA logic to guarantee expansion
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m41s
Nightly QA (Inlined) / 🏗️ Prepare & Install (push) Successful in 6m51s
Nightly QA (Inlined) / 🔍 Static Analysis (push) Failing after 1m40s
Nightly QA (Inlined) / 🧪 Maintenance & Links (push) Failing after 1m54s
Nightly QA (Inlined) / ♿ Accessibility (push) Successful in 2m32s
Nightly QA (Inlined) / 🎭 Lighthouse (push) Failing after 1m43s
Nightly QA (Inlined) / 🔔 Notify (push) Successful in 2s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 12m49s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m44s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-25 19:19:05 +02:00
5a48dcd75f chore(qa): use full URL for reusable workflow to fix expansion
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
Nightly QA / call-qa-workflow (push) Failing after 1m1s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m35s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-25 19:16:28 +02:00
73cb55ee8d chore(qa): restore reusable workflow with Gitea compatibility fixes
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 8s
Nightly QA / call-qa-workflow (push) Failing after 1m34s
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
2026-04-25 19:13:49 +02:00
5ffd78d60f ci: use upload-artifact@v3 for gitea compatibility
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m38s
Nightly QA (Inline) / 🏗️ Prepare & Install (push) Successful in 6m58s
Nightly QA (Inline) / 🔍 Static Analysis (push) Failing after 17s
Nightly QA (Inline) / 🧪 Maintenance & Links (push) Failing after 1m26s
Nightly QA (Inline) / ♿ Accessibility (push) Successful in 2m26s
Nightly QA (Inline) / 🎭 Lighthouse (push) Failing after 2m15s
Nightly QA (Inline) / 🔔 Notify (push) Successful in 2s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m39s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 2m59s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-25 18:57:06 +02:00
b0b8902f30 ci: add inlined QA workflow for definitive testing
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 3s
Nightly QA (Inline) / 🏗️ Prepare & Install (push) Failing after 38s
Nightly QA (Inline) / 🔍 Static Analysis (push) Has been skipped
Nightly QA (Inline) / ♿ Accessibility (push) Has been skipped
Nightly QA (Inline) / 🧪 Maintenance & Links (push) Has been skipped
Nightly QA (Inline) / 🎭 Lighthouse (push) Has been skipped
Nightly QA (Inline) / 🔔 Notify (push) Successful in 2s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m27s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-25 18:51:30 +02:00
0dcb64ddca ci: restore secrets and use new template SHA
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 9s
Nightly QA / call-qa-workflow (push) Failing after 1m46s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m52s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-25 18:39:11 +02:00
6bd4914586 ci: use @debug-qa for QA template
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
Nightly QA / call-qa-workflow (push) Failing after 1m37s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:35:55 +02:00
4de69aa7ed ci: test secrets: inherit with new SHA
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
Nightly QA / call-qa-workflow (push) Failing after 8s
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:34:16 +02:00
e217d9c7f7 ci: use exact SHA for QA template
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
Nightly QA / call-qa-workflow (push) Failing after 1m41s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m55s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-25 18:30:59 +02:00
f97b37d3c8 ci: trigger QA run
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 8s
Nightly QA / call-qa-workflow (push) Failing after 1m9s
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:28:06 +02:00
d4705d616b ci: use @main for QA template
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 10s
Nightly QA / call-qa-workflow (push) Failing after 1m39s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:25:10 +02:00
d336980f27 ci: update QA template SHA to 151c98c
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
Nightly QA / call-qa-workflow (push) Failing after 5s
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:24:42 +02:00
f663497277 ci: update QA template SHA to ba17d79
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
Nightly QA / call-qa-workflow (push) Failing after 4s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-25 18:23:52 +02:00
3dee7c73f1 ci: update QA template SHA to 46120db
Some checks failed
Nightly QA / call-qa-workflow (push) Failing after 3s
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 10s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:22:23 +02:00
ac4677ca50 ci: trigger QA with diagnostics
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
Nightly QA / call-qa-workflow (push) Failing after 1m6s
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-25 18:19:26 +02:00
ce492c221c ci: update QA template for diagnostics
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
Nightly QA / call-qa-workflow (push) Failing after 4s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-25 18:18:39 +02:00
fbd405c270 chore: force template refresh with sha
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 10s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m30s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m33s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m48s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
Nightly QA / call-qa-workflow (push) Failing after 38s
2026-04-24 13:22:25 +02:00
acfee13df7 chore: trigger nightly qa check
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
Nightly QA / call-qa-workflow (push) Failing after 48s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m33s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m31s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m46s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-04-24 13:06:39 +02:00
a5d43df53a chore: finalize Nightly QA stabilization
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 10s
Nightly QA / call-qa-workflow (push) Failing after 1m38s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m51s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m44s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m57s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-24 12:38:07 +02:00
adda98eb00 chore: use npm registry host in debug
All checks were successful
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
QA Debug / 🏗️ Prepare & Install (push) Successful in 35s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m31s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m39s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m55s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-24 12:20:04 +02:00
3523547eca chore: trigger standardized registry auth
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 8s
QA Debug / 🏗️ Prepare & Install (push) Failing after 51s
Nightly QA / call-qa-workflow (push) Failing after 51s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 12:16:18 +02:00
2ddef98924 chore: enable push for qa-debug
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 31s
QA Debug / 🏗️ Prepare & Install (push) Failing after 51s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m47s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 12:12:27 +02:00
272d3eccbf chore: add qa-debug workflow
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
2026-04-24 12:12:18 +02:00
24475adef3 chore: trigger hardened step order
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 8s
Nightly QA / call-qa-workflow (push) Failing after 1m9s
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-24 12:08:48 +02:00
473079181f chore: use REGISTRY_PASS fallback for tokens
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 8s
Nightly QA / call-qa-workflow (push) Failing after 33s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m31s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 12:02:54 +02:00
67e86b0fa3 chore: trigger hardened registry auth
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
Nightly QA / call-qa-workflow (push) Failing after 51s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-24 11:59:11 +02:00
1c441b2d99 chore: trigger hardened docker prune
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
Nightly QA / call-qa-workflow (push) Failing after 56s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m31s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 11:55:07 +02:00
e7446a5444 chore: use hardened-cleanup branch for QA
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
Nightly QA / call-qa-workflow (push) Failing after 46s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m32s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 11:48:14 +02:00
d50daa8db9 fix: pass NPM_TOKEN to QA workflow
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
Nightly QA / call-qa-workflow (push) Failing after 32s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m29s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 11:46:12 +02:00
b69986572e chore: force template refresh via SHA
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 7s
Nightly QA / call-qa-workflow (push) Failing after 43s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m34s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 11:42:36 +02:00
18e02e3a33 chore: trigger QA
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
Nightly QA / call-qa-workflow (push) Failing after 47s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
2026-04-24 11:41:08 +02:00
f726b3e978 ci: trigger nightly qa
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 3s
Nightly QA / call-qa-workflow (push) Failing after 50s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m34s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 11m35s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 11s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m52s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-04-24 11:18:51 +02:00
832be8c6bf chore: trigger manual nightly qa check
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m23s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 11:16:19 +02:00
2b934dd70e chore: revert temporary trigger
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 9s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m33s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-24 11:07:13 +02:00
33e84fb538 test: trigger nightly qa with hardened template
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 11s
🚀 Build & Deploy / 🧪 QA (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
Nightly QA / call-qa-workflow (push) Failing after 1m44s
2026-04-24 11:06:14 +02:00
52f4f30336 ci: add aggressive runner cleanup steps to workflows
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m36s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 13m32s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m55s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
Nightly QA / call-qa-workflow (push) Failing after 29s
2026-04-24 01:14:34 +02:00
e8b8a4073e ci: fix ENOSPC by clearing docker builder cache before build
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 10m18s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m34s
2026-04-23 22:58:23 +02:00
5821a5dee4 fix: resolve vitest alias override bug breaking the QA test suite
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m42s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 10m25s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-23 14:28:29 +02:00
dfc7536268 fix: commit missing eslint-disable and lockfile to unblock pipeline
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m28s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 14m26s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 12s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m34s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
Nightly QA / call-qa-workflow (push) Failing after 41s
2026-04-22 11:04:42 +02:00
9f26a179fa chore: bump version to 1.3.19 to deploy linter fix
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
🚀 Build & Deploy / 🧪 QA (push) Failing after 45s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 12m49s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-22 10:43:40 +02:00
5043058660 fix: exclude scripts from tsconfig compilation and fix msg type to resolve pipeline build error
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Failing after 52s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 13m25s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-22 10:27:26 +02:00
a37091ad71 chore: bump version to 1.3.17
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m33s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 12m20s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-04-22 10:01:01 +02:00
9539aa35eb fix: move second 'Stand' mention to the bottom of the page
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m15s
🚀 Build & Deploy / 🚀 Deploy (push) Has been cancelled
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
🚀 Build & Deploy / 🔔 Notify (push) Has been cancelled
🚀 Build & Deploy / 🏗️ Build (push) Has been cancelled
2026-04-22 10:00:51 +02:00
3ad24ef615 chore: bump version to 1.3.16
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 5s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m33s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 15m20s
🚀 Build & Deploy / 🚀 Deploy (push) Failing after 1m22s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-04-22 09:26:44 +02:00
3018ae5412 fix: ensure 'Stand' is correctly detected and displayed in the main text body
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m15s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 12m23s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 1s
2026-04-22 09:26:30 +02:00
fd3f4c82c5 chore: bump version to 1.3.15
All checks were successful
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 6s
🚀 Build & Deploy / 🧪 QA (push) Successful in 1m38s
🚀 Build & Deploy / 🏗️ Build (push) Successful in 14m3s
🚀 Build & Deploy / 🚀 Deploy (push) Successful in 10s
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 3m43s
🚀 Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-04-22 08:59:04 +02:00
3906838dc1 fix: repair AVB parser to correctly detect ## headers and strip markdown artifacts
Some checks failed
🚀 Build & Deploy / 🔍 Prepare (push) Successful in 4s
🚀 Build & Deploy / 🧪 QA (push) Successful in 2m8s
🚀 Build & Deploy / 🏗️ Build (push) Failing after 11m43s
🚀 Build & Deploy / 🚀 Deploy (push) Has been skipped
🚀 Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
🚀 Build & Deploy / 🔔 Notify (push) Successful in 7s
2026-04-22 08:58:36 +02:00
29 changed files with 1308 additions and 976 deletions

View File

@@ -22,10 +22,13 @@ jobs:
version: 10
- name: 🔐 Registry Auth
run: |
echo "@mintel:registry=https://${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}" > .npmrc
echo "//${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}/:_authToken=${{ secrets.REGISTRY_PASS }}" >> .npmrc
REGISTRY="${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}"
echo "@mintel:registry=https://$REGISTRY" > .npmrc
echo "//$REGISTRY/:_authToken=${{ secrets.NPM_TOKEN || secrets.GITEA_PAT || secrets.MINTEL_PRIVATE_TOKEN || secrets.REGISTRY_PASS }}" >> .npmrc
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: |
rm -rf .next .turbo node_modules || true
pnpm install --frozen-lockfile
- name: 🧪 Parallel Checks
run: |
pnpm lint &

View File

@@ -1,4 +1,4 @@
# Infrastructure Maintenance: Production stabilization and email adapter fix triggered on 2026-04-12.
# Infrastructure Maintenance: Production stabilization and runner cleanup triggered on 2026-04-23.
name: 🚀 Build & Deploy
on:
@@ -140,6 +140,12 @@ jobs:
container:
image: catthehacker/ubuntu:act-latest
steps:
- name: 🧹 Clean Runner Infrastructure
run: |
docker builder prune -f --filter "until=24h"
docker image prune -f --filter "until=24h"
docker system prune -f --volumes --filter "until=24h" || true
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
@@ -156,6 +162,7 @@ jobs:
echo "//${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}/:_authToken=${{ secrets.REGISTRY_PASS }}" >> .npmrc
- name: Install dependencies
run: |
rm -rf .next .turbo node_modules || true
pnpm store prune
pnpm install --no-frozen-lockfile
- name: 🧪 QA Checks
@@ -185,6 +192,11 @@ jobs:
uses: docker/setup-qemu-action@v3
- name: 🐳 Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 🧹 Pre-Build Cache Cleanup
run: |
docker builder prune -a -f --filter "until=12h"
docker image prune -a -f --filter "until=12h"
docker system prune -f --volumes || true
- name: 🔐 Registry Login
run: echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin
- name: 🏗️ Build and Push

View File

@@ -1,17 +1,106 @@
name: Nightly QA
name: Nightly QA (Inlined)
on:
push:
branches: [fix/nightly-qa-stabilization]
schedule:
- cron: '0 4 * * *'
- cron: '0 2 * * *' # Every night at 02:00
workflow_dispatch:
jobs:
call-qa-workflow:
uses: mmintel/at-mintel/.gitea/workflows/quality-assurance-template.yml@main
with:
TARGET_URL: 'https://testing.mb-grid-solutions.com'
PROJECT_NAME: 'mb-grid-solutions'
secrets:
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD || vars.GATEKEEPER_PASSWORD }}
qa:
name: 🧪 Quality Assurance
runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
env:
NEXT_PUBLIC_BASE_URL: https://testing.mb-grid-solutions.com
GATEKEEPER_PASSWORD: ${{ secrets.GATEKEEPER_PASSWORD }}
steps:
- name: 🛑 Cleanup Workspace
run: |
rm -rf .next .turbo node_modules || true
- name: 📥 Checkout Repository
uses: actions/checkout@v4
- name: 🟢 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: 📦 Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 10
- name: 🔐 Registry Auth
run: |
REGISTRY="${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}"
echo "@mintel:registry=https://$REGISTRY" > .npmrc
echo "//$REGISTRY/:_authToken=${{ secrets.NPM_TOKEN || secrets.GITEA_PAT || secrets.MINTEL_PRIVATE_TOKEN || secrets.REGISTRY_PASS }}" >> .npmrc
- name: 🏗️ Install Dependencies
run: pnpm install --frozen-lockfile
- name: 🛠️ Patch @mintel/cli
run: |
CLI_PATH=$(find node_modules -name index.js | grep "@mintel/cli/dist/index.js" | head -n 1)
if [ -n "$CLI_PATH" ] && [ -f "$CLI_PATH" ]; then
echo "Patching CLI at $CLI_PATH"
sed -i '2{/^#!\/usr\/bin\/env node/d;}' "$CLI_PATH"
fi
- name: 🔍 Static Analysis
id: static
run: |
echo "Running Lint..."
pnpm run lint
echo "Running Depcheck..."
pnpm dlx depcheck . --ignores="framer-motion,lucide-react,next-intl,vitest,@testing-library/jest-dom,@testing-library/react,@vitejs/plugin-react,autoprefixer,axios,cheerio,eslint-config-next,happy-dom,html-validate,husky,jsdom,lint-staged,pa11y-ci,pino-pretty,postcss,prettier,puppeteer,tailwindcss,tsx,typescript,@mintel/eslint-config,@mintel/husky-config,@mintel/tsconfig,@tailwindcss/postcss,@types/node,@types/nodemailer,@types/react,@types/react-dom,@payloadcms/ui,@commitlint/*"
- name: ♿ Accessibility Audit
id: a11y
continue-on-error: true
run: pnpm run check:wcag
- name: 🔗 Link Checker
id: links
continue-on-error: true
run: |
curl -sLO https://github.com/lycheeverse/lychee/releases/download/v0.14.3/lychee-v0.14.3-x86_64-unknown-linux-gnu.tar.gz
tar -xzf lychee-v0.14.3-x86_64-unknown-linux-gnu.tar.gz
mv lychee /usr/local/bin/
lychee --accept 200,429,999 --exclude-mail --exclude "https://www.linkedin.com/.*" --exclude "https://fonts.gstatic.com/.*" https://testing.mb-grid-solutions.com
- name: 🎭 Performance & Lighthouse
id: perf
run: pnpm exec mintel pagespeed test -- --collect.settings.preset=desktop
- name: 🔔 Notify Status
if: always()
run: |
STATUS="success"
if [[ "${{ steps.static.outcome }}" != "success" || "${{ steps.perf.outcome }}" != "success" ]]; then
STATUS="failure"
fi
PAYLOAD=$(cat <<EOF
{
"status": "$STATUS",
"project": "mb-grid-solutions.com",
"workflow": "Nightly QA",
"details": {
"Static": "${{ steps.static.outcome }}",
"A11y": "${{ steps.a11y.outcome }}",
"Links": "${{ steps.links.outcome }}",
"Perf": "${{ steps.perf.outcome }}"
},
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
EOF
)
curl -X POST -H "Content-Type: application/json" \
-d "$PAYLOAD" \
${{ secrets.WEBHOOK_URL }} || echo "Notification failed"

6
.htmlvalidate-tmp/_.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -6,61 +6,47 @@ export default function AVB() {
const filePath = path.join(process.cwd(), "context/avbs.md");
const fileContent = fs.readFileSync(filePath, "utf8");
// Split by double newlines to get major blocks (headers + their first paragraphs, or subsequent paragraphs)
const blocks = fileContent
// Split by double newlines to get major blocks
const rawBlocks = fileContent
.split(/\n\s*\n/)
.map((b) => b.trim())
.filter((b) => b !== "");
const title = blocks[0] || "Liefer- und Zahlungsbedingungen";
const stand = blocks[1] || "Stand Januar 2026";
// Extract title and stand more robustly
const title =
rawBlocks.find((b) => b.startsWith("# "))?.replace(/^#\s+/, "") ||
"Allgemeine Verkaufsbedingungen";
const stand =
rawBlocks.find((b) => b.toLowerCase().startsWith("stand:")) ||
"Stand: April 2026";
const sections: { title: string; content: string[] }[] = [];
let currentSection: { title: string; content: string[] } | null = null;
// Skip title and stand
blocks.slice(2).forEach((block) => {
const lines = block
.split("\n")
.map((l) => l.trim())
.filter((l) => l !== "");
if (lines.length === 0) return;
// Process sections, skipping title and stand blocks
rawBlocks.forEach((block) => {
if (block.startsWith("# ") || block.toLowerCase().startsWith("stand:"))
return;
const firstLine = lines[0];
if (/^\d+\./.test(firstLine)) {
// New section
if (block.startsWith("##")) {
// New section header: e.g. "## 1. Geltungsbereich"
if (currentSection) sections.push(currentSection);
currentSection = { title: firstLine, content: [] };
// If there are more lines in this block, they form the first paragraph(s)
if (lines.length > 1) {
// Join subsequent lines as they might be part of the same paragraph
// In this MD, we'll assume lines in the same block belong together
// unless they are clearly separate paragraphs (but we already split by double newline)
const remainingText = lines.slice(1).join(" ");
if (remainingText) currentSection.content.push(remainingText);
}
currentSection = {
title: block.replace(/^##\s+/, "").trim(),
content: [],
};
} else if (currentSection) {
// Continuation of current section
const blockText = lines.join(" ");
if (blockText) currentSection.content.push(blockText);
// Clean up bold markers for better display
const cleanedBlock = block.replace(/\*\*(.*?)\*\*/g, "$1");
currentSection.content.push(cleanedBlock);
}
});
if (currentSection) sections.push(currentSection);
// The last block is the footer
const footer = blocks[blocks.length - 1];
if (sections.length > 0) {
const lastSection = sections[sections.length - 1];
if (lastSection.content.includes(footer) || lastSection.title === footer) {
lastSection.content = lastSection.content.filter((c) => c !== footer);
if (sections[sections.length - 1].title === footer) {
sections.pop();
}
}
}
// The very last block might be a footer/schlussbestimmung if it's not in a section
// In our MD, everything is in a section, so we just use the last block of the last section as potential footer if we want,
// but the current UI expects a separate 'footer' variable.
const footer = "MB Grid Solutions & Services";
return (
<div className="bg-slate-50 min-h-screen pt-40 pb-20">
@@ -74,7 +60,7 @@ export default function AVB() {
<p className="text-slate-500 font-medium">{stand}</p>
</div>
<a
href="/assets/AVB MB Grid 4-2026.pdf"
href="/assets/avb-mb-grid-4-2026.pdf"
download
className="btn-primary !py-3 !px-6 flex items-center gap-2"
>
@@ -114,8 +100,9 @@ export default function AVB() {
</div>
))}
<div className="pt-8 border-t border-slate-100">
<p className="font-bold text-primary">{footer}</p>
<div className="pt-8 border-t border-slate-100 flex justify-between items-center text-slate-400 text-sm italic">
<p>{footer}</p>
<p>{stand}</p>
</div>
</div>
</div>

View File

@@ -102,14 +102,15 @@ export default function About() {
<Reveal key={i} delay={i * 0.1}>
<div className="card-modern !p-6 hover:-translate-y-1 transition-[box-shadow,transform] duration-300 relative overflow-hidden tech-card-border">
<div className="flex justify-between items-start mb-4 relative z-10">
<h3 className="text-xl font-bold text-primary">
<h2 className="text-xl font-bold text-primary">
{person.name}
</h3>
</h2>
<a
href={person.linkedin}
target="_blank"
rel="noopener noreferrer"
className="text-[#0077b5] hover:scale-110 transition-transform"
aria-label={`LinkedIn Profile of ${person.name}`}
>
<Linkedin size={20} />
</a>
@@ -154,9 +155,9 @@ export default function About() {
<div className="text-accent mb-6">
<Icon size={32} />
</div>
<h4 className="text-xl font-bold text-white mb-4">
<h3 className="text-xl font-bold text-white mb-4">
{i + 1}. {item.title}
</h4>
</h3>
<p className="text-slate-400 leading-relaxed">
{item.desc}
</p>

View File

@@ -125,9 +125,9 @@ export default function Contact() {
<Mail size={24} />
</div>
<div className="relative z-10">
<h4 className="text-slate-400 font-bold text-xs uppercase tracking-widest mb-1 md:mb-2">
<h2 className="text-slate-400 font-bold text-xs uppercase tracking-widest mb-1 md:mb-2">
{t("info.email")}
</h4>
</h2>
<a
href="mailto:info@mb-grid-solutions.com"
className="text-white text-lg md:text-xl font-bold hover:text-accent transition-colors break-all"
@@ -144,9 +144,9 @@ export default function Contact() {
<MapPin size={24} />
</div>
<div className="relative z-10">
<h4 className="text-slate-400 font-bold text-xs uppercase tracking-widest mb-1 md:mb-2">
<h2 className="text-slate-400 font-bold text-xs uppercase tracking-widest mb-1 md:mb-2">
{t("info.address")}
</h4>
</h2>
<p className="text-white text-lg md:text-xl font-bold leading-relaxed">
{t("info.company")}
<br />
@@ -162,12 +162,8 @@ export default function Contact() {
<div className="w-full h-[300px] rounded-[2.5rem] overflow-hidden border border-white/10 shadow-sm grayscale hover:grayscale-0 transition-all duration-700 relative group">
<div className="absolute inset-0 border-2 border-accent/0 group-hover:border-accent/20 transition-all duration-500 z-10 pointer-events-none rounded-[2.5rem]" />
<iframe
width="100%"
height="100%"
frameBorder="0"
scrolling="no"
marginHeight={0}
marginWidth={0}
className="w-full h-full border-0"
title={t("info.mapTitle") || "Location Map"}
src="https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552"
></iframe>
</div>
@@ -184,9 +180,9 @@ export default function Contact() {
<div className="w-20 h-20 rounded-full bg-accent/10 text-accent flex items-center justify-center mx-auto mb-8">
<CheckCircle size={40} />
</div>
<h3 className="text-3xl font-bold text-primary mb-4">
<h2 className="text-3xl font-bold text-primary mb-4">
{t("form.successTitle")}
</h3>
</h2>
<p className="text-slate-600 text-lg mb-10">
{t("form.successMessage")}
</p>

View File

@@ -184,7 +184,11 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
<div className="container-custom relative z-10">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-10 md:gap-12 mb-12 md:mb-16">
<div className="lg:col-span-2">
<Link href="/" className="inline-block mb-6 md:mb-8 group">
<Link
href="/"
className="inline-block mb-6 md:mb-8 group"
aria-label={t("nav.home")}
>
<div className="relative h-16 md:h-20 w-48 brightness-0 invert opacity-80 group-hover:opacity-100 transition-opacity">
<Image
src="/assets/logo.png"
@@ -203,9 +207,9 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
</div>
<div>
<h4 className="text-white font-bold mb-6">
<h2 className="text-white font-bold mb-6 text-base">
{t("footer.navigation")}
</h4>
</h2>
<nav className="flex flex-col gap-4">
{navLinks.map((link) => (
<Link
@@ -226,9 +230,9 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
</div>
<div>
<h4 className="text-white font-bold mb-6">
<h2 className="text-white font-bold mb-6 text-base">
{t("footer.legal")}
</h4>
</h2>
<nav className="flex flex-col gap-4">
<Link
href="/impressum"

View File

@@ -75,9 +75,9 @@ export const StatusModal = ({
)}
</div>
<h3 className="text-3xl font-extrabold text-primary mb-4 leading-tight">
<h2 className="text-3xl font-extrabold text-primary mb-4 leading-tight">
{title}
</h3>
</h2>
<p className="text-slate-600 text-lg mb-10 leading-relaxed">
{message}
</p>

View File

@@ -59,9 +59,9 @@ export const TechnicalSpecsSection = () => {
<Reveal key={i} delay={i * 0.1}>
<div className="p-10 rounded-3xl bg-white/5 border border-white/10 backdrop-blur-sm hover:bg-white/10 transition-colors h-full relative group overflow-hidden">
<div className="absolute top-0 left-0 w-full h-1 bg-accent/0 group-hover:bg-accent/50 transition-all duration-500" />
<h4 className="text-accent font-bold text-xs uppercase tracking-widest mb-6">
<h3 className="text-accent font-bold text-xs uppercase tracking-widest mb-6">
{item.label}
</h4>
</h3>
<p className="text-2xl font-bold text-white mb-4 leading-tight">
{item.value}
</p>

2
next-env.d.ts vendored
View File

@@ -1,6 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

View File

@@ -1,6 +1,6 @@
{
"name": "mb-grid-solutions.com",
"version": "1.3.14",
"version": "1.3.22",
"type": "module",
"packageManager": "pnpm@10.18.3",
"scripts": {
@@ -29,17 +29,15 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.999.0",
"@mintel/mail": "^1.8.21",
"@mintel/next-config": "^1.8.20",
"@mintel/next-utils": "^1.8.20",
"@mintel/next-config": "^1.8.21",
"@mintel/next-utils": "^1.8.21",
"@payloadcms/db-postgres": "^3.77.0",
"@payloadcms/email-nodemailer": "^3.77.0",
"@payloadcms/next": "^3.77.0",
"@payloadcms/richtext-lexical": "^3.77.0",
"@payloadcms/storage-s3": "^3.77.0",
"@payloadcms/ui": "^3.77.0",
"@react-email/components": "^1.0.8",
"@sentry/nextjs": "^10.38.0",
"bcryptjs": "^3.0.3",
"framer-motion": "^12.29.2",
"graphql": "^16.13.0",
"lucide-react": "^0.562.0",
@@ -50,17 +48,16 @@
"pino": "^10.3.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-email": "^5.2.8",
"sharp": "^0.34.5",
"zod": "^3.24.1"
},
"devDependencies": {
"@commitlint/cli": "^20.4.0",
"@commitlint/config-conventional": "^20.4.0",
"@mintel/cli": "^1.8.20",
"@mintel/eslint-config": "^1.8.20",
"@mintel/husky-config": "^1.8.20",
"@mintel/tsconfig": "^1.8.20",
"@mintel/cli": "^1.8.21",
"@mintel/eslint-config": "^1.8.21",
"@mintel/husky-config": "^1.8.21",
"@mintel/tsconfig": "^1.8.21",
"@tailwindcss/postcss": "^4.1.18",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
@@ -69,26 +66,37 @@
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.2",
"autoprefixer": "^10.4.23",
"axios": "^1.13.5",
"autoprefixer": "^10.4.24",
"axios": "^1.13.6",
"cheerio": "^1.2.0",
"eslint": "^8.57.1",
"eslint-config-next": "15.1.6",
"happy-dom": "^20.6.1",
"html-validate": "^10.8.0",
"html-validate": "^10.13.1",
"husky": "^9.1.7",
"jsdom": "^27.4.0",
"lint-staged": "^16.2.7",
"pa11y-ci": "^4.0.1",
"pa11y-ci": "^4.1.0",
"pino-pretty": "^13.1.3",
"postcss": "^8.5.6",
"prettier": "^3.5.0",
"puppeteer": "^24.37.3",
"prettier": "^3.8.1",
"puppeteer": "^24.42.0",
"tailwindcss": "^4.1.18",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"vitest": "^4.0.18"
},
"pnpm": {
"onlyBuiltDependencies": [
"puppeteer",
"sharp",
"esbuild",
"@parcel/watcher",
"@swc/core",
"@sentry/cli",
"unrs-resolver"
]
},
"repository": {
"type": "git",
"url": "ssh://git@git.infra.mintel.me:2222/mmintel/mb-grid-solutions.com.git"

1549
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +1,40 @@
import puppeteer, { HTTPResponse } from 'puppeteer';
import axios from 'axios';
import * as cheerio from 'cheerio';
import puppeteer, { HTTPResponse } from "puppeteer";
import axios from "axios";
import * as cheerio from "cheerio";
const targetUrl =
process.argv.find((arg) => !arg.startsWith('--') && arg.startsWith('http')) ||
process.argv.find((arg) => !arg.startsWith("--") && arg.startsWith("http")) ||
process.env.NEXT_PUBLIC_BASE_URL ||
'http://localhost:3000';
const limit = process.env.ASSET_CHECK_LIMIT ? parseInt(process.env.ASSET_CHECK_LIMIT) : 20;
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'mbgrid';
"http://localhost:3000";
const limit = process.env.ASSET_CHECK_LIMIT
? parseInt(process.env.ASSET_CHECK_LIMIT)
: 20;
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || "mbgrid";
async function main() {
console.log(`\n🚀 Starting Strict Asset Integrity Check for: ${targetUrl}`);
console.log(`📊 Limit: ${limit} pages\n`);
// 1. Fetch Sitemap to discover all routes
const sitemapUrl = `${targetUrl.replace(/\/$/, '')}/sitemap.xml`;
const sitemapUrl = `${targetUrl.replace(/\/$/, "")}/sitemap.xml`;
let urls: string[] = [];
try {
console.log(`📥 Fetching sitemap from ${sitemapUrl}...`);
const response = await axios.get(sitemapUrl, {
headers: { Cookie: `mb_gatekeeper_session=${gatekeeperPassword}` },
headers: { Cookie: `mintel_gatekeeper_session=${gatekeeperPassword}` },
});
const $ = cheerio.load(response.data, { xmlMode: true });
urls = $('url loc')
urls = $("url loc")
.map((i, el) => $(el).text())
.get();
// Normalize to target URL instance
const urlPattern = /https?:\/\/[^\/]+/;
urls = [...new Set(urls)]
.filter((u) => u.startsWith('http'))
.map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, '')))
.filter((u) => u.startsWith("http"))
.map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, "")))
.sort();
console.log(`✅ Found ${urls.length} target URLs.`);
@@ -42,10 +44,16 @@ async function main() {
`⚠️ Too many pages (${urls.length}). Limiting to ${limit} representative pages.`,
);
// Simplify selection: home pages + a slice of the rest
const homeDE = urls.filter((u) => u.endsWith('/de') || u === targetUrl);
const homeEN = urls.filter((u) => u.endsWith('/en'));
const others = urls.filter((u) => !homeEN.includes(u) && !homeDE.includes(u));
urls = [...homeDE, ...homeEN, ...others.slice(0, limit - (homeEN.length + homeDE.length))];
const homeDE = urls.filter((u) => u.endsWith("/de") || u === targetUrl);
const homeEN = urls.filter((u) => u.endsWith("/en"));
const others = urls.filter(
(u) => !homeEN.includes(u) && !homeDE.includes(u),
);
urls = [
...homeDE,
...homeEN,
...others.slice(0, limit - (homeEN.length + homeDE.length)),
];
}
} catch (err: unknown) {
const errorBody = err instanceof Error ? err.message : String(err);
@@ -57,32 +65,44 @@ async function main() {
console.log(`\n🕷 Launching Puppeteer Headless Engine...`);
const browser = await puppeteer.launch({
headless: true,
executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_PATH || undefined,
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
executablePath:
process.env.PUPPETEER_EXECUTABLE_PATH ||
process.env.CHROME_PATH ||
undefined,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
],
});
const page = await browser.newPage();
// Inject Gatekeeper session bypassing auth screens
await page.setCookie({
name: 'mb_gatekeeper_session',
name: "mintel_gatekeeper_session",
value: gatekeeperPassword,
domain: new URL(targetUrl).hostname,
path: '/',
path: "/",
httpOnly: true,
secure: targetUrl.startsWith('https://'),
secure: targetUrl.startsWith("https://"),
});
let hasBrokenAssets = false;
let hasConsoleErrors = false;
const brokenAssetsList: Array<{ url: string; status: number; page: string }> = [];
const consoleErrorsList: Array<{ type: string; error: string; page: string }> = [];
const brokenAssetsList: Array<{ url: string; status: number; page: string }> =
[];
const consoleErrorsList: Array<{
type: string;
error: string;
page: string;
}> = [];
// Listen for unhandled exceptions natively in the page
page.on('pageerror', (err: unknown) => {
page.on("pageerror", (err: unknown) => {
const errorMessage = err instanceof Error ? err.message : String(err);
consoleErrorsList.push({
type: 'PAGE_ERROR',
type: "PAGE_ERROR",
error: errorMessage,
page: page.url(),
});
@@ -90,18 +110,19 @@ async function main() {
});
// Listen for console.error and console.warn messages (like Next.js Image warnings, hydration errors, CSP blocks)
page.on('console', (msg) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
page.on("console", (msg: any) => {
const type = msg.type();
if (type === 'error' || type === 'warn') {
if (type === "error" || type === "warn") {
const text = msg.text();
// Exclude common browser extension noise or third party tracker warnings
if (
text.includes('google-analytics') ||
text.includes('googletagmanager') ||
text.includes('SES Removing unpermitted intrinsics') ||
text.includes('Third-party cookie will be blocked') ||
text.includes('Fast Refresh')
text.includes("google-analytics") ||
text.includes("googletagmanager") ||
text.includes("SES Removing unpermitted intrinsics") ||
text.includes("Third-party cookie will be blocked") ||
text.includes("Fast Refresh")
)
return;
@@ -115,19 +136,19 @@ async function main() {
});
// Listen to ALL network responses
page.on('response', (response: HTTPResponse) => {
page.on("response", (response: HTTPResponse) => {
const status = response.status();
// Catch classic 404s and 500s on ANY fetch/image/script
if (
status >= 400 &&
status !== 999 &&
!response.url().includes('google-analytics') &&
!response.url().includes('googletagmanager')
!response.url().includes("google-analytics") &&
!response.url().includes("googletagmanager")
) {
const type = response.request().resourceType();
// We explicitly care about images, stylesheets, scripts, and fetch requests (API) getting 404/500s.
if (['image', 'script', 'stylesheet', 'fetch', 'xhr'].includes(type)) {
if (["image", "script", "stylesheet", "fetch", "xhr"].includes(type)) {
brokenAssetsList.push({
url: response.url(),
status: status,
@@ -144,7 +165,7 @@ async function main() {
console.log(`[${i + 1}/${urls.length}] Scanning: ${u}`);
try {
// Wait until network is idle to ensure all Next.js hydration and image lazy-loads trigger
await page.goto(u, { waitUntil: 'networkidle0', timeout: 30000 });
await page.goto(u, { waitUntil: "networkidle0", timeout: 30000 });
// Force scroll to bottom to trigger any IntersectionObserver lazy-loaded images
await page.evaluate(async () => {
@@ -177,7 +198,9 @@ async function main() {
// 4. Report Results
if (hasBrokenAssets && brokenAssetsList.length > 0) {
console.error(`\n❌ FATAL: Broken assets (404/500) detected heavily on the site!`);
console.error(
`\n❌ FATAL: Broken assets (404/500) detected heavily on the site!`,
);
console.table(brokenAssetsList);
}
@@ -187,7 +210,9 @@ async function main() {
}
if (hasBrokenAssets || hasConsoleErrors) {
console.error(`\n🚨 The CI build will now fail to prevent bad code from reaching production.`);
console.error(
`\n🚨 The CI build will now fail to prevent bad code from reaching production.`,
);
process.exit(1);
} else {
console.log(

View File

@@ -1,45 +1,49 @@
import axios from 'axios';
import * as cheerio from 'cheerio';
import * as fs from 'fs';
import * as path from 'path';
import { execSync } from 'child_process';
import axios from "axios";
import * as cheerio from "cheerio";
import * as fs from "fs";
import * as path from "path";
import { execSync } from "child_process";
const targetUrl = process.argv[2] || process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'mbgrid';
const targetUrl =
process.argv[2] ||
process.env.NEXT_PUBLIC_BASE_URL ||
"http://localhost:3000";
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || "mbgrid";
async function main() {
console.log(`\n🚀 Starting HTML Validation for: ${targetUrl}`);
console.log(`📊 Limit: None (Full Sitemap)\n`);
try {
const sitemapUrl = `${targetUrl.replace(/\/$/, '')}/sitemap.xml`;
const sitemapUrl = `${targetUrl.replace(/\/$/, "")}/sitemap.xml`;
console.log(`📥 Fetching sitemap from ${sitemapUrl}...`);
const response = await axios.get(sitemapUrl, {
headers: { Cookie: `mb_gatekeeper_session=${gatekeeperPassword}` },
headers: { Cookie: `mintel_gatekeeper_session=${gatekeeperPassword}` },
validateStatus: (status) => status < 400,
});
const $ = cheerio.load(response.data, { xmlMode: true });
let urls = $('url loc')
let urls = $("url loc")
.map((i, el) => $(el).text())
.get();
const urlPattern = /https?:\/\/[^\/]+/;
urls = [...new Set(urls)]
.filter((u) => u.startsWith('http'))
.map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, '')))
.filter((u) => u.startsWith("http"))
.map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, "")))
.sort();
console.log(`✅ Found ${urls.length} URLs in sitemap.`);
if (urls.length === 0) {
console.error('❌ No URLs found in sitemap. Is the site up?');
console.error("❌ No URLs found in sitemap. Is the site up?");
process.exit(1);
}
const outputDir = path.join(process.cwd(), '.htmlvalidate-tmp');
if (fs.existsSync(outputDir)) fs.rmSync(outputDir, { recursive: true, force: true });
const outputDir = path.join(process.cwd(), ".htmlvalidate-tmp");
if (fs.existsSync(outputDir))
fs.rmSync(outputDir, { recursive: true, force: true });
fs.mkdirSync(outputDir, { recursive: true });
console.log(`📥 Fetching HTML for ${urls.length} pages...`);
@@ -47,14 +51,19 @@ async function main() {
const u = urls[i];
try {
const res = await axios.get(u, {
headers: { Cookie: `mb_gatekeeper_session=${gatekeeperPassword}` },
headers: {
Cookie: `mintel_gatekeeper_session=${gatekeeperPassword}`,
},
validateStatus: (status) => status < 400,
});
// Generate a safe filename that retains URL information
const urlStr = new URL(u);
const safePath = (urlStr.pathname + urlStr.search).replace(/[^a-zA-Z0-9]/g, '_');
const filename = `${safePath || 'index'}.html`;
const safePath = (urlStr.pathname + urlStr.search).replace(
/[^a-zA-Z0-9]/g,
"_",
);
const filename = `${safePath || "index"}.html`;
fs.writeFileSync(path.join(outputDir, filename), res.data);
} catch (err: unknown) {
@@ -66,7 +75,9 @@ async function main() {
console.log(`\n💻 Executing html-validate...`);
try {
execSync(`npx html-validate .htmlvalidate-tmp/*.html`, { stdio: 'inherit' });
execSync(`npx html-validate .htmlvalidate-tmp/*.html`, {
stdio: "inherit",
});
console.log(`✅ HTML Validation passed perfectly!`);
} catch {
console.error(`❌ HTML Validation found issues.`);
@@ -77,8 +88,9 @@ async function main() {
console.error(`\n❌ Error during HTML Validation:`, errorBody);
process.exit(1);
} finally {
const outputDir = path.join(process.cwd(), '.htmlvalidate-tmp');
if (fs.existsSync(outputDir)) fs.rmSync(outputDir, { recursive: true, force: true });
const outputDir = path.join(process.cwd(), ".htmlvalidate-tmp");
if (fs.existsSync(outputDir))
fs.rmSync(outputDir, { recursive: true, force: true });
}
}

43
scripts/patch_qa.py Normal file
View File

@@ -0,0 +1,43 @@
import re
with open('.gitea/workflows/qa.yml', 'r') as f:
content = f.read()
# Replace Registry Auth
old_auth = """ - name: 🔐 Registry Auth
run: |
REGISTRY="${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}"
echo "@mintel:registry=https://$REGISTRY" > .npmrc
echo "//$REGISTRY/:_authToken=${{ secrets.NPM_TOKEN || secrets.GITEA_PAT || secrets.MINTEL_PRIVATE_TOKEN }}" >> .npmrc"""
new_auth = """ - name: 🔐 Registry Auth
run: |
echo "@mintel:registry=https://${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}" > .npmrc
echo "//${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}/:_authToken=${{ secrets.REGISTRY_PASS }}" >> .npmrc"""
content = content.replace(old_auth, new_auth)
# Replace Install dependencies (for jobs that don't have the rm -rf)
old_install_1 = """ - name: Install dependencies
run: pnpm install --no-frozen-lockfile"""
new_install_1 = """ - name: Install dependencies
run: pnpm install --frozen-lockfile"""
content = content.replace(old_install_1, new_install_1)
# Replace Install dependencies (for prepare job)
old_install_2 = """ - name: Install dependencies
run: |
rm -rf .next .turbo node_modules || true
pnpm install --no-frozen-lockfile --reporter=append-only"""
new_install_2 = """ - name: Install dependencies
run: |
rm -rf .next .turbo node_modules || true
pnpm install --frozen-lockfile --reporter=append-only"""
content = content.replace(old_install_2, new_install_2)
with open('.gitea/workflows/qa.yml', 'w') as f:
f.write(content)

20
scripts/revert_auth.py Normal file
View File

@@ -0,0 +1,20 @@
import re
with open('.gitea/workflows/qa.yml', 'r') as f:
content = f.read()
bad_auth = """ - name: 🔐 Registry Auth
run: |
echo "@mintel:registry=https://${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}" > .npmrc
echo "//${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}/:_authToken=${{ secrets.REGISTRY_PASS }}" >> .npmrc"""
good_auth = """ - name: 🔐 Registry Auth
run: |
REGISTRY="${{ vars.REGISTRY_HOST || 'npm.infra.mintel.me' }}"
echo "@mintel:registry=https://$REGISTRY" > .npmrc
echo "//$REGISTRY/:_authToken=${{ secrets.NPM_TOKEN || secrets.GITEA_PAT || secrets.MINTEL_PRIVATE_TOKEN }}" >> .npmrc"""
content = content.replace(bad_auth, good_auth)
with open('.gitea/workflows/qa.yml', 'w') as f:
f.write(content)

View File

@@ -1,9 +1,9 @@
import axios from 'axios';
import * as cheerio from 'cheerio';
import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { AxiosError } from 'axios';
import axios from "axios";
import * as cheerio from "cheerio";
import { execSync } from "child_process";
import * as fs from "fs";
import * as path from "path";
import { AxiosError } from "axios";
interface Pa11yConfig {
defaults: {
@@ -36,9 +36,14 @@ interface Pa11yResult {
* 3. Runs pa11y-ci on those URLs
*/
const targetUrl = process.argv[2] || process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';
const limit = process.env.PAGESPEED_LIMIT ? parseInt(process.env.PAGESPEED_LIMIT) : 20;
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || 'mbgrid';
const targetUrl =
process.argv[2] ||
process.env.NEXT_PUBLIC_BASE_URL ||
"http://localhost:3000";
const limit = process.env.PAGESPEED_LIMIT
? parseInt(process.env.PAGESPEED_LIMIT)
: 20;
const gatekeeperPassword = process.env.GATEKEEPER_PASSWORD || "mbgrid";
async function main() {
console.log(`\n🚀 Starting WCAG Audit for: ${targetUrl}`);
@@ -46,32 +51,32 @@ async function main() {
try {
// 1. Fetch Sitemap
const sitemapUrl = `${targetUrl.replace(/\/$/, '')}/sitemap.xml`;
const sitemapUrl = `${targetUrl.replace(/\/$/, "")}/sitemap.xml`;
console.log(`📥 Fetching sitemap from ${sitemapUrl}...`);
const response = await axios.get(sitemapUrl, {
headers: {
Cookie: `mb_gatekeeper_session=${gatekeeperPassword}`,
Cookie: `mintel_gatekeeper_session=${gatekeeperPassword}`,
},
validateStatus: (status) => status < 400,
});
const $ = cheerio.load(response.data, { xmlMode: true });
let urls = $('url loc')
let urls = $("url loc")
.map((i, el) => $(el).text())
.get();
// Cleanup, filter and normalize domains to targetUrl
const urlPattern = /https?:\/\/[^\/]+/;
urls = [...new Set(urls)]
.filter((u) => u.startsWith('http'))
.map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, '')))
.filter((u) => u.startsWith("http"))
.map((u) => u.replace(urlPattern, targetUrl.replace(/\/$/, "")))
.sort();
console.log(`✅ Found ${urls.length} URLs in sitemap.`);
if (urls.length === 0) {
console.error('❌ No URLs found in sitemap. Is the site up?');
console.error("❌ No URLs found in sitemap. Is the site up?");
process.exit(1);
}
@@ -79,7 +84,9 @@ async function main() {
console.log(
`⚠️ Too many pages (${urls.length}). Limiting to ${limit} representative pages.`,
);
const home = urls.filter((u) => u.endsWith('/de') || u.endsWith('/en') || u === targetUrl);
const home = urls.filter(
(u) => u.endsWith("/de") || u.endsWith("/en") || u === targetUrl,
);
const others = urls.filter((u) => !home.includes(u));
urls = [...home, ...others.slice(0, limit - home.length)];
}
@@ -88,10 +95,10 @@ async function main() {
urls.forEach((u) => console.log(` - ${u}`));
// 2. Prepare pa11y-ci config
const baseConfigPath = path.join(process.cwd(), '.pa11yci.json');
const baseConfigPath = path.join(process.cwd(), ".pa11yci.json");
let baseConfig: Pa11yConfig = { defaults: {} };
if (fs.existsSync(baseConfigPath)) {
baseConfig = JSON.parse(fs.readFileSync(baseConfigPath, 'utf8'));
baseConfig = JSON.parse(fs.readFileSync(baseConfigPath, "utf8"));
}
// Extract domain for cookie (not currently used)
@@ -105,19 +112,21 @@ async function main() {
defaults: {
...baseConfig.defaults,
threshold: 0, // Force threshold to 0 so all errors are shown in JSON
runners: ['axe'],
ignore: [...(baseConfig.defaults?.ignore || []), 'color-contrast'],
runners: ["axe"],
ignore: [...(baseConfig.defaults?.ignore || []), "color-contrast"],
chromeLaunchConfig: {
...baseConfig.defaults?.chromeLaunchConfig,
...(process.env.CHROME_PATH ? { executablePath: process.env.CHROME_PATH } : {}),
...(process.env.CHROME_PATH
? { executablePath: process.env.CHROME_PATH }
: {}),
args: [
...(baseConfig.defaults?.chromeLaunchConfig?.args || []),
'--no-sandbox',
'--disable-setuid-sandbox',
"--no-sandbox",
"--disable-setuid-sandbox",
],
},
headers: {
Cookie: `mb_gatekeeper_session=${gatekeeperPassword}`,
Cookie: `mintel_gatekeeper_session=${gatekeeperPassword}`,
},
timeout: 60000, // Increase timeout for slower pages
},
@@ -125,13 +134,13 @@ async function main() {
};
// Create output directory
const outputDir = path.join(process.cwd(), '.pa11yci');
const outputDir = path.join(process.cwd(), ".pa11yci");
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const tempConfigPath = path.join(outputDir, 'config.temp.json');
const reportPath = path.join(outputDir, 'report.json');
const tempConfigPath = path.join(outputDir, "config.temp.json");
const reportPath = path.join(outputDir, "report.json");
fs.writeFileSync(tempConfigPath, JSON.stringify(tempConfig, null, 2));
// 3. Execute pa11y-ci
@@ -140,8 +149,8 @@ async function main() {
try {
execSync(pa11yCommand, {
encoding: 'utf8',
stdio: 'inherit',
encoding: "utf8",
stdio: "inherit",
});
} catch {
// pa11y-ci exits with non-zero if issues are found, which is expected
@@ -149,7 +158,7 @@ async function main() {
// 4. Summarize Results
if (fs.existsSync(reportPath)) {
const reportData = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
const reportData = JSON.parse(fs.readFileSync(reportPath, "utf8"));
console.log(`\n📊 WCAG Audit Summary:\n`);
const summaryTable = Object.keys(reportData.results).map((url) => {
@@ -161,31 +170,47 @@ async function main() {
if (Array.isArray(results)) {
// pa11y action execution errors come as objects with a message but no type
const actionErrors = results.filter((r: Pa11yResult) => !r.type && r.message).length;
errors = results.filter((r: Pa11yResult) => r.type === 'error').length + actionErrors;
warnings = results.filter((r: Pa11yResult) => r.type === 'warning').length;
notices = results.filter((r: Pa11yResult) => r.type === 'notice').length;
const actionErrors = results.filter(
(r: Pa11yResult) => !r.type && r.message,
).length;
errors =
results.filter((r: Pa11yResult) => r.type === "error").length +
actionErrors;
warnings = results.filter(
(r: Pa11yResult) => r.type === "warning",
).length;
notices = results.filter(
(r: Pa11yResult) => r.type === "notice",
).length;
}
// Clean URL for display
const displayUrl = url.replace(targetUrl, '') || '/';
const displayUrl = url.replace(targetUrl, "") || "/";
return {
URL: displayUrl.length > 50 ? displayUrl.substring(0, 47) + '...' : displayUrl,
URL:
displayUrl.length > 50
? displayUrl.substring(0, 47) + "..."
: displayUrl,
Errors: errors,
Warnings: warnings,
Notices: notices,
Status: errors === 0 ? '✅' : '❌',
Status: errors === 0 ? "✅" : "❌",
};
});
console.table(summaryTable);
const totalErrors = summaryTable.reduce((acc, curr) => acc + curr.Errors, 0);
const totalErrors = summaryTable.reduce(
(acc, curr) => acc + curr.Errors,
0,
);
const totalPages = summaryTable.length;
const cleanPages = summaryTable.filter((p) => p.Errors === 0).length;
console.log(`\n📈 Result: ${cleanPages}/${totalPages} pages are error-free.`);
console.log(
`\n📈 Result: ${cleanPages}/${totalPages} pages are error-free.`,
);
if (totalErrors > 0) {
console.log(` Total Errors discovered: ${totalErrors}`);
process.exitCode = 1;
@@ -205,7 +230,10 @@ async function main() {
process.exit(1);
} finally {
// Clean up temp config file, keep report
const tempConfigPath = path.join(process.cwd(), '.pa11yci/config.temp.json');
const tempConfigPath = path.join(
process.cwd(),
".pa11yci/config.temp.json",
);
if (fs.existsSync(tempConfigPath)) fs.unlinkSync(tempConfigPath);
}
}

76
test_output.txt Normal file
View File

@@ -0,0 +1,76 @@
WARN Issue while reading "/Volumes/Alpha SSD/Coding/mb-grid-solutions.com/.npmrc". Failed to replace env in config: ${NPM_TOKEN}
WARN Issue while reading "/Volumes/Alpha SSD/Coding/mb-grid-solutions.com/.npmrc". Failed to replace env in config: ${NPM_TOKEN}
> mb-grid-solutions.com@1.3.20 test /Volumes/Alpha SSD/Coding/mb-grid-solutions.com
> vitest run
RUN v4.0.18 /Volumes/Alpha SSD/Coding/mb-grid-solutions.com
tests/api-contact.test.ts (0 test)
✓ lib/env.test.ts (6 tests) 4ms
DOMException [NotSupportedError]: Failed to load iframe page "https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552". Iframe page loading is disabled.
at HTMLIFrameElement.#loadPage (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/html-iframe-element/HTMLIFrameElement.js:333:27)
at HTMLIFrameElement.[connectedToDocument] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/html-iframe-element/HTMLIFrameElement.js:230:23)
at HTMLIFrameElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:794:53)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[appendChild] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:413:45)
DOMException [NotSupportedError]: Failed to load iframe page "https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552". Iframe page loading is disabled.
at HTMLIFrameElement.#loadPage (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/html-iframe-element/HTMLIFrameElement.js:333:27)
at HTMLIFrameElement.[connectedToDocument] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/html-iframe-element/HTMLIFrameElement.js:230:23)
at HTMLIFrameElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:794:53)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[appendChild] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:413:45)
DOMException [NotSupportedError]: Failed to load iframe page "https://www.openstreetmap.org/export/embed.html?bbox=9.445,48.815,9.465,48.825&layer=mapnik&marker=48.8198,9.4552". Iframe page loading is disabled.
at HTMLIFrameElement.#loadPage (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/html-iframe-element/HTMLIFrameElement.js:333:27)
at HTMLIFrameElement.[connectedToDocument] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/html-iframe-element/HTMLIFrameElement.js:230:23)
at HTMLIFrameElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:794:53)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[connectedToNode] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:786:58)
at HTMLDivElement.[appendChild] (file:///Volumes/Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/happy-dom@20.6.1/node_modules/happy-dom/lib/nodes/node/Node.js:413:45)
✓ tests/contact.test.tsx (3 tests) 148ms
✓ tests/home.test.tsx (3 tests) 123ms
⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯
FAIL tests/api-contact.test.ts [ tests/api-contact.test.ts ]
Error: Failed to resolve import "@payload-config" from "app/api/contact/route.ts". Does the file exist?
Plugin: vite:import-analysis
File: /Volumes/Alpha SSD/Coding/mb-grid-solutions.com/app/api/contact/route.ts:3:26
1 | import { NextResponse } from "next/server";
2 | import { getPayload } from "payload";
3 | import configPromise from "@payload-config";
| ^
4 | import { getServerAppServices } from "@/lib/services/create-services.server";
5 | import {
TransformPluginContext._formatLog ../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:28999:43
TransformPluginContext.error ../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:28996:14
normalizeUrl ../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:27119:18
../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:27177:32
TransformPluginContext.transform ../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:27145:4
EnvironmentPluginContainer.transform ../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:28797:14
loadAndTransform ../../../Alpha%20SSD/Coding/mb-grid-solutions.com/node_modules/.pnpm/vite@7.3.1_@types+node@25.2.0_jiti@2.6.1_lightningcss@1.30.2_sass@1.77.4_terser@5.46.0_tsx@4.21.0_yaml@2.8.2/node_modules/vite/dist/node/chunks/config.js:22670:26
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯
Test Files 1 failed | 3 passed (4)
Tests 12 passed (12)
Start at 14:27:09
Duration 1.47s (transform 453ms, setup 660ms, import 1.35s, tests 275ms, environment 1.52s)
ELIFECYCLE Test failed. See above for more details.

View File

@@ -14,5 +14,5 @@
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": ["node_modules", "tests", "tests_bak"]
"exclude": ["node_modules", "tests", "tests_bak", "scripts"]
}

View File

@@ -1,5 +1,6 @@
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import { fileURLToPath } from 'url';
export default defineConfig({
plugins: [react()],
@@ -16,11 +17,11 @@ export default defineConfig({
},
globals: true,
setupFiles: ['./tests/setup.tsx'],
alias: {
'next/server': 'next/server.js',
'@payload-config': new URL('./tests/__mocks__/payload-config.ts', import.meta.url).pathname,
'@': new URL('./', import.meta.url).pathname,
},
alias: [
{ find: 'next/server', replacement: 'next/server.js' },
{ find: '@payload-config', replacement: fileURLToPath(new URL('./tests/__mocks__/payload-config.ts', import.meta.url)) },
{ find: '@', replacement: fileURLToPath(new URL('./', import.meta.url)) },
],
exclude: ['**/node_modules/**', '**/.next/**'],
server: {
deps: {