0.2.3: prepare follow-up fixes and client features (#407, #408, #410, #413, #431, #435, #436, #440, #444)
Add special-target activation without bypassing attack cadence, cooperative card preferences and emotes, skill sound banks, per-operator voice choices, text sizing, install prompts, closed-tab recovery and unanimous setup rerolls. Retain late deployment elapsed time and resolve echo/counter pulses without recursive hook overflow. Independent final review remains pending. Golden: roster-016, roster-035, roster-036, roster-045; boss-boss_1-pair, boss-boss_3-pair, boss-boss_5-pair, boss-boss_7-pair, hidden-boss_9-pair; solo-HARD-9-boosted: Lemuen attack cadence. diy-132: Necras extra activation targets. coop2-NORMAL-14-standins: cooperative purchase preference and simulation fixes. hidden-boss_10-solo: echo pulse FIFO resolution. See DESIGN 28.13-28.24 for assumptions, sources and contributor credit.
This commit is contained in:
1 parent
314564c139
commit
f3658a0dd4
104 files changed
+3674
-741
No files matched your search
@@ -0,0 +1,54 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { createPwaInstall } from '../../public/js/pwa.js';
|
||||
function rig(standalone = false) {
|
||||
const win = new EventTarget(), display = new EventTarget();
|
||||
display.matches = standalone;
|
||||
win.matchMedia = () => display;
|
||||
const pwa = createPwaInstall(win);
|
||||
const offer = (outcome = 'dismissed', fail = false) => {
|
||||
let calls = 0;
|
||||
const e = new Event('beforeinstallprompt', { cancelable: true });
|
||||
e.prompt = async () => { calls++; if (fail) throw Error('unavailable'); return { outcome }; };
|
||||
win.dispatchEvent(e);
|
||||
return { calls: () => calls, e };
|
||||
};
|
||||
return { pwa, win, display, offer };
|
||||
}
|
||||
test('install offer is consumed even on dismissal, duplicate clicks, or rejected prompt', async () => {
|
||||
const { pwa, offer } = rig();
|
||||
const states = []; const off = pwa.subscribe((x) => states.push(x));
|
||||
assert.equal(pwa.available(), false);
|
||||
const first = offer();
|
||||
assert.equal(first.e.defaultPrevented, true);
|
||||
assert.equal(pwa.available(), true);
|
||||
const a = pwa.request(), b = pwa.request();
|
||||
assert.equal(await a, false); assert.equal(await b, false); assert.equal(first.calls(), 1);
|
||||
const broken = offer('accepted', true);
|
||||
assert.equal(await pwa.request(), false); assert.equal(await pwa.request(), false); assert.equal(broken.calls(), 1);
|
||||
const next = offer('accepted');
|
||||
assert.equal(await pwa.request(), true); assert.equal(next.calls(), 1);
|
||||
assert.deepEqual(states, [false, true, false, true, false, true, false]);
|
||||
off(); pwa.dispose();
|
||||
});
|
||||
test('installed / standalone hides stale offers; disposing removes listeners', async () => {
|
||||
const { pwa, win, display, offer } = rig();
|
||||
offer(); display.matches = true; display.dispatchEvent(new Event('change'));
|
||||
assert.equal(pwa.available(), false); assert.equal(await pwa.request(), false);
|
||||
display.matches = false; win.dispatchEvent(new Event('appinstalled')); offer();
|
||||
assert.equal(pwa.available(), false);
|
||||
pwa.dispose();
|
||||
assert.equal(offer().e.defaultPrevented, false);
|
||||
const native = rig(true); native.offer(); assert.equal(native.pwa.available(), false); native.pwa.dispose();
|
||||
});
|
||||
test('manifest uses actual 192/512 icons shipped outside optional game assets', () => {
|
||||
const m = JSON.parse(readFileSync(new URL('../../public/manifest.json', import.meta.url)));
|
||||
assert.equal(m.start_url, '/'); assert.equal(m.scope, '/');
|
||||
for (const icon of m.icons) {
|
||||
assert.ok(icon.src.startsWith('/icons/'));
|
||||
const bytes = readFileSync(new URL('../../public' + icon.src, import.meta.url));
|
||||
const size = Number(icon.sizes.split('x')[0]);
|
||||
assert.equal(bytes.readUInt32BE(16), size); assert.equal(bytes.readUInt32BE(20), size);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user