QA profile: Hermes QA Specialist (read-only audit — no source code modified)
Date: 2026-08-28
Repo: D:\GitHub\adscalculator-xyz (branch main, up to date with origin/main)
Live: https://adscalculator.xyz
Git status at start: ✅ clean working tree (git status → "nothing to commit, working tree clean"). No uncommitted changes that could fake bugs.
Пълният QA одит на целия сайт засече 12 реални дефекта: 6 Critical, 1 High, 3 Medium, 2 Low. Най-сериозните проблеми са в самите калкулатори — 6 от 12 калкулатора са дефектни: при 3 (CPC/CPM/CTR) резултатът се изчислява правилно, но остава невидим за потребителя (CSS .hidden{display:none!important} побеждава inline стила); при други 3 (CPA/CPL/AOV) калкулаторът е напълно нефункционален (липсва JS логика). ROAS работи, но добавката "profit margin" е счупена. Блогът (50 поста) е здрав като съдържание, но нито един пост няма FAQPage schema (пропуснати rich results). Достъпността има 49 axe нарушения (10 critical). Gate статусът: 6/7 gates PASS; E2E FAIL (1 тест, но невъзпроизводим — asset-ът връща 200 live и локално → flaky/serve race, не реален дефект).
Full-site QA audit found 12 real defects: 6 Critical, 1 High, 3 Medium, 2 Low. The most severe are in the calculators themselves — 6 of 12 calculators are defective: 3 (CPC/CPM/CTR) compute the correct result but render it invisible to the user (.hidden{display:none!important} overrides the inline reveal); 3 (CPA/CPL/AOV) are completely non-functional (no JS handler wired up). ROAS works, but its "profit margin" add-on is broken. The blog (50 posts) is content-healthy but 0/50 posts have FAQPage structured schema. Accessibility has 49 axe violations (10 critical). Gate status: 6/7 gates PASS; E2E FAIL (1 test, but not reproducible — the asset returns HTTP 200 live and locally, so it is a flaky/serve-readiness issue, not a real defect).
| Gate | Command | Result | Detail |
|---|---|---|---|
| build | npm run build |
✅ PASS | 89s, dist/ produced, no errors |
| lint | eslint "js/**/*.js" "./*.js" |
✅ PASS | 36s, 0 errors |
| test | jest |
✅ PASS | 79/79 passed (3 suites) |
| typecheck | tsc --noEmit |
✅ PASS | 9s, 0 errors |
| schema | node scripts/validate-schemas.js |
✅ PASS | 0 JSON-LD errors |
| links | node scripts/check-links.js |
✅ PASS | 0 broken internal links |
| e2e | npx playwright test |
❌ FAIL | 9 passed, 1 failed (see Issue #9) |
| OVERALL | 6/7 PASS | E2E fails (flaky, non-reproducible) |
| Severity | Count |
|---|---|
| Critical | 6 |
| High | 1 |
| Medium | 3 |
| Low | 2 |
| Total | 12 |
| Category | Count |
|---|---|
| Functional | 7 |
| Visual | 3 |
| Accessibility | 1 |
| Content/SEO | 1 |
| Console | 0 |
dist/.C:\Users\Nikola\qa-audit-temp\qa-results.json and C:\Users\Nikola\qa-audit-temp\shots\*.png.totalCost + numClicks correctly computes CPC and writes it into #header-result-value (verified $2.00 for 1000/500), but #header-result-container stays display:none with the hidden class still applied → the user sees no result.style/sources-tables.css:127 → .hidden { display: none !important; }. The cpc branch in js/simple-main.js reveals the result with headerResultContainer.style.display = "flex" without removing the hidden class. The !important rule wins, so the container is never shown. (ROAS works only because its branch does classList.remove("hidden").)/cpc-calculator/, fill totalCost=1000, numClicks=500. DOM shows #header-result-value = "$2.00" but getComputedStyle(#header-result-container).display === "none", offsetParent === null, rectH === 0.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\cpc-desktop.png$5.00 for cost=500/impressions=100000 but result card remains hidden (display:none, hidden class retained).js/simple-main.js cpm branch sets style.display="flex" without classList.remove("hidden"); .hidden{display:none!important} hides it.cost=500, impressions=100000 → value "$5.00" present, container display:none.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\cpm-desktop.png5.00% for impressions=10000/clicks=500 but result card hidden.impressions=10000, clicks=500 → value "5.00%" present, container display:none.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\ctr-desktop.pngtotalCost + conversions (or clicking the on-page Calculate button) does nothing — #header-result-value stays at the placeholder $0.00 and the result container stays hidden. There is no JavaScript handler attached to this calculator.cpa-calculator.html loads pageScripts: [calculations.js, simple-main.js, utils.js]. js/simple-main.js only wires up branches for #roasResult, #cpc, #cpm, #ctr, #revenueResult — there is no cpa branch. The input element id="cpa" exists, but nothing reads it. No cpa-main.js / calculator-controller.js is loaded.totalCost=1000, conversions=10 → #header-result-value = "$0.00", #header-result-container display:none. Clicking the Calculate button also has no effect.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\cpa-desktop.pngtotalCost + leads produce no result ("$0.00", hidden). Missing cpl branch in js/simple-main.js; loads only calculations.js, simple-main.js, utils.js.totalCost=1000, leads=20 → "$0.00", hidden. Expected CPL = $50.00.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\cpl-desktop.pngtotalRevenue + orders produce no result ("$0.00", hidden). aov-calculator.html loads only calculations.js, simple-main.js, utils.js; there is no aov branch in simple-main.js and no dedicated AOV script.totalRevenue=5000, orders=100 → "$0.00", hidden. Expected AOV = $50.00.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\aov-desktop.pngShared root cause for #1–#6: (a)
.hidden { display:none !important }defeats any reveal that only setselement.style.displaywithout also callingclassList.remove("hidden"); (b)simple-main.jsis missingcpa/cpl/aovcalculator branches. Fix: addclassList.remove("hidden")(and add it back on reset) wherever results are revealed, and add the three missing three-variable branches tosimple-main.js.
#profitInputContainer stays display:none), so a real user cannot enter a margin to get break-even / net-profit. The math itself is correct (when the margin is set programmatically, break-even computes to "500.0% (5.00)").roas-calculator.html:55 → <div id="profitInputContainer" class="hidden mt-2">. The change handler in js/simple-main.js sets profitInputContainer.style.display = this.checked ? "block":"none" without removing the hidden class, and .hidden{display:none!important} hides it.page.check('#enableProfit') / dispatch change → getComputedStyle(#profitInputContainer).display stays "none"; #profitMargin offsetParent === null.MEDIA:C:\Users\Nikola\qa-audit-temp\shots\roas-desktop.pngBlogPosting/Article JSON-LD (inside @graph), but none include a FAQPage node. As a result the site cannot earn FAQ rich results in search.FAQPage schema even when an FAQ section is present. (scripts/validate-schemas.js passes because the existing JSON is valid — it does not assert FAQPage presence.)node audit over dist/blog/*/index.html: Posts WITH FAQPage schema: 0 / 50.FAQPage JSON-LD. Actual: 0/50.npx playwright test (baseURL http://localhost:8080)smoke-regression › cpm-benchmarks-2025: every image preload resolves to a real file. Manual re-verification shows the asset /cpm-benchmarks-2025-300.webp returns HTTP 200 on the live site AND on local serve.js (both confirmed via curl). The failure is therefore a flaky serve-readiness race / environment issue, not a broken asset.curl -I https://adscalculator.xyz/cpm-benchmarks-2025-300.webp → 200; curl -I http://localhost:8080/cpm-benchmarks-2025-300.webp → 200. The file exists at dist/cpm-benchmarks-2025-300.webp and dist/assets/....serve.js (the webServer reuseExistingServer + parallel test start may race); not a production defect.e2e/tests/*.ts_includes/related-calculators.html links ROAS, CPC, CPM, CTR, Campaign Funnel, ROI/LTV, E-commerce Profit, Email Marketing, Engagement Rate, Revenue, Marketing Mix + 3 blog posts — but omits CPA, CPL, AOV, the three broken calculators. (Coincidentally these are the broken ones; once fixed they should be cross-linked.)| # | Severity | Category | Title | URL | Status |
|---|---|---|---|---|---|
| 1 | Critical | Functional/Visual | CPC result computed but invisible | /cpc-calculator/ | Open |
| 2 | Critical | Functional/Visual | CPM result computed but invisible | /cpm-calculator/ | Open |
| 3 | Critical | Functional/Visual | CTR result computed but invisible | /ctr-calculator/ | Open |
| 4 | Critical | Functional | CPA calculator non-functional | /cpa-calculator/ | Open |
| 5 | Critical | Functional | CPL calculator non-functional | /cpl-calculator/ | Open |
| 6 | Critical | Functional | AOV calculator non-functional | /aov-calculator/ | Open |
| 7 | High | Functional | ROAS profit-margin add-on unusable | /roas-calculator/ | Open |
| 8 | Medium | Content/SEO | No FAQPage schema on 50/50 posts | /blog/* | Open |
| 9 | Medium | Test infra | E2E gate FAIL (flaky, non-reproducible) | e2e suite | Open (re-run) |
| 10 | Medium | Testing gap | 10 calculators have no E2E coverage | e2e suite | Open |
| 11 | Low | Content | CPA/CPL/AOV missing from related links | all calc pages | Open |
| 12 | Low | Console | No console errors site-wide (positive) | all pages | OK |
What was tested (with real evidence):
getComputedStyle/visibility probes.@graph), FAQ content (50/50 present), internal links (0 posts with zero), source links (0 posts without).What was NOT tested / limitations:
Blockers: None. The only environmental caveat is the E2E flaky failure (#9), which is test-harness timing, not a site defect.
Evidence artifacts: C:\Users\Nikola\qa-audit-temp\qa-results.json (full machine-readable results) and C:\Users\Nikola\qa-audit-temp\shots\*.png (desktop + mobile screenshots per page).