@bongos/core 1.21.66 → 1.21.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +111 -41
- package/docs/copy-inventory.md +414 -386
- package/docs/copy-registry.json +815 -537
- package/docs/file-map.md +1 -0
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +45 -12
- package/docs/page-readings.json +959 -907
- package/modules/platform-identity/routes/my-projects.js +1 -1
- package/modules/public-landing/public/account.html +1 -1
- package/modules/public-landing/public/assets/cosmos.css +12 -10
- package/modules/public-landing/public/contact.html +1 -1
- package/modules/public-landing/public/guild.html +1 -1
- package/modules/public-landing/public/index-cli.states.json +20 -0
- package/modules/public-landing/public/index.html +68 -1
- package/modules/public-landing/public/index.states.json +4 -4
- package/modules/public-landing/public/invitations-empty.states.json +56 -0
- package/modules/public-landing/public/invitations-picker.states.json +84 -0
- package/modules/public-landing/public/invitations.html +965 -0
- package/modules/public-landing/public/invitations.probes.json +430 -0
- package/modules/public-landing/public/invitations.states.json +473 -0
- package/modules/public-landing/public/privacy.html +1 -1
- package/modules/public-landing/public/projects.html +18 -543
- package/modules/public-landing/public/projects.probes.json +0 -29
- package/modules/public-landing/public/projects.states.json +0 -6
- package/modules/public-landing/public/terms.html +1 -1
- package/modules/ui-design/kit/fixtures/bongos-cli-latest-sample.json +10 -0
- package/modules/ui-design/kit/fixtures/featured-invitations.json +183 -0
- package/modules/ui-design/kit/fixtures/guilds-empty.json +1 -0
- package/modules/ui-design/kit/fixtures/me-guild-engagements-empty.json +1 -0
- package/modules/ui-design/kit/fixtures/me-guild-requests-empty.json +1 -0
- package/modules/ui-design/kit/fixtures/my-projects-applied.json +29 -0
- package/modules/ui-design/kit/fixtures/my-projects-invites-empty.json +1 -0
- package/modules/ui-design/kit/serve.js +5 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -0
- package/src/module-api.js +1 -1
- package/src/platform-server.js +11 -0
- package/tests/hub_account_page.mjs +1 -1
- package/tests/hub_engagement_cards.mjs +44 -40
- package/tests/hub_guild_cards.mjs +24 -22
- package/tests/hub_invitations_page.mjs +429 -0
- package/tests/join_relay_outcome.mjs +1 -1
- package/tests/landing_legal_pages.mjs +8 -6
- package/tests/landing_page.mjs +125 -3
- package/tests/my_projects_surface.mjs +14 -6
- package/tests/public_landing_projects.mjs +12 -14
- package/tests/render_check.mjs +3 -2
- package/tests/ui_design_kit.mjs +3 -3
package/tests/landing_page.mjs
CHANGED
|
@@ -35,6 +35,7 @@ import { test } from 'node:test';
|
|
|
35
35
|
import assert from 'node:assert/strict';
|
|
36
36
|
import fs from 'node:fs';
|
|
37
37
|
import path from 'node:path';
|
|
38
|
+
import vm from 'node:vm';
|
|
38
39
|
import { fileURLToPath } from 'node:url';
|
|
39
40
|
import { createRequire } from 'node:module';
|
|
40
41
|
|
|
@@ -566,15 +567,16 @@ test('the Projects band deep-links the hub\'s views; About and Docs are footer l
|
|
|
566
567
|
assert.doesNotMatch(body.split('<main')[0], /aria-current/, 'the landing is none of those views');
|
|
567
568
|
// the profile band: the person, My projects, Account, Sign out as the honest anchor.
|
|
568
569
|
// Account fills the slot that waited for a settings page (task 1004259) and is
|
|
569
|
-
// apex-only, because /account is served only where platform-identity runs
|
|
570
|
+
// apex-only, because /account is served only where platform-identity runs; so is
|
|
571
|
+
// Invitations, in the same region, for /invitations (task 1004276).
|
|
570
572
|
assert.match(body, /<div class="menuBand" id="menuProfile" data-menu="profile" hidden>/);
|
|
571
573
|
assert.match(body, /<p class="bandWho" id="bandWho"><\/p>/);
|
|
572
574
|
assert.match(body, /<a class="bandT" href="\/projects\?view=mine">My projects<\/a>/);
|
|
573
|
-
assert.match(body, /<!--apex-only:start--><li class="bandCell"><a class="bandT" href="\/account">Account<\/a><\/li><!--apex-only:end-->/);
|
|
575
|
+
assert.match(body, /<!--apex-only:start--><li class="bandCell"><a class="bandT" href="\/invitations">Invitations<\/a><\/li><li class="bandCell"><a class="bandT" href="\/account">Account<\/a><\/li><!--apex-only:end-->/);
|
|
574
576
|
assert.doesNotMatch(body, /class="bandSlot"/, 'the slot is filled, not kept beside its item');
|
|
575
577
|
assert.match(body, /<a class="bandT signout" href="\/api\/bongos\/auth\/logout">Sign out<\/a>/);
|
|
576
578
|
// a crawler reads every destination without scripting on
|
|
577
|
-
for (const copy of ['Sky', 'Table', 'Your projects', 'New project', 'About', 'Docs', 'My projects', 'Account', 'Sign out']) {
|
|
579
|
+
for (const copy of ['Sky', 'Table', 'Your projects', 'New project', 'About', 'Docs', 'My projects', 'Invitations', 'Account', 'Sign out']) {
|
|
578
580
|
assert.ok(body.includes('>' + copy + '<'), `"${copy}" is only reachable with scripting on`);
|
|
579
581
|
}
|
|
580
582
|
// the menu container is .menuBand: .band is this page's own content sections
|
|
@@ -614,3 +616,123 @@ test('the retired gate assets (world/assets/clouds|creatures|plates) are gone
|
|
|
614
616
|
// the chrome landing's own plates (task 1003298) live at assets/world/ and are untouched by this cleanup
|
|
615
617
|
assert.ok(fs.existsSync(path.join(LANDING, 'assets', 'world', 'r2-bongos-chrome-b.jpg')), 'the chrome plate at assets/world/ is untouched (task 1003649 converts it separately)');
|
|
616
618
|
});
|
|
619
|
+
|
|
620
|
+
// ── the CLI download (task 1004257) ─────────────────────────────────────────
|
|
621
|
+
// A door that only exists where a release does: /downloads/bongos/* mounts only when the
|
|
622
|
+
// instance has config/bongos-cli.json, and cloudbongos.com had none when this shipped, so a
|
|
623
|
+
// baked link would have been a door to a 404. The block is markup, hidden, and the release
|
|
624
|
+
// feed is what opens it. The platform pick is RUN below in a vm, not read.
|
|
625
|
+
|
|
626
|
+
const CLOSE = HTML.replace(/\r\n/g, '\n').split('<section class="band close">')[1].split('</section>')[0];
|
|
627
|
+
const CODE_LF = CODE.replace(/\r\n/g, '\n');
|
|
628
|
+
const CLI_JS = CODE_LF.slice(CODE_LF.indexOf('var CLI_NAMES'), CODE_LF.indexOf('box.hidden = false;\n });') + 'box.hidden = false;\n });'.length);
|
|
629
|
+
|
|
630
|
+
test('the CLI block is markup in the closing band, hidden, with a door that has no target until the feed names one', () => {
|
|
631
|
+
assert.match(CLOSE, /<div class="cli" data-cli hidden>/, 'baked hidden: no release, no door');
|
|
632
|
+
const get = CLOSE.match(/<a class="door door--solo" data-cli-get([^>]*)>/);
|
|
633
|
+
assert.ok(get, 'the download door is a door');
|
|
634
|
+
assert.doesNotMatch(get[1], /href=/, 'no baked href: the page cannot know the release or the platform');
|
|
635
|
+
assert.match(get[1], /aria-describedby="cliFor"/, 'the door is described by the platform and version it picked');
|
|
636
|
+
assert.match(CLOSE, /<p class="label" id="cliFor" data-cli-for><\/p>/);
|
|
637
|
+
assert.match(CLOSE, /<p class="cliAlso" data-cli-also><\/p>/);
|
|
638
|
+
assert.ok(CLOSE.indexOf('data-cli') > CLOSE.indexOf('class="doorbar"'), 'it sits under the two doors, never beside them');
|
|
639
|
+
assert.doesNotMatch(HTML.split('<section class="hero">')[1].split('</section>')[0], /data-cli/, 'the hero keeps its two doors');
|
|
640
|
+
// [hidden] loses to any display rule on the element, so the container must carry none
|
|
641
|
+
assert.doesNotMatch(PAGE_CSS, /\n\.cli\{[^}]*display/, '.cli sets no display, or [hidden] stops hiding it');
|
|
642
|
+
assert.match(PAGE_CSS, /\.cliAlso a\{display:inline-block;min-height:24px;/, 'the platform links clear the 24px floor');
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
test('the CLI feed is the apex release redirect, and every link stays on this origin', () => {
|
|
646
|
+
assert.ok(CODE.includes("json('/downloads/bongos/latest.json')"), 'the page reads the release feed');
|
|
647
|
+
assert.match(CLI_JS, /get\.href = '\/downloads\/bongos\/' \+ pick;/);
|
|
648
|
+
assert.match(CLI_JS, /a\.href = '\/downloads\/bongos\/' \+ k;/);
|
|
649
|
+
assert.doesNotMatch(CLI_JS, /\.url\b/, 'never the release asset URL: the redirect is how a release bump stays one config file');
|
|
650
|
+
assert.doesNotMatch(CLI_JS, /innerHTML/);
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// run the region in a vm over a DOM stub: the release feed in, the block's state out
|
|
654
|
+
function cliRun({ feed, nav }) {
|
|
655
|
+
const el = (tag) => ({
|
|
656
|
+
tag, href: null, hidden: false, textContent: '', children: [], removed: false,
|
|
657
|
+
appendChild(c) { this.children.push(c); return c; },
|
|
658
|
+
remove() { this.removed = true; },
|
|
659
|
+
});
|
|
660
|
+
const get = el('a');
|
|
661
|
+
const forEl = el('p');
|
|
662
|
+
const also = el('p');
|
|
663
|
+
const box = el('div');
|
|
664
|
+
box.hidden = true;
|
|
665
|
+
box.querySelector = (s) => ({ '[data-cli-get]': get, '[data-cli-for]': forEl, '[data-cli-also]': also })[s];
|
|
666
|
+
let pending;
|
|
667
|
+
const sandbox = {
|
|
668
|
+
navigator: nav,
|
|
669
|
+
document: {
|
|
670
|
+
querySelector: (s) => (s === '[data-cli]' ? box : null),
|
|
671
|
+
createElement: el,
|
|
672
|
+
createTextNode: (t) => ({ tag: '#text', textContent: t }),
|
|
673
|
+
},
|
|
674
|
+
json: (url) => { assert.equal(url, '/downloads/bongos/latest.json'); pending = Promise.resolve(feed); return pending; },
|
|
675
|
+
};
|
|
676
|
+
vm.runInNewContext(CLI_JS + '\nthis.cliTarget = cliTarget;', sandbox);
|
|
677
|
+
return pending.then(() => ({ box, get, forEl, also, cliTarget: sandbox.cliTarget }));
|
|
678
|
+
}
|
|
679
|
+
const RELEASE = JSON.parse(fs.readFileSync(path.join(ROOT, 'modules', 'ui-design', 'kit', 'fixtures', 'bongos-cli-latest-sample.json'), 'utf8'));
|
|
680
|
+
const MAC = { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.89 Safari/537.36', platform: 'MacIntel', maxTouchPoints: 0 };
|
|
681
|
+
const IPHONE = { userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1', platform: 'iPhone', maxTouchPoints: 5 };
|
|
682
|
+
|
|
683
|
+
test('with a release, a Mac gets the Apple-silicon door and every other platform beside it', async () => {
|
|
684
|
+
const r = await cliRun({ feed: RELEASE, nav: MAC });
|
|
685
|
+
assert.equal(r.box.hidden, false);
|
|
686
|
+
assert.equal(r.get.removed, false);
|
|
687
|
+
assert.equal(r.get.href, '/downloads/bongos/mac-arm64');
|
|
688
|
+
assert.equal(r.forEl.textContent, 'macOS, Apple silicon · v0.4.2');
|
|
689
|
+
assert.equal(r.also.children[0].textContent, 'Also for');
|
|
690
|
+
assert.deepEqual(r.also.children.slice(1).map((a) => [a.href, a.textContent]), [
|
|
691
|
+
['/downloads/bongos/mac-x64', 'macOS, Intel'],
|
|
692
|
+
['/downloads/bongos/linux-x64', 'Linux, x64'],
|
|
693
|
+
['/downloads/bongos/linux-arm64', 'Linux, ARM64'],
|
|
694
|
+
['/downloads/bongos/win-x64', 'Windows'],
|
|
695
|
+
]);
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
test('a phone gets no guess: no door, the whole list', async () => {
|
|
699
|
+
const r = await cliRun({ feed: RELEASE, nav: IPHONE });
|
|
700
|
+
assert.equal(r.box.hidden, false);
|
|
701
|
+
assert.equal(r.get.removed, true, 'a CLI cannot run on the device that is looking');
|
|
702
|
+
assert.equal(r.forEl.textContent, 'Download the CLI · v0.4.2');
|
|
703
|
+
assert.equal(r.also.children[0].textContent, 'For');
|
|
704
|
+
assert.equal(r.also.children.length, 6);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test('no release (the feed 404s, or answers nothing usable) leaves the block hidden', async () => {
|
|
708
|
+
for (const feed of [null, {}, { version: '1.0.0' }, { version: '1.0.0', assets: {} }, { assets: 'x' }]) {
|
|
709
|
+
const r = await cliRun({ feed, nav: MAC });
|
|
710
|
+
assert.equal(r.box.hidden, true, JSON.stringify(feed));
|
|
711
|
+
assert.equal(r.get.href, null);
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
test('a target key that is not a plain slug never becomes a link; a malformed version is dropped', async () => {
|
|
716
|
+
const feed = { version: '1.0.0<b>', assets: { '../../etc': {}, 'javascript:x': {}, 'Mac-ARM64': {}, 'linux-x64': {} } };
|
|
717
|
+
const r = await cliRun({ feed, nav: MAC });
|
|
718
|
+
assert.equal(r.get.removed, true, 'no Mac build in this release, so no door for a Mac');
|
|
719
|
+
assert.equal(r.forEl.textContent, 'Download the CLI');
|
|
720
|
+
assert.deepEqual(r.also.children.slice(1).map((a) => a.href), ['/downloads/bongos/linux-x64']);
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
test('the platform pick', async () => {
|
|
724
|
+
const { cliTarget } = await cliRun({ feed: null, nav: MAC });
|
|
725
|
+
const all = ['mac-arm64', 'mac-x64', 'linux-x64', 'linux-arm64', 'win-x64'];
|
|
726
|
+
const ua = (s, extra) => Object.assign({ userAgent: s, platform: '', maxTouchPoints: 0 }, extra);
|
|
727
|
+
assert.equal(cliTarget(MAC, all), 'mac-arm64', 'a Mac: Apple silicon, since a user agent cannot say');
|
|
728
|
+
assert.equal(cliTarget(MAC, ['mac-x64', 'linux-x64']), 'mac-x64', 'a release with only the Intel build still serves a Mac');
|
|
729
|
+
assert.equal(cliTarget(ua('Mozilla/5.0 (Windows NT 10.0; Win64; x64)', { platform: 'Win32' }), all), 'win-x64');
|
|
730
|
+
assert.equal(cliTarget(ua('Mozilla/5.0 (X11; Linux x86_64)', { platform: 'Linux x86_64' }), all), 'linux-x64');
|
|
731
|
+
assert.equal(cliTarget(ua('Mozilla/5.0 (X11; Linux aarch64)', { platform: 'Linux aarch64' }), all), 'linux-arm64');
|
|
732
|
+
assert.equal(cliTarget(ua('Mozilla/5.0 (X11; CrOS x86_64 14541.0.0)'), all), 'linux-x64', 'ChromeOS runs the Linux build');
|
|
733
|
+
assert.equal(cliTarget(ua('x', { userAgentData: { platform: 'macOS', mobile: false } }), all), 'mac-arm64', 'client hints are read first');
|
|
734
|
+
assert.equal(cliTarget(ua('Mozilla/5.0 (Linux; Android 14; Pixel 8) Mobile', { platform: 'Linux armv8l' }), all), null, 'Android says Linux and is not');
|
|
735
|
+
assert.equal(cliTarget(IPHONE, all), null);
|
|
736
|
+
assert.equal(cliTarget(Object.assign({}, MAC, { maxTouchPoints: 5 }), all), null, 'an iPad reports a Mac; touch gives it away');
|
|
737
|
+
assert.equal(cliTarget(ua('Mozilla/5.0 (Windows NT 10.0; Win64; x64)'), ['mac-arm64']), null, 'nothing built for this platform: no guess');
|
|
738
|
+
});
|
|
@@ -21,9 +21,10 @@
|
|
|
21
21
|
// audit could not confirm, so it is asserted here rather than described.
|
|
22
22
|
// 3. WHAT WAS STILL MISSING. The invitations half had no caller anywhere — no
|
|
23
23
|
// surface fetched the invite list, so a builder holding an invitation could
|
|
24
|
-
// not act on it. Closed by task 1003774
|
|
25
|
-
//
|
|
26
|
-
//
|
|
24
|
+
// not act on it. Closed by task 1003774, which put the list in the hub's
|
|
25
|
+
// /projects?view=mine (idea 1000903); task 1004276 moved it to the hub's own
|
|
26
|
+
// /invitations page. The pin below flipped from "no surface calls this" to
|
|
27
|
+
// "some surface does" for the same reason.
|
|
27
28
|
//
|
|
28
29
|
// Static reads only (no import of the app, no DB) → runs in the `unit` gate.
|
|
29
30
|
//
|
|
@@ -116,10 +117,17 @@ test('an invitations surface exists — the hub reads GET /my-projects/invites (
|
|
|
116
117
|
// dead end the moment a caller exists to press it. Each invite renders as a
|
|
117
118
|
// way IN (a link to the project) instead — signing in there is the acceptance
|
|
118
119
|
// act (task 1002969).
|
|
120
|
+
// Both hub pages: /invitations holds the invite list now (task 1004276), and
|
|
121
|
+
// /projects is where it lived and where a regression could put a caller back.
|
|
122
|
+
const HUB_PAGES = ['modules/public-landing/public/invitations.html', 'modules/public-landing/public/projects.html'];
|
|
119
123
|
test('the hub never calls the accept route — ADR 0335 retired that flip', () => {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
for (const rel of HUB_PAGES) {
|
|
125
|
+
assert.doesNotMatch(read(rel), /invites\/[^'"]*\/accept/,
|
|
126
|
+
`${rel}: a hub caller of the accept route reopens the dead end ADR 0335 closed — render the invite as a link into the project instead`);
|
|
127
|
+
}
|
|
128
|
+
// the guard is only meaningful where the invite list is: it must be on one of these pages
|
|
129
|
+
assert.ok(HUB_PAGES.some((rel) => read(rel).includes("'/my-projects/invites'")),
|
|
130
|
+
'the invite list moved off both hub pages — point this guard at wherever it went');
|
|
123
131
|
});
|
|
124
132
|
|
|
125
133
|
// Task 1002818 (ADR 0353) finished the retirement on the server: the route is gone,
|
|
@@ -521,28 +521,26 @@ test('a stamped asset still serves — the query string is not part of the filen
|
|
|
521
521
|
// nowhere to live until now. loadMemberships() already fetched GET /my-projects
|
|
522
522
|
// for the map's Apply button (R10, task 1002286) — this just renders the rest
|
|
523
523
|
// of what that same read carries, plus the separate invites list.
|
|
524
|
-
|
|
524
|
+
// The invitations and the join-by-address field moved to their own page with task
|
|
525
|
+
// 1004276 (the owner's call, ADR 0337 D5); tests/hub_invitations_page.mjs holds that
|
|
526
|
+
// page as served. What stays here: building-on with Leave, and a door to the page.
|
|
527
|
+
test('#view-mine keeps building-on with Leave, and points at /invitations for the invitations and the join field', async () => {
|
|
525
528
|
const { body } = await request('/projects', 'game.test.local');
|
|
526
|
-
assert.match(body, /\/my-projects\/invites/, 'GET /my-projects/invites must be called');
|
|
527
|
-
assert.match(body, /id="invitesList"/);
|
|
528
529
|
assert.match(body, /id="buildingList"/);
|
|
529
|
-
assert.match(body, /\/my-projects\/join/, 'the join-by-URL field must post to /my-projects/join');
|
|
530
|
-
assert.match(body, /id="joinOrigin"/);
|
|
531
|
-
assert.match(body, /id="joinNote"/, 'the applicant note (task 1002330) rides along, and stays optional');
|
|
532
530
|
assert.match(body, /\/my-projects\/'\s*\+\s*encodeURIComponent/, 'Leave must address the project by its own client id');
|
|
533
|
-
|
|
534
|
-
|
|
531
|
+
for (const gone of ['invitesList', 'guildInviteList', 'engageList', 'guildRequestList', 'joinOrigin', 'joinNote', 'joinBtn', 'mineInvites']) {
|
|
532
|
+
assert.doesNotMatch(body, new RegExp(`id="${gone}"`), `#${gone} moved to /invitations`);
|
|
533
|
+
}
|
|
534
|
+
assert.doesNotMatch(body, /\/my-projects\/invites/, 'the invitations are read on their own page now');
|
|
535
|
+
assert.match(body, /<h2 id="mineToInvitesH">Invitations<\/h2>\s*<p class="lede">[^<]*<a href="\/invitations">Open your invitations<\/a><\/p>/, 'the mine view says where they went');
|
|
536
|
+
assert.match(body, /\/my-projects\/join/, 'the map card’s Apply to join still posts the join relay');
|
|
535
537
|
});
|
|
536
538
|
|
|
537
|
-
test('
|
|
539
|
+
test('the hub never calls the retired accept flip (ADR 0335)', async () => {
|
|
538
540
|
const { body } = await request('/projects', 'game.test.local');
|
|
539
541
|
// the hub-only accept flip never admits anyone to the project's own instance
|
|
540
|
-
// (ADR 0335) — a caller of it here would reopen the exact dead end that ADR
|
|
541
|
-
// retired, so the invite's action is an outbound link instead
|
|
542
|
+
// (ADR 0335) — a caller of it here would reopen the exact dead end that ADR retired
|
|
542
543
|
assert.doesNotMatch(body, /invites\/[^'"]*\/accept/, 'no caller of the retired hub accept route');
|
|
543
|
-
assert.match(body, /Open project/, 'the invite links into the project — signing in there is the acceptance act');
|
|
544
|
-
assert.match(body, /'\/my-projects\/invites\/' \+ encodeURIComponent\([^)]+\) \+ '\/decline'/,
|
|
545
|
-
'decline still works: it only clears the hub\'s own pending row');
|
|
546
544
|
});
|
|
547
545
|
|
|
548
546
|
test('the map card\'s Apply button reads as truly inert once applied, with a live status region (R10 fixups)', async () => {
|
package/tests/render_check.mjs
CHANGED
|
@@ -24,8 +24,9 @@ test('a shared asset reaches every page in its dir whose HTML names it', () => {
|
|
|
24
24
|
// sky-data.js is shared by the two doors of one page (task 1004232): /thinking and /goal-map.
|
|
25
25
|
assert.deepEqual(names(['modules/hall-ui/public/sky-data.js']), ['goal-map.states.json', 'thinking.states.json']);
|
|
26
26
|
assert.deepEqual(names(['modules/hall-ui/public/text-fit.js']), ['goals.states.json']);
|
|
27
|
-
// the account page links the hub's sheet too since task 1004259,
|
|
28
|
-
|
|
27
|
+
// the account page links the hub's sheet too since task 1004259, the guild page since task 1002301,
|
|
28
|
+
// and the invitations page since task 1004276
|
|
29
|
+
assert.deepEqual(names(['modules/public-landing/public/assets/cosmos.css']), ['account.states.json', 'guild.states.json', 'invitations.states.json', 'projects.states.json']);
|
|
29
30
|
});
|
|
30
31
|
|
|
31
32
|
test('the page a builder changed comes before the pages a shared file reaches, so the render cap never drops it', () => {
|
package/tests/ui_design_kit.mjs
CHANGED
|
@@ -34,7 +34,7 @@ test('the platform floors are a pinned list — a floor cannot vanish quietly',
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
test('the shipped states files validate and sit beside the page they name', () => {
|
|
37
|
-
for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/projects-empty.states.json', 'modules/public-landing/public/projects-dns-pending.states.json', 'modules/public-landing/public/projects-hall-live.states.json','modules/public-landing/public/index.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/account-private.states.json', 'modules/public-landing/public/guild.states.json', 'modules/hall-ui/public/ranks.states.json']) {
|
|
37
|
+
for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/projects-empty.states.json', 'modules/public-landing/public/projects-dns-pending.states.json', 'modules/public-landing/public/projects-hall-live.states.json','modules/public-landing/public/index.states.json', 'modules/public-landing/public/index-cli.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/account-private.states.json', 'modules/public-landing/public/guild.states.json', 'modules/public-landing/public/invitations.states.json', 'modules/public-landing/public/invitations-empty.states.json', 'modules/public-landing/public/invitations-picker.states.json', 'modules/hall-ui/public/ranks.states.json']) {
|
|
38
38
|
const json = readJson(rel);
|
|
39
39
|
const v = lib.validateStatesFile(json);
|
|
40
40
|
assert.deepEqual(v.errors, [], `${rel}: ${v.errors.join('; ')}`);
|
|
@@ -43,14 +43,14 @@ test('the shipped states files validate and sit beside the page they name', () =
|
|
|
43
43
|
}
|
|
44
44
|
// the apex is dark only (task 1003336): its states files name the one mode, and
|
|
45
45
|
// render.js reads it as the default so a plain `--page /` never renders light
|
|
46
|
-
for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/index.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/guild.states.json']) {
|
|
46
|
+
for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/index.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/guild.states.json', 'modules/public-landing/public/invitations.states.json']) {
|
|
47
47
|
assert.deepEqual(readJson(rel).modes, ['dark'], `${rel}: the apex renders dark only`);
|
|
48
48
|
assert.equal(readJson(rel).modeQuery, false, `${rel}: no query walks a second mode`);
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
test('the shipped probes files validate', () => {
|
|
53
|
-
for (const rel of ['modules/public-landing/public/projects.probes.json', 'modules/public-landing/public/index.probes.json', 'modules/public-landing/public/account.probes.json', 'modules/public-landing/public/guild.probes.json']) {
|
|
53
|
+
for (const rel of ['modules/public-landing/public/projects.probes.json', 'modules/public-landing/public/index.probes.json', 'modules/public-landing/public/account.probes.json', 'modules/public-landing/public/guild.probes.json', 'modules/public-landing/public/invitations.probes.json']) {
|
|
54
54
|
const v = lib.validateProbesFile(readJson(rel));
|
|
55
55
|
assert.deepEqual(v.errors, [], `${rel}: ${v.errors.join('; ')}`);
|
|
56
56
|
}
|