4.1 KiB
DOM Analysis Spec (WE-D)
Overview
Extracts structured metadata from a loaded page using Playwright's page.evaluate().
Provides the page structure data used in the report's "Page Structure" section.
Runs in the same browser session as the screenshots to avoid a second page load.
Responsibilities
- Extract title, meta tags, canonical URL, Open Graph tags
- Count and validate heading hierarchy (H1–H6)
- Audit images for missing alt text
- Audit links for external targets missing
rel="noopener" - Detect JSON-LD structured data
- Return a plain object (serialisable to JSON)
Delegates to: Playwright page.evaluate()
Dependencies
Read pipeline.md for output file layout. Read screenshot.md — DOM extraction reuses the same Playwright page.
Data Model
{
title: 'Example Domain',
titleLength: 14,
meta: {
description: null, // string or null
descriptionLength: null, // number or null
robots: 'index, follow', // string or null
viewport: 'width=device-width, initial-scale=1', // string or null
},
canonical: null, // string URL or null
openGraph: {
title: null,
description: null,
image: null,
type: null,
},
headings: {
h1: ['Example Domain'], // array of text content
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
skips: [], // e.g. ['H1→H3'] if H2 is absent between H1 and H3
},
images: {
total: 12,
missingAlt: 3, // count with no alt attribute or alt=""
missingAltSrcs: ['...'], // up to 5 example src values
},
links: {
total: 24,
external: 8,
externalNewTab: 4, // target="_blank"
externalNewTabNoOpener: 3, // target="_blank" without rel containing noopener
},
structuredData: [], // array of parsed JSON-LD objects (empty if none)
}
Requirements
WE-D-1: Extract metadata in a single page.evaluate() call to minimise
round-trips. All DOM access happens inside the browser context.
WE-D-2: meta.description is null if the <meta name="description"> tag
is absent or has an empty content attribute.
WE-D-3: Heading hierarchy skips are detected by comparing sequential heading
levels. If the level jumps by more than 1 (e.g., H1 → H3), record the skip as
"H1→H3" in headings.skips.
Why: Heading skips confuse screen readers and weaken SEO.
WE-D-4: An image is counted as missingAlt if it lacks the alt attribute
entirely OR if alt is an empty string "".
Why: Both mean the image is inaccessible to screen readers.
WE-D-5: A link is counted as externalNewTabNoOpener if it has target="_blank"
AND its rel attribute does not contain noopener.
Why: Without noopener, the opened page can access window.opener — a security risk.
WE-D-6: Structured data is extracted from all <script type="application/ld+json">
tags. Parse each; if parsing fails, include the raw text string instead of the object.
WE-D-7: The missingAltSrcs array contains at most 5 example src values
(truncated to 80 chars each) to keep the report concise.
WE-D-8: The result must be JSON-serialisable (no DOM nodes, functions, or circular refs).
WE-D-9: Run on the desktop viewport page (the same page used for the desktop screenshot). Do not navigate again.
Scenarios
Scenario: Well-structured page
Given: Page with one H1, sequential headings, all images have alt, no blank-target links
When: analyzeDom(page) is called
Then: headings.skips is empty, images.missingAlt === 0, links.externalNewTabNoOpener === 0
Scenario: Missing meta description
Given: Page with no <meta name="description"> tag
When: DOM is analysed
Then: meta.description === null, meta.descriptionLength === null
Scenario: Heading skip detected
Given: Page with H1 then H3 (no H2)
When: DOM is analysed
Then: headings.skips includes "H1→H3"
Scenario: JSON-LD present
Given: Page with <script type="application/ld+json">{"@type":"WebSite"}</script>
When: DOM is analysed
Then: structuredData contains [{ "@type": "WebSite" }]