openvibers/openvibe.shared Commits

4.100.1: the browser harness counts a counted fold's text as on the page (#261)

OP OpenVibers committed 11 days ago · bc4840348d · 6 files, +20 −7

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 78936b8..63c6097 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -4,6 +4,14 @@ All notable changes to `openvibe-shared`. Versions follow [semver](https://semve
breaking change to any exported module, browser global or served file name is a new major.
A release is the git tag `vX.Y.Z`; consumers pin the tag's tarball (see README).
++## 4.100.1 — 2026-11-02
++
++- **The browser harness counts a counted fold's text as on the page.** A closed `<details>` opens with one tap, with
++ or without JavaScript, and search engines read it; the network's rule is to fold, never to hide. The release check's
++ JSON-LD rule (each entity's name in the page's text; 80% of a list's items) failed Network's home: its "50 sites"
++ list names the sites under "Every other neighbourhood". The contents of closed `<details>` (all but the summary) are
++ now part of the text the checks read.
++
## 4.100.0 — 2026-11-02
From a phone sweep of every site's home (11-02):
ddiff --git a/README.md b/README.md
iindex a6c6318..aa45332 100644
---- a/README.md
++++ b/README.md
@@@ -2,7 +2,7 @@
> Versioned UI, the OpenVibe Frame (the navbar, footer and "shipped" views every site sits in), SEO, legal and release-client packages every OpenVibe site renders.
--**Status:** alpha, v4.100.0 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
++**Status:** alpha, v4.100.1 (every release is a tag; see [CHANGELOG.md](CHANGELOG.md)). Every deployed
consumer installs a tagged release and none keeps a vendored copy
([docs/migration-plan.md](docs/migration-plan.md) is done); each repository's `package.json` names
the tag it pins.
ddiff --git a/STATUS.json b/STATUS.json
iindex 09300d0..f943722 100644
---- a/STATUS.json
++++ b/STATUS.json
@@@ -4,7 +4,7 @@
"code": true,
"wave": "W2",
"package": "openvibe-shared",
-- "version": "4.100.0",
++ "version": "4.100.1",
"plan": "OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026)",
"deployed": false,
"deployment": "none of its own: a package released as git tags; OpenVibe.Network serves /shared/* from its pinned tag, and a site can serve its own pinned copy (openvibe-shared/serve)",
ddiff --git a/browser-harness.js b/browser-harness.js
iindex b2ae9cf..ee8991e 100644
---- a/browser-harness.js
++++ b/browser-harness.js
@@@ -360,7 +360,10 @@ const READ_PAGE = `(() => {
offenders.push({ el: e, desc: describe(e) + ' (right ' + Math.round(r.right) + 'px)' });
}
}
-- const text = (body ? body.innerText : '').replace(/\\s+/g, ' ').trim();
++ // A counted fold's contents (a closed <details>: one tap, with or without JavaScript, and read by search engines)
++ // count as the page's text: the network's rule is to fold, never to hide (the owner, 2026-10-31).
++ const folded = [...document.querySelectorAll('details:not([open])')].map((d) => [...d.children].filter((c) => c.tagName !== 'SUMMARY').map((c) => c.textContent).join(' ')).join(' ');
++ const text = ((body ? body.innerText : '') + ' ' + folded).replace(/\\s+/g, ' ').trim();
return {
url: location.href, title: document.title, vw, scrollWidth, scrollX,
offenders: offenders.map((o) => o.desc),
ddiff --git a/package.json b/package.json
iindex c178a9e..9f033dc 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-shared",
-- "version": "4.100.0",
++ "version": "4.100.1",
"description": "Shared navbar, footer, themes, icons, legal pages, SEO, auth and analytics for every OpenVibe site",
"main": "index.js",
"bin": {
ddiff --git a/test/browser-harness-chrome.test.js b/test/browser-harness-chrome.test.js
iindex 39fadb2..8d6e2b4 100644
---- a/test/browser-harness-chrome.test.js
++++ b/test/browser-harness-chrome.test.js
@@@ -15,8 +15,10 @@ if (process.env.OV_SKIP_BROWSER === '1' || !h.findChrome()) {
const words = 'This page has enough server-rendered words to count as meaningful content for a crawler. '.repeat(4);
const page = (body, head = '') => `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>T</title><link rel="icon" href="data:,">${head}</head><body>${body}</body></html>`;
const ROUTES = {
-- '/': () => page(`<main><h1>Good Page</h1><p>${words}</p><a href="/b">B page</a></main>`,
-- '<link rel="canonical" href="ORIGIN/"><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","name":"Good Page"}</script>'),
++ // A list whose items sit in a counted fold (a closed <details>) is on the page: fold, never hide (2026-11-02).
++ '/': () => page(`<main><h1>Good Page</h1><p>${words}</p><a href="/b">B page</a><details><summary>Every other site <span>3 more</span></summary><ul><li>Folded Alpha</li><li>Folded Beta</li><li>Folded Gamma</li></ul></details></main>`,
++ '<link rel="canonical" href="ORIGIN/"><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","name":"Good Page"}</script>'
++ + '<script type="application/ld+json">{"@context":"https://schema.org","@type":"ItemList","name":"Sites","itemListElement":[{"@type":"ListItem","position":1,"name":"Folded Alpha"},{"@type":"ListItem","position":2,"name":"Folded Beta"},{"@type":"ListItem","position":3,"name":"Folded Gamma"}]}</script>'),
'/b': () => page(`<div id="root"></div><div style="width:2000px" class="wide">wide</div>
<script src="/s.js?v=1"></script><script src="/s.js?v=2"></script>
<script>document.getElementById('root').innerHTML = '<p>${words}</p>'; console.error('boom from b'); window.onload = () => { null.x; };</script>`,
@@@ -73,7 +75,7 @@ const AXE_STUB = `window.axe = { run: () => Promise.resolve({ violations: locati
assert.ok(/^Chrome\/|HeadlessChrome\//.test(report.chrome), report.chrome);
assert.deepStrictEqual(good.checks, { status: 'pass', errors: 'pass', overflow: 'pass', scripts: 'pass', nojs: 'pass', canonical: 'pass', jsonld: 'pass', axe: 'pass' }, text);
assert.strictEqual(good.canonical.href, `${base}/`);
-- assert.deepStrictEqual(good.jsonld.entities.map((e) => e.found), ['html']);
++ assert.deepStrictEqual(good.jsonld.entities.map((e) => e.found), ['html', 'html'], 'a list folded in a closed <details> counts as on the page');
assert.deepStrictEqual(bad.checks, { status: 'pass', errors: 'fail', overflow: 'fail', scripts: 'fail', nojs: 'fail', canonical: 'fail', jsonld: 'fail', axe: 'fail' }, text);
assert.ok(bad.errors.some((e) => e.startsWith('console: boom from b (')), bad.errors.join(' | '));