- renderDpia: matrix wrappet i .card med h2 - renderSecurity: ros-layout (matrix+radar), small-multiples-section, top-risks som <ol> i .card - renderRos: speil renderSecurity (5x5) + summary-grid for top-risks+recommendation - renderFindingsBlock: fjern .report-meta-band-aid, bruk findings-section + findings__items--standalone - Legg til .ros-layout, .summary-grid, .findings-section, .small-multiples-section i lokal CSS - Fjern .top-risks fra defensive layout-block - test-playground-v3.sh: bytt .findings__list → .findings__items i DS-klasse-asserts - Style-blokk: 182 → 188 linjer (mål ≤195 nådd) Refs V1.14.0-AUDIT.local.md sub-batch B + helper-section.
575 lines
24 KiB
Bash
Executable file
575 lines
24 KiB
Bash
Executable file
#!/bin/bash
|
|
# test-playground-v3.sh — Static checks for the Playground v3 HTML
|
|
#
|
|
# Bash 3.2-kompatibel. Verifiserer struktur, vendored CSS, surfaces, command-katalog,
|
|
# parser/renderer-routing, eksponerte globals, og design-system CSS-klassebruk.
|
|
# JS-kjøring testes separat i test-parsers-v3.mjs (eller .sh-shim) — denne fila
|
|
# leser kun rå tekst med grep/awk/wc.
|
|
|
|
set -euo pipefail
|
|
|
|
PLUGIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
HTML_FILE="$PLUGIN_ROOT/playground/ms-ai-architect-playground.html"
|
|
|
|
# Inkluder felles helpers (init_suite, pass, fail, warn, print_summary,
|
|
# assert_min_lines, assert_matches_pattern). Disse aktiverer set -euo pipefail —
|
|
# wrapper hver assert i logikk som returnerer 0 selv ved miss for å unngå tidlig
|
|
# exit i denne lange suiten.
|
|
# shellcheck disable=SC1091
|
|
source "$PLUGIN_ROOT/tests/lib/e2e-helpers.sh"
|
|
|
|
init_suite "Playground v3 — Static structure"
|
|
|
|
# -------------------------------------------------------
|
|
# 1. Fil eksisterer + minimum størrelse
|
|
# -------------------------------------------------------
|
|
if [ ! -f "$HTML_FILE" ]; then
|
|
fail "HTML-fila finnes ikke: $HTML_FILE"
|
|
print_summary
|
|
exit 1
|
|
fi
|
|
pass "HTML-fila eksisterer: playground/ms-ai-architect-playground.html"
|
|
|
|
assert_min_lines "$HTML_FILE" 1500 "v3 HTML er >= 1500 linjer"
|
|
|
|
# -------------------------------------------------------
|
|
# 2. Grunnleggende HTML-struktur
|
|
# -------------------------------------------------------
|
|
for marker in '<!DOCTYPE html>' '<html ' '</html>' '<head>' '</head>' '<body>' '</body>'; do
|
|
if grep -qF "$marker" "$HTML_FILE"; then
|
|
pass "HTML-marker til stede: $marker"
|
|
else
|
|
fail "HTML-marker mangler: $marker"
|
|
fi
|
|
done
|
|
|
|
# data-theme-attribute (default-verdi i markup)
|
|
if grep -q 'data-theme="dark"' "$HTML_FILE" || grep -q "data-theme='dark'" "$HTML_FILE"; then
|
|
pass "data-theme=\"dark\" satt på <html> som default"
|
|
else
|
|
fail "data-theme=\"dark\" mangler på <html>"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 3. Vendored CSS-koblinger (7 stk i bestemt rekkefølge)
|
|
# -------------------------------------------------------
|
|
EXPECTED_CSS="fonts.css tokens.css base.css components.css components-tier2.css components-tier3.css components-tier3-supplement.css"
|
|
prev_line=0
|
|
order_ok=1
|
|
for css in $EXPECTED_CSS; do
|
|
line=$(grep -n "vendor/playground-design-system/$css" "$HTML_FILE" | head -n 1 | cut -d: -f1 || echo "")
|
|
if [ -z "$line" ]; then
|
|
fail "CSS-link mangler: vendor/playground-design-system/$css"
|
|
order_ok=0
|
|
else
|
|
pass "CSS-link til stede: $css (linje $line)"
|
|
if [ "$prev_line" -gt 0 ] && [ "$line" -lt "$prev_line" ]; then
|
|
order_ok=0
|
|
fi
|
|
prev_line=$line
|
|
fi
|
|
done
|
|
if [ "$order_ok" -eq 1 ]; then
|
|
pass "Vendored CSS-link-tags i forventet rekkefølge"
|
|
else
|
|
fail "Vendored CSS-link-tags er ikke i forventet rekkefølge"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 4. Theme bootstrap (Step 13)
|
|
# -------------------------------------------------------
|
|
assert_matches_pattern "$HTML_FILE" "ms-ai-architect-theme" \
|
|
"localStorage-nøkkel ms-ai-architect-theme referert (Step 13)"
|
|
assert_matches_pattern "$HTML_FILE" "data-action=\"toggle-theme\"" \
|
|
"data-action=\"toggle-theme\" til stede"
|
|
assert_matches_pattern "$HTML_FILE" "class=\"theme-toggle\"" \
|
|
".theme-toggle-knapp wired til topbar"
|
|
|
|
# -------------------------------------------------------
|
|
# 5. Ingen eksterne JS-script-references (file:// must work)
|
|
# -------------------------------------------------------
|
|
if grep -qE '<script[^>]+src=["'\'']https?://' "$HTML_FILE"; then
|
|
fail "Ekstern <script src=\"http(s)://\"> funnet — bryter file://-kompatibilitet"
|
|
elif grep -qE '<script[^>]+src=["'\'']//' "$HTML_FILE"; then
|
|
fail "Protocol-relative <script src=\"//\"> funnet — bryter file://-kompatibilitet"
|
|
else
|
|
pass "Ingen eksterne <script src=...>-koblinger (file://-trygg)"
|
|
fi
|
|
|
|
# Ingen eksterne stylesheet-koblinger
|
|
if grep -qE '<link[^>]+href=["'\'']https?://' "$HTML_FILE"; then
|
|
fail "Ekstern <link href=\"http(s)://\"> funnet"
|
|
elif grep -qE '<link[^>]+href=["'\'']//' "$HTML_FILE"; then
|
|
fail "Protocol-relative <link href=\"//\"> funnet"
|
|
else
|
|
pass "Ingen eksterne <link href=...> stylesheet-koblinger"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 6. Surfaces (4 stk)
|
|
# -------------------------------------------------------
|
|
for surface in onboarding home catalog project; do
|
|
if grep -qE "data-surface=[\"']${surface}[\"']" "$HTML_FILE"; then
|
|
pass "Surface registrert: $surface"
|
|
else
|
|
fail "Surface mangler: $surface"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 7. STATE_KEY-konstant (schema-versjon)
|
|
# -------------------------------------------------------
|
|
if grep -qE "STATE_KEY *= *['\"]ms-ai-architect-state-v1['\"]" "$HTML_FILE"; then
|
|
pass "STATE_KEY = 'ms-ai-architect-state-v1' satt"
|
|
else
|
|
fail "STATE_KEY-konstant mangler eller har feil verdi"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 8. Eksponerte window.__-globals
|
|
# -------------------------------------------------------
|
|
EXPECTED_GLOBALS="__store __CATALOG __PARSERS __RENDERERS __buildCommand __buildEnvelope __handlePasteImport __STATE_KEY"
|
|
for g in $EXPECTED_GLOBALS; do
|
|
if grep -qE "window\.${g} *=" "$HTML_FILE"; then
|
|
pass "Global eksponert: window.$g"
|
|
else
|
|
fail "Global mangler: window.$g"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 9. Alle 24 command-IDer fra commands/*.md referert i HTML
|
|
# -------------------------------------------------------
|
|
cmd_count=0
|
|
for f in "$PLUGIN_ROOT"/commands/*.md; do
|
|
[ -f "$f" ] || continue
|
|
cmd_count=$((cmd_count + 1))
|
|
cmd_id=$(basename "$f" .md)
|
|
if grep -qE "id: *['\"]${cmd_id}['\"]" "$HTML_FILE" || grep -q "/architect:${cmd_id}" "$HTML_FILE"; then
|
|
pass "Command-ID '${cmd_id}' referert i v3 HTML"
|
|
else
|
|
fail "Command-ID '${cmd_id}' mangler i v3 HTML"
|
|
fi
|
|
done
|
|
if [ "$cmd_count" -eq 25 ]; then
|
|
pass "25 command-filer funnet i commands/ (forventet 25)"
|
|
else
|
|
fail "Forventet 25 command-filer, fant $cmd_count"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 10. 14 parser-funksjoner (kanonisk archetype-routing)
|
|
# -------------------------------------------------------
|
|
PARSERS="parseAiAct parseRequirements parseTextDocument parseFria parseConformityChecklist parseMatrixRisk parseMatrixRisk6x5 parseFindings parseCostDistribution parseCapabilityMatrix parsePhasedPlan parseMarkdown parseVerdict parseComparison"
|
|
parser_hits=0
|
|
for p in $PARSERS; do
|
|
if grep -qE "function ${p}\b|${p} *:" "$HTML_FILE"; then
|
|
pass "Parser definert: $p"
|
|
parser_hits=$((parser_hits + 1))
|
|
else
|
|
fail "Parser mangler: $p"
|
|
fi
|
|
done
|
|
if [ "$parser_hits" -eq 14 ]; then
|
|
pass "14/14 parsere til stede"
|
|
else
|
|
fail "Forventet 14 parsere, fant $parser_hits"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 11. 17 renderer-funksjoner (kanonisk routing)
|
|
# -------------------------------------------------------
|
|
RENDERERS="renderAiActPyramid renderRequirements renderTransparency renderFria renderConformity renderDpia renderSecurity renderRos renderReview renderCost renderLicense renderMigrate renderAdr renderSummary renderPoc renderUtredning renderCompare"
|
|
renderer_hits=0
|
|
for r in $RENDERERS; do
|
|
if grep -qE "function ${r}\b|${r} *:" "$HTML_FILE"; then
|
|
pass "Renderer definert: $r"
|
|
renderer_hits=$((renderer_hits + 1))
|
|
else
|
|
fail "Renderer mangler: $r"
|
|
fi
|
|
done
|
|
if [ "$renderer_hits" -eq 17 ]; then
|
|
pass "17/17 renderers til stede"
|
|
else
|
|
fail "Forventet 17 renderers, fant $renderer_hits"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 12. Design-system CSS-klasse-bruk (Tier 1+2+3)
|
|
# -------------------------------------------------------
|
|
# v1.14.0 sesjon 3: .findings__list-wrapper fjernet sammen med .report-meta-band-aid.
|
|
# renderFindingsBlock bruker nå <section class="findings-section"> + <ul class="findings__items
|
|
# findings__items--standalone">. Asserterer .findings__items (BEM-list-items) i stedet —
|
|
# bekrefter at findings-strukturen fortsatt er i bruk uten at vi misbruker grid-containeren.
|
|
DS_CLASSES=".pyramide .matrix .radar .findings__items .distribution .critique-card .capability-matrix .aiact-timeline .tracks .error-summary .guide-panel .expansion .form-progress"
|
|
for cls in $DS_CLASSES; do
|
|
# Match som klassen i class="..." eller selektor — søk på klassenavnet uten leading dot
|
|
bare="${cls#.}"
|
|
if grep -qE "class=[\"'][^\"']*\\b${bare}\\b" "$HTML_FILE"; then
|
|
pass "Design-system-klasse brukt: ${cls}"
|
|
else
|
|
fail "Design-system-klasse mangler i markup: ${cls}"
|
|
fi
|
|
done
|
|
|
|
# .cmd-pipeline er reservert i design-systemet men ikke konsumert i v3 v.t. —
|
|
# pipeline-strenger rendres som <pre class="code-block">. Warn-only inntil
|
|
# en eksplisitt pipeline-renderer settes opp.
|
|
if grep -qE "class=[\"'][^\"']*\\bcmd-pipeline\\b" "$HTML_FILE"; then
|
|
pass "Design-system-klasse brukt: .cmd-pipeline"
|
|
else
|
|
warn "Design-system-klasse .cmd-pipeline ikke brukt (reservert for fremtidig pipeline-renderer)"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 13. data-report-slot per rapport-produserende command (17 stk)
|
|
# -------------------------------------------------------
|
|
REPORT_CMDS="classify requirements transparency frimpact conformity dpia security ros review cost license migrate adr summary poc utredning compare"
|
|
slot_hits=0
|
|
for c in $REPORT_CMDS; do
|
|
if grep -qE "data-report-slot=[\"']${c}[\"']" "$HTML_FILE"; then
|
|
pass "data-report-slot=\"${c}\" markup til stede"
|
|
slot_hits=$((slot_hits + 1))
|
|
else
|
|
warn "data-report-slot=\"${c}\" finnes ikke i statisk markup (kan rendres dynamisk)"
|
|
fi
|
|
done
|
|
# Slot rendrer dynamisk via render-funksjoner — warn kun, ingen fail
|
|
pass "Report-slot-stikkprøve fullført ($slot_hits/17 statiske; resterende rendres dynamisk)"
|
|
|
|
# -------------------------------------------------------
|
|
# 14. report_archetype-routing-felt i CATALOG-data
|
|
# -------------------------------------------------------
|
|
if grep -qE "report_archetype *:" "$HTML_FILE"; then
|
|
pass "report_archetype-felt brukt i CATALOG"
|
|
else
|
|
fail "report_archetype-felt mangler i CATALOG"
|
|
fi
|
|
|
|
if grep -qE "renderer *:" "$HTML_FILE"; then
|
|
pass "renderer-felt brukt i CATALOG"
|
|
else
|
|
fail "renderer-felt mangler i CATALOG"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 15. Form-renderer felt-typer (Step 8)
|
|
# -------------------------------------------------------
|
|
FIELD_TYPES="text textarea select multiselect boolean number"
|
|
for ft in $FIELD_TYPES; do
|
|
if grep -qE "type *: *['\"]${ft}['\"]" "$HTML_FILE"; then
|
|
pass "Form-felt-type definert: $ft"
|
|
else
|
|
warn "Form-felt-type ikke direkte funnet i markup: $ft (kan være avledet)"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 16. Onboarding-schema: 5 grupper
|
|
# -------------------------------------------------------
|
|
ONBOARDING_GROUPS="organization technology security architecture business"
|
|
for g in $ONBOARDING_GROUPS; do
|
|
if grep -qE "id: *['\"]${g}['\"]" "$HTML_FILE"; then
|
|
pass "Onboarding-gruppe definert: $g"
|
|
else
|
|
fail "Onboarding-gruppe mangler: $g"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 17. Catalog-expansion: 5 grupper
|
|
# -------------------------------------------------------
|
|
CATALOG_GROUPS="regulatory security economy documentation tool"
|
|
for g in $CATALOG_GROUPS; do
|
|
if grep -qE "id: *['\"]${g}['\"].*label:" "$HTML_FILE"; then
|
|
pass "Catalog-gruppe definert: $g"
|
|
else
|
|
warn "Catalog-gruppe-id '${g}' kunne ikke verifiseres på samme linje"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 18. Renderer- og parser-helpers
|
|
# -------------------------------------------------------
|
|
HELPERS="renderError renderEmptyState renderMatrixHtml renderRadarSvg renderThreatsTable renderFindingsBlock parseTable parseSections extractField escapeHtml escapeAttr"
|
|
for h in $HELPERS; do
|
|
if grep -qE "function ${h}\b" "$HTML_FILE"; then
|
|
pass "Helper definert: $h"
|
|
else
|
|
fail "Helper mangler: $h"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 19. State-modul: SCHEMA_VERSION + MIGRATIONS-pipeline
|
|
# -------------------------------------------------------
|
|
if grep -qE "SCHEMA_VERSION" "$HTML_FILE"; then
|
|
pass "SCHEMA_VERSION-konstant til stede"
|
|
else
|
|
fail "SCHEMA_VERSION-konstant mangler"
|
|
fi
|
|
|
|
if grep -qE "const MIGRATIONS|MIGRATIONS *=" "$HTML_FILE"; then
|
|
pass "MIGRATIONS-pipeline definert"
|
|
else
|
|
fail "MIGRATIONS-pipeline mangler"
|
|
fi
|
|
|
|
# IDB-primær / localStorage-fallback
|
|
if grep -qE "indexedDB|IDBOpenDBRequest|openDB\b" "$HTML_FILE"; then
|
|
pass "IndexedDB-primær persistens implementert"
|
|
else
|
|
warn "IndexedDB-referanser ikke funnet — fallback bruker localStorage alene"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 20. ACTIONS-handlers (kanonisk liste)
|
|
# -------------------------------------------------------
|
|
ACTIONS_LIST="goto-home goto-catalog goto-onboarding new-project open-project create-project delete-project confirm-delete-project modal-cancel parse onboarding-save onboarding-cancel onboarding-toggle-group onboarding-goto-group onboarding-focus-error project-tab open-catalog-form catalog-toggle-group export-state import-state copy-command preview-command toggle-theme"
|
|
for a in $ACTIONS_LIST; do
|
|
if grep -qE "ACTIONS\[['\"]${a}['\"]\]" "$HTML_FILE"; then
|
|
pass "ACTIONS-handler registrert: $a"
|
|
else
|
|
fail "ACTIONS-handler mangler: $a"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 21. archetype-routing (17 commands → archetype + renderer)
|
|
# -------------------------------------------------------
|
|
# Each report-producing command must have report_archetype + renderer in CATALOG.
|
|
# We do a coarse check: count of report_archetype: keys >= 17, count of renderer: keys >= 17
|
|
arch_count=$( { grep -E "report_archetype *: *['\"]" "$HTML_FILE" || true; } | wc -l | tr -d ' ')
|
|
rend_count=$( { grep -E "^[[:space:]]*renderer *: *['\"]" "$HTML_FILE" || true; } | wc -l | tr -d ' ')
|
|
if [ "${arch_count:-0}" -ge 17 ]; then
|
|
pass "report_archetype tilordnet >= 17 commands ($arch_count totalt)"
|
|
else
|
|
fail "report_archetype-tilordninger: forventet >= 17, fant $arch_count"
|
|
fi
|
|
if [ "${rend_count:-0}" -ge 17 ]; then
|
|
pass "renderer tilordnet >= 17 commands ($rend_count totalt)"
|
|
else
|
|
fail "renderer-tilordninger: forventet >= 17, fant $rend_count"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 22. produces_report-flagg på rapport-commands
|
|
# -------------------------------------------------------
|
|
prod_count=$( { grep -E "produces_report *: *true" "$HTML_FILE" || true; } | wc -l | tr -d ' ')
|
|
if [ "${prod_count:-0}" -ge 17 ]; then
|
|
pass "produces_report: true satt på >= 17 commands ($prod_count totalt)"
|
|
else
|
|
fail "produces_report: true: forventet >= 17, fant $prod_count"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 23. Eksport/import — Blob, URL.createObjectURL, FileReader / file-input
|
|
# -------------------------------------------------------
|
|
if grep -qE "Blob" "$HTML_FILE"; then
|
|
pass "Eksport-primitive: Blob"
|
|
else
|
|
fail "Eksport-primitive mangler: Blob"
|
|
fi
|
|
|
|
if grep -qE "URL\.createObjectURL" "$HTML_FILE"; then
|
|
pass "Eksport-primitive: URL.createObjectURL"
|
|
else
|
|
fail "Eksport-primitive mangler: URL.createObjectURL"
|
|
fi
|
|
|
|
if grep -qE "FileReader" "$HTML_FILE" || grep -qE "type=[\"']file[\"']" "$HTML_FILE"; then
|
|
pass "Import-primitive: FileReader eller <input type=\"file\">"
|
|
else
|
|
fail "Import-primitive mangler: FileReader / file-input"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 24. data-action attributter — minst 20 unike (delegert click-handler)
|
|
# -------------------------------------------------------
|
|
unique_actions=$( { grep -oE "data-action=[\"'][a-z-]+[\"']" "$HTML_FILE" || true; } | sort -u | wc -l | tr -d ' ')
|
|
if [ "$unique_actions" -ge 20 ]; then
|
|
pass "Unike data-action-verdier: $unique_actions (>= 20)"
|
|
else
|
|
fail "For få unike data-action-verdier: $unique_actions (< 20)"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 25a. SC8 — per-renderer verdict-pill emission (R7)
|
|
# Hver av de 6 Sub-batch A-rendererene må enten emitte data-verdict direkte
|
|
# i sin body, eller invokere renderPageShell (som emitter via helper).
|
|
# -------------------------------------------------------
|
|
SC8_RENDERERS_A="renderAiActPyramid renderRequirements renderTransparency renderFria renderConformity renderDpia"
|
|
for fn in $SC8_RENDERERS_A; do
|
|
body=$(awk "/function $fn\(/,/^ \}$/" "$HTML_FILE")
|
|
if echo "$body" | grep -qE "verdict[^A-Za-z]*data-verdict\s*=\s*[\"'](go|go-with-conditions|block|approved|failed|allow|warning|n-a)[\"']" \
|
|
|| echo "$body" | grep -q "renderPageShell"; then
|
|
pass "SC8 verdict-pill: $fn (direkte eller via renderPageShell)"
|
|
else
|
|
fail "SC8 verdict-pill: $fn mangler både data-verdict og renderPageShell"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 25b. Step 10 must_contain — kanban-board + pair-before-after
|
|
# (v1.11.0: residual-pair migrert til DS-navn pair-before-after)
|
|
# -------------------------------------------------------
|
|
kanban_count=$( { grep -cE "kanban-board|kanban-col" "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${kanban_count:-0}" -ge 1 ]; then
|
|
pass "kanban-board markup til stede ($kanban_count treff, Step 10 must_contain)"
|
|
else
|
|
fail "kanban-board markup mangler (Step 10 must_contain krever >=1)"
|
|
fi
|
|
|
|
pair_count=$( { grep -cE "pair-before-after" "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${pair_count:-0}" -ge 1 ]; then
|
|
pass "pair-before-after markup til stede ($pair_count treff, Step 10 must_contain)"
|
|
else
|
|
fail "pair-before-after markup mangler (Step 10 must_contain krever >=1)"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 25c. SC8 — per-renderer verdict-pill emission for Sub-batch B (R7)
|
|
# Hver av de 3 Sub-batch B-rendererene må enten emitte data-verdict direkte
|
|
# i sin body, eller invokere renderPageShell (som emitter via helper).
|
|
# -------------------------------------------------------
|
|
SC8_RENDERERS_B="renderSecurity renderRos renderReview"
|
|
for fn in $SC8_RENDERERS_B; do
|
|
body=$(awk "/function $fn\(/,/^ \}$/" "$HTML_FILE")
|
|
if echo "$body" | grep -qE "verdict[^A-Za-z]*data-verdict\s*=\s*[\"'](go|go-with-conditions|block|approved|failed|allow|warning|n-a)[\"']" \
|
|
|| echo "$body" | grep -q "renderPageShell"; then
|
|
pass "SC8 verdict-pill: $fn (direkte eller via renderPageShell)"
|
|
else
|
|
fail "SC8 verdict-pill: $fn mangler både data-verdict og renderPageShell"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 25d. Step 11 must_contain — top-risks + suppressed
|
|
# -------------------------------------------------------
|
|
toprisks_count=$( { grep -cE "top-risks" "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${toprisks_count:-0}" -ge 1 ]; then
|
|
pass "top-risks markup til stede ($toprisks_count treff, Step 11 must_contain)"
|
|
else
|
|
fail "top-risks markup mangler (Step 11 must_contain krever >=1)"
|
|
fi
|
|
|
|
suppressed_count=$( { grep -cE "suppressed" "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${suppressed_count:-0}" -ge 1 ]; then
|
|
pass "suppressed markup til stede ($suppressed_count treff, Step 11 must_contain)"
|
|
else
|
|
fail "suppressed markup mangler (Step 11 must_contain krever >=1)"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 25e. SC8 — per-renderer verdict-pill emission for Sub-batch C (R7)
|
|
# Hver av de 8 Sub-batch C-rendererene må enten emitte data-verdict direkte
|
|
# i sin body, eller invokere renderPageShell (som emitter via helper).
|
|
# -------------------------------------------------------
|
|
SC8_RENDERERS_C="renderCost renderLicense renderMigrate renderAdr renderSummary renderPoc renderUtredning renderCompare"
|
|
for fn in $SC8_RENDERERS_C; do
|
|
body=$(awk "/function $fn\(/,/^ \}$/" "$HTML_FILE")
|
|
if echo "$body" | grep -qE "verdict[^A-Za-z]*data-verdict\s*=\s*[\"'](go|go-with-conditions|block|approved|failed|allow|warning|n-a)[\"']" \
|
|
|| echo "$body" | grep -q "renderPageShell"; then
|
|
pass "SC8 verdict-pill: $fn (direkte eller via renderPageShell)"
|
|
else
|
|
fail "SC8 verdict-pill: $fn mangler både data-verdict og renderPageShell"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 25f. Step 12 must_contain — mat-ladder + tab-list + _consumer
|
|
# (v1.11.0: screen-tabs migrert til DS-navn tab-list)
|
|
# -------------------------------------------------------
|
|
matladder_count=$( { grep -cE "mat-ladder" "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${matladder_count:-0}" -ge 1 ]; then
|
|
pass "mat-ladder markup til stede ($matladder_count treff, Step 12 must_contain)"
|
|
else
|
|
fail "mat-ladder markup mangler (Step 12 must_contain krever >=1)"
|
|
fi
|
|
|
|
tablist_count=$( { grep -cE 'class="tab-list"' "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${tablist_count:-0}" -ge 1 ]; then
|
|
pass "tab-list markup til stede ($tablist_count treff, Step 12 must_contain)"
|
|
else
|
|
fail "tab-list markup mangler (Step 12 must_contain krever >=1)"
|
|
fi
|
|
|
|
consumer_count=$( { grep -cE "_consumer" "$HTML_FILE" || true; } | tr -d ' ')
|
|
if [ "${consumer_count:-0}" -ge 1 ]; then
|
|
pass "_consumer-mekanisme til stede ($consumer_count treff, Step 12 must_contain)"
|
|
else
|
|
fail "_consumer-mekanisme mangler (Step 12 must_contain krever >=1)"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 25g. Felles grunnskjelett — alle 17 renderers emiter page__eyebrow + h1 + verdict
|
|
# Step 12 strukturell assert per R7 + plan-spec.
|
|
# -------------------------------------------------------
|
|
ALL_RENDERERS="renderAiActPyramid renderRequirements renderTransparency renderFria renderConformity renderDpia renderSecurity renderRos renderReview renderCost renderLicense renderMigrate renderAdr renderSummary renderPoc renderUtredning renderCompare"
|
|
shell_count=0
|
|
for fn in $ALL_RENDERERS; do
|
|
body=$(awk "/function $fn\(/,/^ \}$/" "$HTML_FILE")
|
|
if echo "$body" | grep -q "renderPageShell"; then
|
|
shell_count=$((shell_count + 1))
|
|
fi
|
|
done
|
|
if [ "$shell_count" -eq 17 ]; then
|
|
pass "Alle 17 renderers bruker renderPageShell (felles grunnskjelett: page__eyebrow + h1 + verdict via helper)"
|
|
else
|
|
fail "Kun $shell_count/17 renderers bruker renderPageShell — felles grunnskjelett ufullstendig"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 25h. Tier 3-bruk per Step 12 — kanban (conformity/review), mat-ladder (migrate/poc)
|
|
# -------------------------------------------------------
|
|
for fn in renderConformity renderReview; do
|
|
body=$(awk "/function $fn\(/,/^ \}$/" "$HTML_FILE")
|
|
if echo "$body" | grep -qE "kanban-board|kanban-col"; then
|
|
pass "Tier 3 kanban: $fn bruker kanban-markup"
|
|
else
|
|
fail "Tier 3 kanban: $fn mangler kanban-markup"
|
|
fi
|
|
done
|
|
for fn in renderMigrate renderPoc; do
|
|
body=$(awk "/function $fn\(/,/^ \}$/" "$HTML_FILE")
|
|
if echo "$body" | grep -q "mat-ladder"; then
|
|
pass "Tier 3 mat-ladder: $fn bruker mat-ladder"
|
|
else
|
|
fail "Tier 3 mat-ladder: $fn mangler mat-ladder"
|
|
fi
|
|
done
|
|
|
|
# -------------------------------------------------------
|
|
# 25i. Onboarding-config field-type-distribution (4 strukturerte / 14 fritekst)
|
|
# Step 12 strukturell assert per R4 / R7. Counts ONBOARDING_SCHEMA-felter
|
|
# med type=select/multiSelect (strukturerte) vs text/textarea (fritekst).
|
|
# -------------------------------------------------------
|
|
onb_block=$(awk '/const ONBOARDING_SCHEMA = \[/,/^ \];/' "$HTML_FILE")
|
|
struct_count=$(printf '%s\n' "$onb_block" | grep -cE "type:\s*'(select|multiSelect)'" | tr -d ' ')
|
|
free_count=$(printf '%s\n' "$onb_block" | grep -cE "type:\s*'(text|textarea)'" | tr -d ' ')
|
|
if [ "${struct_count:-0}" -ge 4 ] && [ "${struct_count:-0}" -le 5 ]; then
|
|
pass "Onboarding strukturerte felter: $struct_count (forventet 4)"
|
|
else
|
|
fail "Onboarding strukturerte felter: $struct_count (forventet 4)"
|
|
fi
|
|
if [ "${free_count:-0}" -ge 13 ] && [ "${free_count:-0}" -le 16 ]; then
|
|
pass "Onboarding fritekst-felter: $free_count (forventet ~14)"
|
|
else
|
|
fail "Onboarding fritekst-felter: $free_count (forventet ~14)"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# 25. Inline-script eneste JS — ingen <script src=> til lokale .js-filer
|
|
# -------------------------------------------------------
|
|
ext_local_js=$( { grep -E "<script[^>]+src=[\"'][^\"']+\.js[\"']" "$HTML_FILE" || true; } | wc -l | tr -d ' ')
|
|
if [ "${ext_local_js:-0}" -eq 0 ]; then
|
|
pass "Ingen eksterne <script src=...js>-koblinger (single-file v3)"
|
|
else
|
|
fail "Eksterne lokale .js-koblinger funnet: $ext_local_js"
|
|
fi
|
|
|
|
# -------------------------------------------------------
|
|
# Oppsummering
|
|
# -------------------------------------------------------
|
|
print_summary
|