PRACTICAL GUIDE / Playwright test JSON-LD schema
Test JSON-LD Schema with Playwright
Learn Playwright test JSON-LD schema checks for BlogPosting, FAQPage, and BreadcrumbList, including parsing, required fields, URLs, and CI failures.
In this guide10 sections
- What Does a Playwright JSON-LD Test Actually Prove?
- Which JSON-LD Objects Does the Blog Page Render?
- How Should You Find and Parse Multiple JSON-LD Blocks?
- A Numbered Workflow for Testing Rendered Structured Data
- Code Example: Assert BlogPosting Against the Rendered Article
- How Do You Test FAQPage and BreadcrumbList Without Brittle Snapshots?
- JSON Syntax, Vocabulary, and Page Consistency
- Which Failures Should Block CI?
- Frequently Asked Questions About Playwright JSON-LD Tests
- Can Playwright validate JSON-LD without a third-party schema library?
- How do I test several JSON-LD script tags on one page?
- Should I snapshot the complete JSON-LD object?
- How do I test an optional FAQPage block?
- Does valid JSON-LD guarantee a Google rich result?
- Should JSON-LD tests compare values with visible page content?
- Next Steps: Build a Focused JSON-LD Regression Suite
What you will learn
- What Does a Playwright JSON-LD Test Actually Prove?
- Which JSON-LD Objects Does the Blog Page Render?
- How Should You Find and Parse Multiple JSON-LD Blocks?
- A Numbered Workflow for Testing Rendered Structured Data
Playwright test JSON-LD schema checks can validate the structured data that a browser actually receives. Locate every script[type="application/ld+json"], parse each text value with JSON.parse, select objects by @type, and compare required properties with the page URL, metadata, and visible content. This is different from validating an arbitrary API response against JSON Schema. The target is rendered SEO markup, including BlogPosting, FAQPage, and BreadcrumbList, after the application has assembled the final page.
That browser boundary matters. A TypeScript object can look correct before rendering while the delivered page contains an old canonical URL, an empty author, duplicate schema types, or a stale FAQ list. A Playwright test sees the same document boundary that a crawler sees after navigation. It can connect page identity, structured data, and visible content in one diagnostic test.
What Does a Playwright JSON-LD Test Actually Prove?
A useful JSON-LD test proves several claims separately. First, every selected script contains parseable JSON. Second, the page emits the object types required by the product contract. Third, each object carries the values the application intended. Fourth, linked values agree across surfaces, such as the canonical link and mainEntityOfPage.@id. Fifth, conditional objects appear only when their source content exists.
These claims are narrower than search-engine eligibility. The Google structured-data introduction explains that structured data helps Google understand page content and that feature-specific requirements still apply. A passing local test cannot promise crawling, indexing, or a rich result. It can prove that a release did not break the markup contract your team controls.
Feature support can also end while a repository contract remains useful. Google stopped showing FAQ rich results on May 7, 2026 and removed its FAQ rich-result documentation in June 2026. QABattle can still test FAQPage because the object expresses a Schema.org contract and must agree with visible questions and answers. That test should not be presented as a path to a current Google FAQ search feature.
This separation prevents two common testing errors. The first is stopping after JSON.parse, which accepts a syntactically valid object with the wrong meaning. The second is copying an external validator's result into CI without checking page-specific values. External validation may know the vocabulary, but it does not know that the article slug, headline, FAQ count, and canonical identity should agree with this page.
Think of the result as a chain of evidence. Script discovery proves the document contains candidate data. Parsing proves each candidate is JSON. Type selection proves the expected page-level objects exist. Property assertions prove the template populated the contract. Cross-surface checks prove those properties describe the current document. A failure at an earlier link should not be hidden by a later optional check, so keep each assertion and message tied to one link in that chain.
Serialization deserves one focused check too. The page sends every object through serializeJsonLd before assigning script text. The end-to-end suite should consume that final text exactly as delivered. It should not import articleJsonLd, call the same serializer, or reconstruct a corrected object in test code. Doing so would move the assertion away from the browser artifact and could let one shared defect influence both expected and actual values.
Readers who need generic payload validation should use the JSON Schema validation guide. Teams designing validation at TypeScript runtime boundaries can also consult runtime schema validation with static models. Those practices complement browser checks, but they answer different questions.
Which JSON-LD Objects Does the Blog Page Render?
The repository page at src/app/blog/[slug]/page.tsx creates three local structured-data objects. articleJsonLd describes the article. breadcrumbJsonLd describes the path from home to blog to the current guide. faqJsonLd is conditional: it becomes an object only when post.faq has entries. The render filters false values before serializing each object with serializeJsonLd.
That implementation gives the test a precise map:
| Object type | Repository symbol | Core assertions | Conditional state | Typical regression |
|---|---|---|---|---|
BlogPosting | articleJsonLd | headline, canonical ID, dates, author, citations | Always present for an article | stale title or wrong canonical |
BreadcrumbList | breadcrumbJsonLd | three positions, names, item URLs | Always present for an article | wrong final slug or position |
FAQPage | faqJsonLd | question count, question text, answer text | Present only when FAQs exist | markup and visible FAQs diverge |
The article object also connects several systems. Its headline comes from post.title; description comes from frontmatter; datePublished and dateModified derive from article dates; mainEntityOfPage.@id uses the canonical URL; and citation is built from editorial sources. The test should assert those relationships rather than reimplementing the entire object construction in test code.
Other properties have precise repository sources. wordCount comes from the parsed post, the image URL appends /opengraph-image to the canonical, and the author type becomes Organization for The Testing Academy. Publisher name, logo dimensions, language, and combined keywords are template policy. Select a representative subset for every article and reserve exact article-specific checks for fields likely to regress. For example, require a positive integer word count globally, then compare an exact derived value only in a content-parser integration test.
Cardinality is part of the contract. The render maps the three local objects after filtering the nullable FAQ value, so an article with FAQs should expose one object of each type and an article without FAQs should expose two. If a layout later adds another structured-data type, lookup by @type lets that addition coexist without changing article assertions. Duplicate BlogPosting or BreadcrumbList objects should still fail because they create competing page-level descriptions.
The Schema.org BlogPosting type defines the vocabulary available for an article object. The Schema.org BreadcrumbList type defines an ordered list of breadcrumb items. Use these references to understand the types, then let the repository contract decide which properties must remain stable for this product.
How Should You Find and Parse Multiple JSON-LD Blocks?
Do not assume one script or a fixed script order. A page can contain article, breadcrumb, organization, product, or other structured data in separate blocks. A component added later may place a new block before the article block. A test that parses .first() can silently validate the wrong object or fail for an irrelevant ordering change.
Start with all matching scripts. Parse them independently so a failure identifies the exact block. If the project permits a top-level array, flatten it after parsing. Then build a lookup by @type. This creates readable assertions such as "expected one BlogPosting" instead of a deep property error against an unknown item.
The repository's e2e/public.spec.ts already demonstrates the sound base pattern: allTextContents(), JSON.parse, and find by @type. It then checks article word count, citation membership, and FAQ entity count. An expanded helper can add duplicate detection and better parse diagnostics without replacing that direct pattern.
Use Playwright's page evaluation guidance when values must be read or transformed in the page context. For JSON-LD scripts, locator text retrieval is usually enough. Page evaluation becomes useful when you need DOM properties, resolved URLs, or a content comparison that is easiest to express against browser state.
Top-level arrays need an explicit policy rather than an unconditional cast. Some pages may serialize one object per script, while another integration may serialize an array or use @graph. If arrays are accepted, flatten only that known form and continue to validate every element as an object before reading @type. If @graph is not part of the application contract, fail with a clear unsupported-shape message rather than silently skipping nested entities.
Likewise, @type can be a string or, in some vocabularies, a list. The current QABattle objects use one string each, so the narrow helper can require a string and report the block index when it receives anything else. That gives the suite room to adopt a wider representation deliberately instead of accidentally treating an array as a missing type.
A Numbered Workflow for Testing Rendered Structured Data
Use a workflow that moves from document access to semantic consistency:
- Navigate to a known canonical article route and require a successful page response.
- Collect all
application/ld+jsonscript text from the rendered document. - Require at least one block so an empty collection cannot pass later loops.
- Parse each block independently and include its index in any parse error.
- Flatten permitted arrays and group objects by their
@typevalues. - Require exactly one object for each unique page-level type in the fixture.
- Assert values against the canonical URL, visible heading, description, author, dates, and FAQ source.
- Run a second fixture that covers optional structured data, especially the no-FAQ branch.
- Attach the raw failing block or page HTML to the test report after redacting any sensitive content.
The order is deliberate. Structural failures should stop the test before semantic assertions produce confusing messages. Type grouping should happen before property access. Page comparisons should happen only after the expected object has been identified. That sequence turns one broad "schema failed" message into a small, actionable failure class.
Do not normalize away defects. Trimming harmless surrounding whitespace before parsing is reasonable. Rewriting malformed quotes, filling missing fields, or correcting URLs inside the test makes the test validate its own repair rather than the emitted page. Preserve the source value and report the discrepancy.
Design diagnostic output before the first CI failure. Include the route, script index, discovered types, expected type, and offending property path. For cardinality failures, list how many objects of each type were found. For URL disagreement, print the canonical link and schema value side by side. Attach raw script text only when the content is appropriate for test artifacts, and cap or redact it if future pages can include user-controlled data.
The fixture matrix should also state why each route exists. One page proves the positive FAQ branch, one proves absence, one has multiple citations, and one exercises updated dates or large content. Named intent prevents a later editor from replacing a fixture with a simpler article that no longer covers the boundary while leaving the test name unchanged.
Code Example: Assert BlogPosting Against the Rendered Article
The following TypeScript test follows the repository pattern while adding focused identity checks. The expected production URL is explicit because a local test server origin is not the page's canonical identity.
import { expect, test } from "@playwright/test";
type JsonLd = Record<string, unknown> & { "@type"?: string };
test("article emits one consistent BlogPosting object", async ({ page }) => {
const slug = "test-cases-for-payment-gateway";
const canonical = `https://qabattle.com/blog/${slug}`;
await page.goto(`/blog/${slug}`);
const rawBlocks = await page
.locator('script[type="application/ld+json"]')
.allTextContents();
expect(rawBlocks.length).toBeGreaterThan(0);
const objects = rawBlocks.map((raw, index) => {
try {
return JSON.parse(raw) as JsonLd;
} catch (error) {
throw new Error(`JSON-LD block ${index} is invalid: ${String(error)}`);
}
});
const articles = objects.filter((item) => item["@type"] === "BlogPosting");
expect(articles).toHaveLength(1);
const article = articles[0] as {
headline?: string;
mainEntityOfPage?: { "@id"?: string };
author?: { name?: string };
citation?: string[];
};
await expect(page.locator("h1")).toHaveText(article.headline ?? "");
expect(article.mainEntityOfPage?.["@id"]).toBe(canonical);
expect(article.author?.name).toBe("The Testing Academy");
expect(article.citation).toBeDefined();
expect(article.citation).not.toHaveLength(0);
for (const url of article.citation ?? []) {
expect(new URL(url).protocol).toBe("https:");
}
});This example does not repeat every production property. It chooses values that connect the structured object to other trusted surfaces. The H1 comparison catches a stale headline. The explicit canonical catches preview-host leakage. The author check protects organization identity. The citation checks require at least one source and reject non-HTTPS source values while leaving exact source membership to article-specific tests. Use the dedicated Playwright canonical URL testing guide when redirects, query parameters, and host policy need their own route matrix.
For reusable assertion design, custom Playwright matchers can package type selection and diagnostic output. Keep page-specific business assertions visible in each test so a reviewer can see what the route promises.
How Do You Test FAQPage and BreadcrumbList Without Brittle Snapshots?
Whole-object snapshots are tempting because JSON-LD is serializable. They also capture dates, word counts, citations, descriptions, and URLs that may change for valid editorial reasons. A reviewer can approve a large snapshot update without noticing that the last breadcrumb points to the wrong page. Focused assertions keep attention on identity and relationships.
For BreadcrumbList, require three ordered items for the current repository page. Check position values 1, 2, and 3; check the stable names Home and Blog; and compare the last item URL with the canonical. This validates order without pinning unrelated serialization details.
For FAQPage, use two routes. The positive route should have frontmatter FAQs and a visible FAQ section. Compare mainEntity.length with the expected FAQ count, then compare question names with visible question headings or a known data source. The negative route should have no FAQs and no FAQPage object. This directly exercises the conditional branch in src/app/blog/[slug]/page.tsx.
test("FAQ and breadcrumb objects match page content", async ({ page }) => {
await page.goto("/blog/test-cases-for-payment-gateway");
const values = await page
.locator('script[type="application/ld+json"]')
.allTextContents();
const objects = values.map((value) => JSON.parse(value));
const faq = objects.find((value) => value["@type"] === "FAQPage");
const breadcrumb = objects.find(
(value) => value["@type"] === "BreadcrumbList",
);
expect(faq).toBeDefined();
expect(faq.mainEntity).toHaveLength(5);
expect(
faq.mainEntity.every(
(item: { name?: unknown }) =>
typeof item.name === "string" && item.name.endsWith("?"),
),
).toBe(true);
expect(breadcrumb.itemListElement.map(
(item: { position: number }) => item.position,
)).toEqual([1, 2, 3]);
expect(breadcrumb.itemListElement.at(-1)?.item).toBe(
"https://qabattle.com/blog/test-cases-for-payment-gateway",
);
});When a property is dynamic but meaningful, assert its rule. A word count can be a positive integer or a content-derived exact value. A date can match frontmatter or ISO formatting. A source list can contain required official references. Rules survive legitimate edits better than a serialized blob.
Visible FAQ comparison needs stable selection. Prefer the actual FAQ headings or the parsed post data exposed through a supported page boundary. Do not compare only the count if reordered or duplicated questions would matter. Normalize whitespace for display formatting, but keep punctuation and wording checks exact enough to detect that structured data describes a different question. Answers can receive the same treatment when editorial consistency is part of the contract.
Breadcrumb checks should validate both order and identity. A set comparison would accept positions in the wrong sequence, while checking only [1, 2, 3] would accept incorrect destinations. Pair positions with names and URLs, then compare the third item with the already validated canonical. This creates one readable assertion for each navigation level without snapshotting context, serialization order, or properties unrelated to the breadcrumb path.
JSON Syntax, Vocabulary, and Page Consistency
Treat structured-data quality as layered evidence:
| Layer | Example failure | Best check | What it does not prove |
|---|---|---|---|
| JSON syntax | trailing comma or broken quote | parse every script | correct vocabulary |
| Object presence | no BlogPosting | group by @type | correct properties |
| Vocabulary shape | missing headline | focused property assertions | agreement with page |
| Page consistency | canonical ID differs from link tag | cross-surface comparison | search selection |
| Conditional behavior | FAQ object exists without FAQs | positive and negative fixtures | rich-result display |
The layers also determine ownership. A parse failure usually belongs to rendering or serialization. A missing object may belong to a template branch. A wrong canonical may belong to metadata assembly. A visible-content mismatch may come from editorial data or stale caching. Reporting the failed layer shortens triage.
Property-based techniques can help when many generated values share one contract. The guide to property-based evaluation of structured JSON addresses a different producer, but its invariant mindset transfers: identify rules that hold across examples, then generate cases around the boundaries. Keep the browser tests representative rather than attempting to crawl every article on every pull request.
Contract evolution deserves explicit review. Contract testing for schema evolution explains how producer and consumer expectations can drift. For JSON-LD, the producer is the page template and consumers include search tools, internal audits, and browser tests. A vocabulary addition should not force a test update unless the page contract actually changed.
Syntax, vocabulary, and page agreement should also fail with different messages. Wrap each JSON.parse call so the error names the script index and retains the original parser message. After parsing, check that each value is a non-null object before reading @type. Then report the set of observed types when an expected one is absent. That sequence gives a developer evidence such as "block 2 is malformed" or "expected BlogPosting, found BreadcrumbList and FAQPage" instead of an unhelpful property access error.
Cardinality deserves an explicit rule. A page can validly contain several JSON-LD blocks, but this template is designed to emit one BlogPosting, one BreadcrumbList, and zero or one FAQPage. Grouping by type lets a test reject duplicate page-level objects while accepting the three different objects together. If a future component adds another supported type, it should not disturb lookups based on @type.
Arrays need a documented boundary too. The current blog renderer serializes each object separately, while another route may serialize an array in one script. A collection helper can flatten a top-level array after parsing without recursively flattening arbitrary property arrays such as mainEntity or itemListElement. This keeps document containers separate from vocabulary data.
Page-consistency assertions should compare independent rendered evidence. Read the canonical href from the head, the H1 text from the article, and visible FAQ questions from the document. Do not import the same object builder that produced articleJsonLd and use its output as the expected value. Shared construction could reproduce the defect on both sides and let the test pass.
Dates need the same discipline. src/app/blog/[slug]/page.tsx builds datePublished and dateModified from post.publishedAt and post.updatedAt, adding the repository's time offset. A stable test can compare the emitted date prefix with the article metadata or require a parseable date and the expected calendar date. Avoid comparing with the current clock, which says nothing about the content record.
Image assertions should focus on page identity and shape. The repository constructs image.url under the canonical article route and supplies fixed width and height fields. Check the canonical prefix, expected Open Graph image suffix, and positive numeric dimensions. Downloading and visually comparing the generated image belongs in a separate test because it answers a different question.
Which Failures Should Block CI?
Block a release when the emitted document cannot be parsed, a required page-level object is missing or duplicated, the canonical identity points to the wrong host or slug, or structured data contradicts visible content. These are deterministic defects in output the application controls.
Use a review policy for optional or recommended properties. A new citation, image variation, or editorial description change may be correct. Tests should validate formatting and consistency while allowing intentional content updates. Avoid hard-coded counts unless the count itself is a product invariant, as with the three breadcrumb positions in this template.
Run a small matrix in pull requests:
- One article with populated FAQs.
- One article without FAQs.
- One article with several official sources.
- One recently updated article where modified date matters.
- One long article where word count and reading metadata are nontrivial.
Choose fixtures by branch, not by popularity. The FAQ-positive article exercises faqJsonLd and mainEntity; a no-FAQ article proves the conditional object is truly absent. A source-heavy article covers citation. A recently changed article covers date mapping. One content-heavy page checks numeric word count without making every pull request crawl the full library.
Keep fixture expectations close to their source. If the selected FAQ article changes from five questions to six, update its visible content and the focused expectation together. Do not hide all counts in a remote constants file that reviewers cannot connect to the page. When exact values are editorially volatile, compare the structured entity count with the rendered question count instead of pinning a number.
CI diagnostics should preserve only useful evidence. Attach the failing raw block, its script index, current route, and observed type list. For a consistency failure, include the canonical and structured values side by side. A complete HTML attachment can help in trace review, but the assertion message should already identify the violated contract.
Run the representative matrix on changes to src/app/blog/[slug]/page.tsx, src/lib/json-ld.ts, blog parsing, metadata fields, and article content used as fixtures. A scheduled or post-deployment pass can sample more routes. Separating fast template coverage from broader sampling keeps pull-request feedback focused while still detecting content-specific output defects.
Broader checks can run after deployment. The browser suite proves emitted behavior. Search-engine tools can inspect deployed pages under crawler-facing conditions. Preserve the separation so a temporary external-tool issue does not look like an application regression.
Split CI by cost and ownership. Pull requests can run a small deterministic page matrix against the built application. A scheduled job can sample more articles and report drift without making every content edit wait for a corpus crawl. A deployment smoke test can repeat canonical host, parse, required-type, and citation checks against the public route. Keep external rich-result review outside the deterministic browser gate and record its findings as operational evidence.
When a framework or serializer change lands, inspect the raw output before updating assertions. Formatting changes such as escaped characters or script ordering may be harmless because JSON.parse produces the same values. A changed type, missing page identity, or altered conditional branch is semantic and needs a product decision. This distinction prevents snapshot churn while keeping real contract changes visible.
Treat content edits and template edits differently in failure triage. If one article has a wrong title or source, review its frontmatter and source catalog. If every article loses mainEntityOfPage, inspect the shared page template. If only deployed pages use a preview host, inspect environment configuration. The same test can expose all three, but its report should preserve enough context to route the issue correctly.
For adjacent Playwright practices, use the Playwright API testing guide when response-level checks are sufficient, the locator guide for stable DOM selection, and strict TypeScript patterns for typed test helpers. Teams testing generated model JSON should instead read structured LLM output evaluation. REST Assured users have a separate schema-validation interview guide.
Frequently Asked Questions About Playwright JSON-LD Tests
Can Playwright validate JSON-LD without a third-party schema library?
Yes. The built-in browser and Node APIs are enough to collect scripts, parse JSON, and compare object properties. Add a vocabulary validator only when its extra coverage justifies another dependency. Keep page-specific assertions either way, because a generic validator cannot know the correct article URL, headline, author, or FAQ source.
How do I test several JSON-LD script tags on one page?
Read every matching block and select by @type. Never rely on order unless the order itself is part of the application contract. If top-level arrays are allowed, flatten them before grouping. Report block indexes for parse errors and object types for cardinality errors.
Should I snapshot the complete JSON-LD object?
Usually not. Snapshots are useful only for small, stable sub-objects. Full snapshots create noisy updates and make critical identity errors hard to spot. Prefer exact checks for relationships and rule-based checks for changing data. A breadcrumb list may suit a small inline snapshot; an entire article object usually does not.
How do I test an optional FAQPage block?
Use one page with FAQs and another without them. On the positive page, compare entity count and question text with the content. On the negative page, require the object to be absent. This tests both branches and prevents a template from emitting empty or stale FAQ markup.
Does valid JSON-LD guarantee a Google rich result?
No. Google stopped showing FAQ rich results on May 7, 2026 and removed the related documentation in June 2026. Testing QABattle's FAQPage still protects its Schema.org shape and agreement with visible content, but it is not evidence of FAQ rich-result eligibility. Evaluate other structured-data types against their currently supported Google features.
Should JSON-LD tests compare values with visible page content?
Yes. The markup describes the page, so key claims should agree with what users and metadata consumers receive. Compare titles, canonical identity, authorship, dates, and FAQ questions at stable boundaries. This catches a class of defects that both JSON parsing and vocabulary validation can miss.
Next Steps: Build a Focused JSON-LD Regression Suite
Start with the existing parsing pattern in e2e/public.spec.ts. Extract a small helper only for repeated mechanics: collecting blocks, parsing with diagnostics, and grouping by @type. Keep route-specific assertions in the tests. Add a positive FAQ fixture, a negative FAQ fixture, and cross-surface canonical checks.
Then decide which failures block a pull request and which require editorial review. Keep external search validation in a deployed-page stage. The result is a test suite that proves what the application controls: parseable markup, expected object types, correct page identity, and agreement between structured data and the content it describes.
// LIVE COURSE / THE TESTING ACADEMY
Playwright Automation Mastery
Go beyond Selenium. Master Playwright with JS/TS in 90 days.
From the instructor behind this guide.
Playwright jobs are growing 8x faster than Selenium. 90 days / 75+ live hrs / Tue-Thu-Sat 7 AM IST.
PRIMARY REFERENCES
Verify the details at the source
QABattle guides are practical explanations. Product behavior, standards, and APIs can change, so use these primary references for the canonical details.
- 01Official playwright.dev reference
playwright.dev
Primary documentation selected and verified for the claims in this guide.
- 02Official developers.google.com reference
developers.google.com
Primary documentation selected and verified for the claims in this guide.
- 03Official schema.org reference
schema.org
Primary documentation selected and verified for the claims in this guide.
- 04Official schema.org reference
schema.org
Primary documentation selected and verified for the claims in this guide.
FAQ / QUICK ANSWERS
Questions testers ask
Can Playwright validate JSON-LD without a third-party schema library?
Yes. Playwright can collect application/ld+json script text, parse it with JSON.parse, and assert the properties your page contract requires. A dedicated schema validator is optional when you need vocabulary-wide validation. Focused browser assertions are still valuable because they compare emitted markup with the rendered URL and content.
How do I test several JSON-LD script tags on one page?
Collect every matching script with allTextContents, parse each value, flatten arrays if your implementation permits them, and index objects by their @type value. Avoid assuming the first script is BlogPosting. Explicit type selection produces clearer failures when another component adds or reorders structured-data blocks.
Should I snapshot the complete JSON-LD object?
Usually not. Whole-object snapshots often change for legitimate dates, word counts, images, or citations and can hide the property that matters. Prefer focused assertions for required identity, relationships, and page consistency. A small inline snapshot can help for a stable sub-object such as fixed breadcrumb positions.
How do I test an optional FAQPage block?
Choose one fixture page with FAQ entries and one without them. Require exactly one FAQPage object on the first page, compare its question count and text with visible content, and require no FAQPage object on the second. This exercises both branches without making FAQ markup mandatory everywhere.
Does valid JSON-LD guarantee a Google rich result?
No. Google stopped showing FAQ rich results on May 7, 2026 and removed its FAQ rich-result documentation in June 2026. QABattle can still test FAQPage as a Schema.org and page-consistency contract. Other supported structured-data features remain subject to feature rules, policies, crawling, indexing, and Google's selection systems.
Should JSON-LD tests compare values with visible page content?
Yes. Structured data should describe the page users can access. Compare fields such as headline, description, canonical identity, author, and FAQ questions with their visible or metadata sources. That catches stale templates and mismatched content that pure syntax validation would accept even though the markup describes something else.
RELATED GUIDES
Continue the learning route
GUIDE 01
JSON Schema Validation in API Testing
Use JSON Schema validation in API testing to catch payload drift, required fields, types, and enum breaks with practical examples and a reusable checklist.
GUIDE 02
Runtime Schema Validation with Static TypeScript Models
TypeScript runtime schema validation architecture: practical design, implementation, debugging, CI, metrics, and interview guidance for QA, SDET, and automation.
GUIDE 03
Playwright Locators Guide: Find Elements Reliably
Playwright locators guide for stable UI tests with role selectors, filters, assertions, strict mode, debugging, and flaky selector fixes in CI.
GUIDE 04
Playwright API Testing: Validate APIs Inside Your E2E Suite
Playwright API testing guide covering request contexts, setup flows, assertions, authentication, fixtures, UI strategy, and CI-ready checks.
GUIDE 05
Custom Playwright Matchers: Extend and Merge expect Safely
Create retry-aware Playwright custom matchers, merge expect modules without collisions, and preserve useful negation, timeout, and failure output.
GUIDE 06
Contract Testing Tool Schema Evolution Across Agent Releases
Contract-test agent tool schema changes with compatibility corpora, adapters, producer-consumer matrices, guardrails, and staged release evidence.