Add structured data testing
Add structured-data-testing-tool
See example https://github.com/ThatGuySam/doesitarm/blob/6e11fbe8e79156282aa9c5d61f87808182814325/test/main.js#L8
Specifically, we want to ensure that any json+ld scripts in build/**/*.html will have the correct schema formats.
Before we start this, do a simple test across all our pages with like
find | exec yarn dlx structured-data-testing-tool test...
If there are some errors on any built page on our sites then setting up this testing will be a win
End result:
- [ ] Add script to package.json to validate after build
- [ ] Add it to our CI testing pipeline after build
- [ ] Create test cases with expected failures and include that to CI build (see existing CI build and fixtures for to check HTML Validate rules are working)
Ideas:
yarn add --dev structured-data-testing-tool
yarn
And make tests/build-structurd-data-validate
import { structuredDataTest } from "structured-data-testing-tool";
import { glob } from "glob";
import { readFileSync } from "fs";
// Find and sort all HTML files in the 'build' directory
const targets = glob.sync("build/**/*.html").sort();
// Synchronously validate each target file
const outcomes = targets.map((target) => {
const html = readFileSync(target, "utf8");
let success = true;
try {
structuredDataTest(html)
.then((res) => {
console.log("✅ " + target);
console.log("⚠️ Warnings:\n", res);
})
.catch((err) => {
console.log("❌ " + target);
console.log("⚠️ Errors:\n", err);
success = false;
});
return success;
} catch (error) {
console.error(`Error validating ${target}:`, error);
success = false;
}
return success;
});
if (outcomes.every((outcome) => outcome)) {
console.log("✨ All tests passed!\n");
} else {
console.log("❌ Some tests failed.");
process.exit(1);
}
And test with index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>My first website about horses</title>
<link rel="canonical" href="https://localhost/">
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
<div class="container">
<h1 class="navbar-brand mb-0">My first website about horses</h1>
</div>
</nav>
<section class="jumbotron text-center">
<div class="container">
<h1 class="jumbotron-heading">Album example</h1>
<p class="lead text-muted">
Something short and leading about the collection below—its contents, the creator, etc. Make it short and
sweet, but not too short so folks don't simply skip over it entirely.
</p>
<p>
<a href="/" class="btn btn-primary">Main call to action</a>
<a href="/" class="btn btn-outline-secondary bg-white">Secondary action</a>
</p>
</div>
</section>
<div class="album text-muted">
<div class="container">
<div class="row">
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
</div>
<div class="row">
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
</div>
<div class="row">
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
<div class="col">
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR4AWNgAAAAAgABc3UBGAAAAABJRU5ErkJggg=="
alt="Card image cap"
width="350"
height="150"
>
<p class="card-text">
This is a wider card with supporting text below as a natural lead-in to additional content. This content
is a little bit longer.
</p>
</div>
</div>
</div>
</div>
<hr>
<footer class="text-muted">
<div class="container">
<p>This web page was made with love and admiration by A Horse Lover.</p>
</div>
</footer>
<script type="application/ld+json">
{
a"@context": "http://schema.org",
"@type": "ReportageNewsArticle",
"url": "https://www.bbc.co.uk/news/world-us-canada-49060410",
"publisher": {
"@type": "NewsMediaOrganization",
"name": "BBC News",
"publishingPrinciples": "http://www.bbc.co.uk/news/help-41670342",
"logo": {
"@type": "ImageObject",
"url": "https://static.files.bbci.co.uk/ws/simorgh-assets/public/news/images/metadata/poster-1024x576.png"
}
},
"datePublished": "2019-07-20T23:07:27.000Z",
"dateModified": "2019-07-21T00:41:12.000Z",
"description": "On 20 July 1969, Apollo 11 landed - and hours later Neil Armstrong took his historic first steps.",
"headline": "Apollo 11: World celebrates 50th anniversary of first Moon landing",
"image": {
"@type": "ImageObject",
"width": 1200,
"height": 675,
"url": "https://ichef.bbci.co.uk/ace/branded_news/1200/cpsprodpb/5509/production/_107896712_moonlanding3getty.jpg"
},
"thumbnailUrl": "https://ichef.bbci.co.uk/ace/branded_news/1200/cpsprodpb/5509/production/_107896712_moonlanding3getty.jpg",
"mainEntityOfPage": "https://www.bbc.co.uk/news/world-us-canada-49060410",
"author": {
"@type": "NewsMediaOrganization",
"name": "BBC News",
"noBylinesPolicy": "http://www.bbc.co.uk/news/help-41670342#authorexpertise",
"logo": {
"@type": "ImageObject",
"url": "https://static.files.bbci.co.uk/ws/simorgh-assets/public/news/images/metadata/poster-1024x576.png"
}
}
}
</script>
</body>
</html>
!!! Notice a before @context.
This should print as an error. But it does not.
Otherwise, this is successfully testing the schema format.