@bongos/core 1.24.89 → 1.24.91
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 +28 -23
- package/docs/copy-inventory.md +5 -5
- package/docs/copy-registry.json +5 -5
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-readings.json +195 -195
- package/modules/hall-ui/public/craft-mode.js +3 -1
- package/modules/hall-ui/public/page-notes.css +4 -0
- package/modules/hall-ui/public/page-notes.js +7 -1
- package/modules/hall-ui/public/shell-game.css +23 -13
- package/modules/hall-ui/public/shell-game.js +5 -4
- package/modules/hall-ui/records/start-screen.md +2 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/src/module-api.js +1 -1
- package/tests/hall_game_review_tab.mjs +86 -0
- package/tests/hall_start_screen.mjs +2 -1
- package/tests/page_notes_panel.mjs +20 -0
|
@@ -1063,6 +1063,8 @@
|
|
|
1063
1063
|
spriteSrc: spriteSrc,
|
|
1064
1064
|
// task 1005148: the visor's two reads — the /me the gate saw, and a tool by id.
|
|
1065
1065
|
me: function () { return lastMe; },
|
|
1066
|
-
|
|
1066
|
+
// A tool opens only for the character whose tool it is (task 1005207): the
|
|
1067
|
+
// review sheet is the Artist's, so no other character can open it this way.
|
|
1068
|
+
openTool: function (id) { var t = toolFor(id); if (t && toolsFor(wearing()).indexOf(t) !== -1) loadTool(t).then(function (api) { api.open(); }, function () { /* tool did not load */ }); },
|
|
1067
1069
|
};
|
|
1068
1070
|
})();
|
|
@@ -58,6 +58,10 @@ html.pn-open { overflow: hidden; }
|
|
|
58
58
|
box-shadow: 0 0 0 1px var(--craft, var(--rule)), var(--pn-shadow-pop);
|
|
59
59
|
cursor: pointer;
|
|
60
60
|
}
|
|
61
|
+
/* Game mode (task 1005207): the glass shows only the visor, so the parked tab
|
|
62
|
+
is not drawn. The visor's "Review this page" (R) opens the sheet, and closing
|
|
63
|
+
it leaves nothing at the edge. Classic mode keeps the tab. */
|
|
64
|
+
html[data-game="on"] .pn__tab { display: none; }
|
|
61
65
|
.pn__tab:hover { background: var(--pn-glass); }
|
|
62
66
|
.pn__tab:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
|
|
63
67
|
.pn__tab-icon { width: 18px; height: 18px; }
|
|
@@ -361,7 +361,13 @@
|
|
|
361
361
|
if (tab) {
|
|
362
362
|
tab.setAttribute('aria-expanded', on ? 'false' : 'true');
|
|
363
363
|
tab.setAttribute('aria-label', on ? 'Show the review panel' : 'Hide the review panel');
|
|
364
|
-
|
|
364
|
+
// In game mode the tab is not drawn (page-notes.css, task 1005207), so focus
|
|
365
|
+
// leaves the tucked panel for the page instead of a tab nobody can see.
|
|
366
|
+
if (on && !quiet) {
|
|
367
|
+
if (tab.getClientRects && tab.getClientRects().length === 0) {
|
|
368
|
+
if (sheet.contains(document.activeElement) && document.activeElement.blur) document.activeElement.blur();
|
|
369
|
+
} else tab.focus();
|
|
370
|
+
}
|
|
365
371
|
}
|
|
366
372
|
if (on) save();
|
|
367
373
|
else if (state.pending) { state.pending = false; openDraft(); }
|
|
@@ -63,14 +63,15 @@ html.gs-open { overflow: hidden; }
|
|
|
63
63
|
/* the ring sits inside the row: the focus colour on the edge, a band of the night inside it, so
|
|
64
64
|
one of the two reads on the accent bar as well as on the panel */
|
|
65
65
|
.gs__item:focus-visible { outline: 0; border-radius: var(--press-radius); box-shadow: var(--press-focus); }
|
|
66
|
-
/*
|
|
67
|
-
|
|
66
|
+
/* One thing is lit: Start on the menu, the view Enter takes on the chooser (task 1005206).
|
|
67
|
+
The accent bar under its dark ink, with the key that takes it */
|
|
68
|
+
.gs__item[data-gs="start"], .gs__item--lit {
|
|
68
69
|
background: var(--accent); color: var(--accent-on); border-bottom-color: transparent;
|
|
69
70
|
font-weight: var(--name-weight-lit); box-shadow: var(--accent-glow);
|
|
70
71
|
}
|
|
71
|
-
.gs__item[data-gs="start"]:hover { background: var(--accent-lift); color: var(--accent-on); }
|
|
72
|
-
.gs__item[data-gs="start"]:focus-visible { box-shadow: var(--press-focus), var(--accent-glow); }
|
|
73
|
-
.gs__item[data-gs="start"]::after {
|
|
72
|
+
.gs__item[data-gs="start"]:hover, .gs__item--lit:hover { background: var(--accent-lift); color: var(--accent-on); }
|
|
73
|
+
.gs__item[data-gs="start"]:focus-visible, .gs__item--lit:focus-visible { box-shadow: var(--press-focus), var(--accent-glow); }
|
|
74
|
+
.gs__item[data-gs="start"]::after, .gs__item--lit::after {
|
|
74
75
|
content: "Enter"; padding: 0 var(--ds-space-hair);
|
|
75
76
|
border: var(--line-strong) solid currentColor;
|
|
76
77
|
font-size: var(--ds-text-md); letter-spacing: var(--label-space);
|
|
@@ -85,16 +86,25 @@ html.gs-open { overflow: hidden; }
|
|
|
85
86
|
.gs__foot { padding: var(--ds-space-md) var(--ds-space-lg) 0; border-top: var(--line-strong) solid var(--rule); }
|
|
86
87
|
.gs__line, .gs__note { margin: 0; font-size: var(--ds-text-lg); line-height: 1.5; text-wrap: pretty; color: var(--ink-soft); }
|
|
87
88
|
.gs__note { margin-top: var(--ds-space-xs); color: var(--ink); }
|
|
88
|
-
/* the view chooser in front of the menu (task 1005200)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
/* the view chooser in front of the menu (task 1005200), in the start menu's own shape (task
|
|
90
|
+
1005206, the Helm start-screen mock-up): Game or Classic as two rows, each with one line
|
|
91
|
+
saying what it is. The view Enter takes (last time's, else Game) is the accent bar with its
|
|
92
|
+
key, as Start is; the other is a quiet row on a hairline. Last time's says so. */
|
|
93
|
+
.gs__ask {
|
|
94
|
+
margin: 0; padding: 0 var(--ds-space-lg) var(--ds-space-sm);
|
|
95
|
+
font-family: var(--name-face); font-size: var(--label-size); font-weight: var(--name-weight);
|
|
96
|
+
letter-spacing: var(--label-space); text-transform: var(--name-case); color: var(--ink-soft);
|
|
97
|
+
}
|
|
92
98
|
.gs__ask[hidden] { display: none; }
|
|
93
|
-
.gs__item--view {
|
|
94
|
-
|
|
99
|
+
.gs__item--view {
|
|
100
|
+
position: relative; flex-direction: column; align-items: flex-start; justify-content: center;
|
|
101
|
+
gap: var(--ds-space-hair); padding-top: var(--ds-space-sm); padding-bottom: var(--ds-space-sm);
|
|
102
|
+
}
|
|
103
|
+
.gs__item--view.gs__item--lit::after { position: absolute; right: var(--ds-space-md); top: 50%; transform: translateY(-50%); }
|
|
95
104
|
.gs__view { display: inline-flex; align-items: baseline; gap: var(--ds-space-sm); }
|
|
96
|
-
.gs__sub { font-family: var(--font-body); font-size: var(--ds-text-md); letter-spacing: 0; text-transform: none; color: var(--ink-soft); }
|
|
97
|
-
.gs__last { font-family: var(--font-body); font-size: var(--label-size); letter-spacing: var(--label-space); text-transform: uppercase; color: var(--accent); }
|
|
105
|
+
.gs__sub { font-family: var(--font-body); font-size: var(--ds-text-md); font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--ink-soft); }
|
|
106
|
+
.gs__last { font-family: var(--font-body); font-size: var(--label-size); font-weight: 400; letter-spacing: var(--label-space); text-transform: uppercase; color: var(--accent); }
|
|
107
|
+
.gs__item--lit .gs__sub, .gs__item--lit .gs__last { color: var(--accent-on); }
|
|
98
108
|
.gs__note[hidden] { display: none; }
|
|
99
109
|
|
|
100
110
|
/* the load screen: the week it is showing, a segment per week, the city, and the tip under it */
|
|
@@ -134,15 +134,16 @@
|
|
|
134
134
|
return '<li><button type="button"' + inner + (m.id === 'extras' ? ' aria-expanded="false" aria-controls="gs-extras"' : '') + '>' + esc(m.label) + '</button></li>';
|
|
135
135
|
}
|
|
136
136
|
// The chooser in front of the start screen (task 1005200): game or classic, the view
|
|
137
|
-
// chosen last time marked and focused, so Enter keeps it.
|
|
137
|
+
// chosen last time marked and focused, so Enter keeps it. In the Helm look (task 1005206) the
|
|
138
|
+
// view Enter takes is the lit row, as Start is on the menu: last time's, else Game.
|
|
138
139
|
var VIEWS = [
|
|
139
140
|
{ id: 'game', label: 'Game', sub: 'The city, full screen' },
|
|
140
141
|
{ id: 'classic', label: 'Classic', sub: 'The hall with its sidebar' },
|
|
141
142
|
];
|
|
142
143
|
function lastView() { var v = read('localStorage', KEY); return v === 'on' ? 'game' : v === 'off' ? 'classic' : null; }
|
|
143
144
|
function viewHtml(v) {
|
|
144
|
-
var last = lastView() === v.id;
|
|
145
|
-
return '<li><button type="button" class="gs__item gs__item--view' + (last ? ' gs__item--last' : '') + '" data-gs="view-' + v.id + '">' +
|
|
145
|
+
var last = lastView() === v.id, lit = (lastView() || 'game') === v.id;
|
|
146
|
+
return '<li><button type="button" class="gs__item gs__item--view' + (lit ? ' gs__item--lit' : '') + (last ? ' gs__item--last' : '') + '" data-gs="view-' + v.id + '">' +
|
|
146
147
|
'<span class="gs__view">' + esc(v.label) + (last ? '<span class="gs__last">Last time</span>' : '') + '</span>' +
|
|
147
148
|
'<span class="gs__sub">' + esc(v.sub) + '</span></button></li>';
|
|
148
149
|
}
|
|
@@ -360,7 +361,7 @@
|
|
|
360
361
|
document.addEventListener('keydown', onKey, true);
|
|
361
362
|
document.body.appendChild(root);
|
|
362
363
|
document.documentElement.classList.add('gs-open');
|
|
363
|
-
var first = root.querySelector('.gs__item--
|
|
364
|
+
var first = root.querySelector('.gs__item--lit') || root.querySelector('.gs__item');
|
|
364
365
|
if (first && first.focus) first.focus();
|
|
365
366
|
return true;
|
|
366
367
|
}
|
|
@@ -27,3 +27,5 @@ Tests: `tests/hall_start_screen.mjs` (the hand-off and pure parts in a vm; both
|
|
|
27
27
|
## The view chooser (task 1005200, owner 2026-11-11)
|
|
28
28
|
|
|
29
29
|
Every sign-in now opens on a chooser before the start screen: **Game** or **Classic**, each with one line saying what it is. The view chosen last time (the browser's `hall-game` copy) is marked "Last time", lit with the accent on its edge, and focused, so Enter keeps it. Game goes on to the start screen as before; Classic closes the screen and the hall is as it always was. Either choice is saved to the account (`PATCH /api/bongos/me/hall-view`). The Extras list lost The docs: it is not a game place. Tests: `tests/hall_start_screen.mjs`.
|
|
30
|
+
|
|
31
|
+
**In the start menu's shape (task 1005206, owner 2026-11-11, from the V3 Helm start-screen mock-up).** The chooser is drawn like the menu it leads to: "How do you want to see it?" is a small label in the name voice, and the view Enter takes (last time's, else Game) is the accent bar with its "Enter" key, exactly as Start is (`.gs__item--lit` shares Start's rules); the other view is a quiet row on a hairline. Each row keeps its one line; on the lit bar the line and the "Last time" tag take `--accent-on`. Focus starts on the lit row.
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.91",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.24.
|
|
9
|
+
"version": "1.24.91",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.91",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/release-notes.json
CHANGED
|
@@ -11637,5 +11637,17 @@
|
|
|
11637
11637
|
"id": "1005203",
|
|
11638
11638
|
"text": "In the game, the visor now shows four small bars for how much of the current version is built, and every main button in the game now belongs on the visor."
|
|
11639
11639
|
}
|
|
11640
|
+
],
|
|
11641
|
+
"1.24.90": [
|
|
11642
|
+
{
|
|
11643
|
+
"id": "1005207",
|
|
11644
|
+
"text": "In the game view the Artist's feedback tab no longer sits on the screen; the Artist opens the feedback sheet from the visor, and only the Artist can open it."
|
|
11645
|
+
}
|
|
11646
|
+
],
|
|
11647
|
+
"1.24.91": [
|
|
11648
|
+
{
|
|
11649
|
+
"id": "1005206",
|
|
11650
|
+
"text": "The screen you land on after signing in, where you pick Game or Classic, now looks like the V3 game start menu: your usual choice is the bright salmon bar with its Enter key, the other a quiet row."
|
|
11651
|
+
}
|
|
11640
11652
|
]
|
|
11641
11653
|
}
|
package/src/module-api.js
CHANGED
|
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
|
|
|
81
81
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
82
82
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
83
83
|
|
|
84
|
-
const CORE_VERSION = '1.24.
|
|
84
|
+
const CORE_VERSION = '1.24.91'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
85
85
|
|
|
86
86
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
87
87
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// tests/hall_game_review_tab.mjs — no parked review tab on the game's glass (task 1005207).
|
|
2
|
+
//
|
|
3
|
+
// Game mode (html[data-game="on"]) shows only the visor, so the Artist's docked review
|
|
4
|
+
// sheet (page-notes.js + page-notes.css) draws no tab at the right edge. The visor's
|
|
5
|
+
// "Review this page" (R) still opens the sheet, and closing it leaves nothing behind.
|
|
6
|
+
// Classic mode keeps the tab exactly as it was. Driven in a real browser over the
|
|
7
|
+
// REAL page-notes.js and the hall's real sheets.
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { test, after } from 'node:test';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
17
|
+
const HALL = path.join(ROOT, 'modules/hall-ui/public');
|
|
18
|
+
|
|
19
|
+
const lib = require(path.join(ROOT, 'modules', 'ui-design', 'kit', 'lib.js'));
|
|
20
|
+
let browser = null;
|
|
21
|
+
try { browser = await lib.launchBrowser(); } catch (e) { if (!(e instanceof lib.NoBrowserError)) throw e; }
|
|
22
|
+
after(() => browser && browser.close());
|
|
23
|
+
const skip = !browser && 'no system Edge or Chrome';
|
|
24
|
+
|
|
25
|
+
const ORIGIN = 'http://hall.test';
|
|
26
|
+
const TYPES = { '.js': 'text/javascript', '.css': 'text/css' };
|
|
27
|
+
const PAGE = (game) => `<!doctype html><html data-theme="dark"${game ? ' data-game="on"' : ''}><head><meta charset="utf-8">
|
|
28
|
+
<link rel="stylesheet" href="/builders/style.css"></head>
|
|
29
|
+
<body data-page="home"><button id="before">page</button>
|
|
30
|
+
<script>window.OTB = { escapeHtml: (s) => String(s == null ? '' : s).replace(/[&<>"']/g, (c) => '&#' + c.charCodeAt(0) + ';') };</script>
|
|
31
|
+
<script src="/builders/page-notes.js"></script></body></html>`;
|
|
32
|
+
|
|
33
|
+
async function open(game) {
|
|
34
|
+
const ctx = await browser.newContext({ viewport: { width: 1280, height: 800 } });
|
|
35
|
+
await ctx.route(ORIGIN + '/**', (route) => {
|
|
36
|
+
const p = new URL(route.request().url()).pathname;
|
|
37
|
+
if (p === '/') return route.fulfill({ contentType: 'text/html', body: PAGE(game) });
|
|
38
|
+
// The sheet's reads: an empty draft and an empty list are enough to draw it.
|
|
39
|
+
if (p.startsWith('/api/bongos/page-notes')) return route.fulfill({ contentType: 'application/json', body: JSON.stringify({ note: { id: 1, body_md: '', status: 'draft' }, images: [], notes: [] }) });
|
|
40
|
+
const f = path.join(HALL, p.replace(/^\/builders\//, ''));
|
|
41
|
+
if (p.startsWith('/builders/') && TYPES[path.extname(p)] && fs.existsSync(f)) return route.fulfill({ contentType: TYPES[path.extname(p)], body: fs.readFileSync(f) });
|
|
42
|
+
return route.fulfill({ status: 404, body: '' });
|
|
43
|
+
});
|
|
44
|
+
const page = await ctx.newPage();
|
|
45
|
+
const errors = [];
|
|
46
|
+
page.on('pageerror', (e) => errors.push(String(e.message)));
|
|
47
|
+
await page.goto(ORIGIN + '/');
|
|
48
|
+
await page.waitForFunction(() => !!window.OTBPageNotes);
|
|
49
|
+
// What craft-mode.js does for the Artist: dock the sheet, tucked away behind its tab.
|
|
50
|
+
await page.evaluate(() => window.OTBPageNotes.dock());
|
|
51
|
+
return { ctx, page, errors };
|
|
52
|
+
}
|
|
53
|
+
const tabShown = (page) => page.evaluate(() => {
|
|
54
|
+
const t = document.querySelector('#page-notes .pn__tab');
|
|
55
|
+
return !!t && getComputedStyle(t).display !== 'none' && t.getClientRects().length > 0;
|
|
56
|
+
});
|
|
57
|
+
const panelShown = (page) => page.evaluate(() => getComputedStyle(document.querySelector('#page-notes .pn__panel')).visibility !== 'hidden'
|
|
58
|
+
&& !document.getElementById('page-notes').classList.contains('pn--collapsed'));
|
|
59
|
+
|
|
60
|
+
test('classic mode keeps the parked tab at the right edge', { skip }, async () => {
|
|
61
|
+
const { ctx, page, errors } = await open(false);
|
|
62
|
+
assert.equal(await tabShown(page), true);
|
|
63
|
+
assert.deepEqual(errors, []);
|
|
64
|
+
await ctx.close();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('game mode: no parked tab; R opens the sheet, and closing leaves nothing at the edge', { skip }, async () => {
|
|
68
|
+
const { ctx, page, errors } = await open(true);
|
|
69
|
+
assert.equal(await tabShown(page), false, 'parked, nothing shows on the glass');
|
|
70
|
+
await page.waitForTimeout(350); // the slide-out
|
|
71
|
+
assert.equal(await panelShown(page), false);
|
|
72
|
+
// The visor's "Review this page" is OTBCraftMode.openTool('palette') → OTBPageNotes.open().
|
|
73
|
+
await page.evaluate(() => window.OTBPageNotes.open());
|
|
74
|
+
assert.equal(await panelShown(page), true, 'R still opens the sheet');
|
|
75
|
+
assert.equal(await tabShown(page), false, 'open, still no tab beside it');
|
|
76
|
+
await page.click('#page-notes [data-pn-close]');
|
|
77
|
+
await page.waitForTimeout(350);
|
|
78
|
+
assert.equal(await panelShown(page), false, 'closed, the sheet is gone');
|
|
79
|
+
assert.equal(await tabShown(page), false, 'and no tab is left behind');
|
|
80
|
+
assert.equal(await page.evaluate(() => document.getElementById('page-notes').contains(document.activeElement)), false,
|
|
81
|
+
'focus leaves the tucked sheet instead of landing on a tab nobody can see');
|
|
82
|
+
await page.evaluate(() => window.OTBPageNotes.open());
|
|
83
|
+
assert.equal(await panelShown(page), true, 'and R opens it again');
|
|
84
|
+
assert.deepEqual(errors, []);
|
|
85
|
+
await ctx.close();
|
|
86
|
+
});
|
|
@@ -128,7 +128,7 @@ test('Home loads the sheet and the script, and the sheet types in no size, corne
|
|
|
128
128
|
assert.match(css, /\.gs__title \{[^}]*font-family: var\(--name-face\);[^}]*letter-spacing: var\(--name-space-wide\); text-transform: var\(--name-case\);/, 'the title is the name voice');
|
|
129
129
|
assert.match(css, /\.gs__item \{[^}]*font-family: var\(--name-face\);[^}]*text-transform: var\(--name-case\);/, 'so is every choice');
|
|
130
130
|
assert.match(css, /\.gs__menu, \.gs__load \{[^}]*background: var\(--night-glass\);/, 'both panels are the night over the art');
|
|
131
|
-
assert.match(css, /\.gs__item\[data-gs="start"\] \{\s*background: var\(--accent\); color: var\(--accent-on\);/, 'Start is the one thing lit, under the dark ink');
|
|
131
|
+
assert.match(css, /\.gs__item\[data-gs="start"\], \.gs__item--lit \{\s*background: var\(--accent\); color: var\(--accent-on\);/, 'Start, and on the chooser the view Enter takes, is the one thing lit, under the dark ink (task 1005206)');
|
|
132
132
|
assert.match(css, /\.gs__item:focus-visible \{[^}]*box-shadow: var\(--press-focus\);/, 'a row rings inside itself, in two tones');
|
|
133
133
|
});
|
|
134
134
|
|
|
@@ -278,6 +278,7 @@ test('choosing Classic at sign-in closes the screen, leaves game mode off, and s
|
|
|
278
278
|
await page.evaluate(() => { const me = { authed: true, rank: 'metic', builder: { id: 7, display_name: 'Ada', github_login: 'ada' } }; window.OTBShell.applyAccess(me); window.OTBShell.applyAccess(me); });
|
|
279
279
|
await page.waitForSelector('#game-start');
|
|
280
280
|
assert.equal(await page.evaluate(() => document.activeElement.textContent), 'ClassicLast timeThe hall with its sidebar', 'the view chosen last time is focused and marked');
|
|
281
|
+
assert.deepEqual(await page.evaluate(() => [...document.querySelectorAll('.gs__item--lit')].map((e) => e.dataset.gs)), ['view-classic'], 'and it is the lit bar, the only one (task 1005206)');
|
|
281
282
|
await page.keyboard.press('Enter');
|
|
282
283
|
await page.waitForSelector('#game-start', { state: 'detached' });
|
|
283
284
|
assert.equal((await state(page)).game, null);
|
|
@@ -95,6 +95,26 @@ test('THE PANEL: docked at the edge in Artist alone, with no top-bar button, and
|
|
|
95
95
|
assert.deepEqual(none.loaded, [], 'and nothing loads');
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
+
test('the review sheet is the Artist\'s alone: openTool (the visor\'s R) opens it for no other character (task 1005207)', async () => {
|
|
99
|
+
const a = boot({ session: { 'hall-craft': 'artist' } });
|
|
100
|
+
await flush();
|
|
101
|
+
a.craft.openTool('palette');
|
|
102
|
+
await flush();
|
|
103
|
+
assert.deepEqual(a.opened, ['dock', 'open'], 'the Artist opens it');
|
|
104
|
+
for (const m of ['artisan', 'patron']) {
|
|
105
|
+
const p = boot({ session: { 'hall-craft': m } });
|
|
106
|
+
await flush();
|
|
107
|
+
p.craft.openTool('palette');
|
|
108
|
+
await flush();
|
|
109
|
+
assert.deepEqual(p.opened, [], `${m}: nothing opens`);
|
|
110
|
+
assert.deepEqual(p.loaded, [], `${m}: the sheet's script never loads`);
|
|
111
|
+
}
|
|
112
|
+
const none = boot();
|
|
113
|
+
none.craft.openTool('palette');
|
|
114
|
+
await flush();
|
|
115
|
+
assert.deepEqual(none.opened, [], 'with no character, nothing opens');
|
|
116
|
+
});
|
|
117
|
+
|
|
98
118
|
test('a screen in the options menu frame docks no second panel: the menu around it has one', async () => {
|
|
99
119
|
const p = boot({ session: { 'hall-craft': 'artist' }, embedded: true });
|
|
100
120
|
await flush();
|