68 lines
3.3 KiB
JavaScript
68 lines
3.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {appearanceView, AppearanceUpdates} from '../src/appearance-state.ts';
|
|
const glass = () => ({requested_material:'frosted', effective_material:'frosted', opacity:90, native_effect:true, fallback_reason:null});
|
|
test('transparency requires a confirmed native effect', () => {
|
|
assert.equal(appearanceView(undefined, false).material, 'solid');
|
|
assert.equal(appearanceView({...glass(), native_effect:false}, false).material, 'solid');
|
|
assert.equal(appearanceView(glass(), false).material, 'frosted');
|
|
assert.equal(appearanceView({...glass(), effective_material:'glass'}, false).material, 'glass');
|
|
});
|
|
test('high contrast stays opaque without losing the preference', () => {
|
|
const status = glass();
|
|
assert.equal(appearanceView(status, true).material, 'solid');
|
|
assert.match(appearanceView(status, true).message, /preference is retained/);
|
|
assert.equal(status.requested_material, 'frosted');
|
|
assert.equal(appearanceView(status, false).material, 'frosted');
|
|
});
|
|
test('fallback is honest and shell tint is bounded', () => {
|
|
const fallback = {...glass(), effective_material:'solid', native_effect:false, fallback_reason:'Native effects unavailable.'};
|
|
assert.match(appearanceView(fallback, false).message, /Solid background/);
|
|
assert.equal(appearanceView({...glass(), opacity:5}, false).opacity, 40);
|
|
assert.equal(appearanceView({...glass(), opacity:110}, false).opacity, 100);
|
|
assert.equal(appearanceView({...glass(), opacity:NaN}, false).opacity, 90);
|
|
});
|
|
|
|
test('rapid pending changes serialize and only publish the latest response', async () => {
|
|
const writes = [], published = [], errors = [];
|
|
let resolve;
|
|
let settled;
|
|
const done = new Promise(r => settled = r);
|
|
const queue = new AppearanceUpdates(update => {
|
|
writes.push(update);
|
|
if (writes.length === 1) return new Promise(r => resolve = r);
|
|
return Promise.resolve({...glass(), opacity:update.preference.opacity});
|
|
}, status => published.push(status), error => errors.push(error), settled);
|
|
queue.submit(false, {material:'glass', opacity:80});
|
|
queue.submit(false, {material:'frosted', opacity:95});
|
|
queue.submit(true); // Preserve the pending saved preference when contrast toggles.
|
|
assert.equal(writes.length, 1);
|
|
assert.equal(queue.busy, true);
|
|
resolve({...glass(), effective_material:'glass', opacity:80});
|
|
await done;
|
|
assert.equal(writes.length, 2);
|
|
assert.equal(writes[1].highContrast, true);
|
|
assert.deepEqual(writes[1].preference, {material:'frosted', opacity:95});
|
|
assert.equal(published.length, 1);
|
|
assert.equal(published[0].opacity, 95);
|
|
assert.equal(queue.busy, false);
|
|
assert.deepEqual(errors, []);
|
|
});
|
|
test('failed stale mutation cannot suppress a queued contrast restore', async () => {
|
|
let reject, settled;
|
|
const done = new Promise(r => settled = r);
|
|
const writes = [], errors = [], published = [];
|
|
const queue = new AppearanceUpdates(update => {
|
|
writes.push(update);
|
|
return writes.length === 1 ? new Promise((_,r) => reject=r) : Promise.resolve(glass());
|
|
}, status => published.push(status), error => errors.push(error), settled);
|
|
queue.submit(true);
|
|
queue.submit(false);
|
|
reject(new Error('owned stale failure'));
|
|
await done;
|
|
assert.equal(writes.length,2);
|
|
assert.equal(writes[1].highContrast,false);
|
|
assert.equal(published.length,1);
|
|
assert.deepEqual(errors,[]);
|
|
});
|