@bongos/core 1.19.929 → 1.19.931
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 +45 -20
- package/docs/copy-inventory.md +35 -7
- package/docs/copy-registry.json +352 -9
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/sky.css +365 -0
- package/modules/hall-ui/public/sky.html +79 -0
- package/modules/hall-ui/public/sky.js +580 -0
- package/modules/hall-ui/public/sky.states.json +20 -0
- package/modules/hall-ui/public/style.css +10 -0
- package/modules/hall-ui/public/thinking.css +0 -9
- package/modules/hall-ui/public/thinking.html +2 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/bongos/serve-internal.js +6 -1
- package/src/module-api.js +1 -1
- package/tests/hall_board_world.mjs +32 -0
- package/tests/hall_page_gate_map.mjs +5 -0
- package/tests/hall_sky.mjs +458 -0
- package/tests/helpers.mjs +121 -0
package/tests/helpers.mjs
CHANGED
|
@@ -855,3 +855,124 @@ export function bootThinkingPage({ pages = [], viewer = { id: 95 }, meStatus = 2
|
|
|
855
855
|
filter: (id) => { tabState.active = id; if (tabState.onChange) tabState.onChange(id); },
|
|
856
856
|
};
|
|
857
857
|
}
|
|
858
|
+
|
|
859
|
+
// bootSkyPage — boot the REAL modules/hall-ui/public/sky.js in a vm against a
|
|
860
|
+
// stub DOM, and hand back the field, the panel and the legend it wrote plus
|
|
861
|
+
// every request it made.
|
|
862
|
+
//
|
|
863
|
+
// The fourth sibling of bootProfilePage / bootIdeaPage / bootThinkingPage, and
|
|
864
|
+
// here for the reason the third one is: THE SKY (task 1004105 / BV2.R26) is a
|
|
865
|
+
// DRAWING of facts that are all correct upstream, and the only place it can go
|
|
866
|
+
// wrong is the last step. A glyph is geometry, so the questions this can ask
|
|
867
|
+
// that no server test can are: does a remnant keep its diameter and lose its
|
|
868
|
+
// fill, does an unreadable brightness leave a star lit, does the page draw a
|
|
869
|
+
// second compression curve of its own, and does every thought carry its whole
|
|
870
|
+
// sentence for a reader who cannot see the picture.
|
|
871
|
+
//
|
|
872
|
+
// THE REAL idea-objects.js IS LOADED INTO THE SAME SANDBOX, never stubbed —
|
|
873
|
+
// the same rule bootThinkingPage keeps, and for the sharper reason here: the
|
|
874
|
+
// pair exists so the sky and the room cannot call one object two names, and a
|
|
875
|
+
// suite that stubbed the vocabulary would assert the sky says whatever the
|
|
876
|
+
// suite told it to.
|
|
877
|
+
const SKY_JS = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/sky.js'), 'utf8');
|
|
878
|
+
export function bootSkyPage({
|
|
879
|
+
pages = [], viewer = { id: 95 }, meStatus = 200, trailStatus = 200,
|
|
880
|
+
goals = null, criteria = {},
|
|
881
|
+
} = {}) {
|
|
882
|
+
const els = new Map();
|
|
883
|
+
const listeners = new Map();
|
|
884
|
+
const makeEl = (id) => ({
|
|
885
|
+
dataset: {}, style: {}, textContent: '', hidden: false, _html: '',
|
|
886
|
+
classList: { add() {}, remove() {}, toggle() { return false; }, contains() { return false; } },
|
|
887
|
+
setAttribute() {}, getAttribute() { return null; },
|
|
888
|
+
addEventListener(type, fn) { listeners.set(`${id}:${type}`, fn); },
|
|
889
|
+
querySelector() { return null; }, querySelectorAll() { return []; }, appendChild() {},
|
|
890
|
+
set innerHTML(v) { this._html = String(v); }, get innerHTML() { return this._html; },
|
|
891
|
+
});
|
|
892
|
+
const documentObj = {
|
|
893
|
+
title: '',
|
|
894
|
+
body: { dataset: { page: 'sky' } },
|
|
895
|
+
documentElement: { dataset: {}, style: {}, classList: { add() {}, remove() {} } },
|
|
896
|
+
getElementById(id) { if (!els.has(id)) els.set(id, makeEl(id)); return els.get(id); },
|
|
897
|
+
querySelector(sel) { return this.getElementById(String(sel).replace(/^#/, '')); },
|
|
898
|
+
querySelectorAll() { return []; },
|
|
899
|
+
createElement() { return makeEl('new'); },
|
|
900
|
+
addEventListener() {},
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
const requests = [];
|
|
904
|
+
const client = {
|
|
905
|
+
request: async (method, url) => {
|
|
906
|
+
requests.push(url);
|
|
907
|
+
if (/\/me$/.test(url)) {
|
|
908
|
+
return meStatus === 200
|
|
909
|
+
? { status: 200, ok: true, data: { builder: viewer } }
|
|
910
|
+
: { status: meStatus, ok: false, data: null };
|
|
911
|
+
}
|
|
912
|
+
// The two well reads. `goals: null` is a route that could not be read at
|
|
913
|
+
// all, which must leave the wells named by their id rather than blank;
|
|
914
|
+
// `criteria` absent for a goal is "not read", which must leave that well
|
|
915
|
+
// with no rings rather than zero of them.
|
|
916
|
+
const one = /\/goals\/(\d+)$/.exec(url);
|
|
917
|
+
if (one) {
|
|
918
|
+
const list = criteria[one[1]];
|
|
919
|
+
return list === undefined
|
|
920
|
+
? { status: 404, ok: false, data: null }
|
|
921
|
+
: { status: 200, ok: true, data: { goal: { id: one[1] }, criteria: list } };
|
|
922
|
+
}
|
|
923
|
+
if (/\/goals$/.test(url)) {
|
|
924
|
+
return goals === null
|
|
925
|
+
? { status: 500, ok: false, data: null }
|
|
926
|
+
: { status: 200, ok: true, data: { goals } };
|
|
927
|
+
}
|
|
928
|
+
if (trailStatus !== 200) return { status: trailStatus, ok: false, data: null };
|
|
929
|
+
const offset = Number((/offset=(\d+)/.exec(url) || [])[1] || 0);
|
|
930
|
+
const page = pages.find((p) => Number(p.offset || 0) === offset) || { ideas: [], total: 0 };
|
|
931
|
+
return { status: 200, ok: true, data: page };
|
|
932
|
+
},
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
const windowObj = {
|
|
936
|
+
__BRANDING__: {}, __MODULES__: { enabled: {} },
|
|
937
|
+
BongosClient: { createClient: () => client },
|
|
938
|
+
CSS: { escape: (s) => String(s) },
|
|
939
|
+
OTB: {
|
|
940
|
+
escapeHtml: (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])),
|
|
941
|
+
$: (sel) => documentObj.querySelector(sel),
|
|
942
|
+
fmtDate: (iso) => String(iso ?? '').slice(0, 10),
|
|
943
|
+
toast() {},
|
|
944
|
+
},
|
|
945
|
+
location: { hostname: 'builders.cloudbongos.com', search: '', pathname: '/sky', hash: '', assign() {} },
|
|
946
|
+
localStorage: { getItem: () => null, setItem() {} },
|
|
947
|
+
addEventListener() {},
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
const sandbox = {
|
|
951
|
+
window: windowObj, document: documentObj, location: windowObj.location,
|
|
952
|
+
console, setTimeout, clearTimeout, URLSearchParams, Math, Number,
|
|
953
|
+
};
|
|
954
|
+
sandbox.globalThis = sandbox;
|
|
955
|
+
vm.createContext(sandbox);
|
|
956
|
+
vm.runInContext(IDEA_OBJECTS_JS, sandbox, { filename: 'idea-objects.js' });
|
|
957
|
+
vm.runInContext(SKY_JS, sandbox, { filename: 'sky.js' });
|
|
958
|
+
|
|
959
|
+
return {
|
|
960
|
+
requests,
|
|
961
|
+
objects: () => windowObj.OTBIdeaObjects,
|
|
962
|
+
field: () => documentObj.getElementById('sky-map').innerHTML,
|
|
963
|
+
panel: () => documentObj.getElementById('sky-panel').innerHTML,
|
|
964
|
+
legend: () => documentObj.getElementById('sky-legend').innerHTML,
|
|
965
|
+
sub: () => documentObj.getElementById('sky-sub').textContent,
|
|
966
|
+
foot: () => documentObj.getElementById('sky-foot'),
|
|
967
|
+
// Picking is the page's only control, and it is DELEGATED — one listener on
|
|
968
|
+
// the field for a trail of 300 bodies — so the suite drives it the way a
|
|
969
|
+
// click does rather than by calling an internal the page does not export.
|
|
970
|
+
pick: (ideaId) => {
|
|
971
|
+
const fn = listeners.get('sky-map:click');
|
|
972
|
+
if (!fn) throw new Error('the field wired no click listener');
|
|
973
|
+
fn({ target: { closest: (sel) => (sel === '[data-idea]'
|
|
974
|
+
? { getAttribute: () => String(ideaId) }
|
|
975
|
+
: null) } });
|
|
976
|
+
},
|
|
977
|
+
};
|
|
978
|
+
}
|