fix(platform): preserve session failures and URL syntax

This commit is contained in:
2026-09-05 06:38:00 +08:00
parent 7e5a950cc7
commit 224df1c21c
6 changed files with 123 additions and 8 deletions
@@ -39,6 +39,16 @@ function makeEntry(createModule: () => GameModule): GameEntry {
};
}
function caughtError(operation: () => void): Error {
try {
operation();
} catch (error) {
assert.ok(error instanceof Error);
return error;
}
assert.fail('expected operation to throw');
}
function makeModule(log: string[], onRestore?: (deskinfo: unknown) => void): GameModule {
let attached = false;
return {
@@ -153,6 +163,64 @@ test('GameSessionHost disposes a module when attachment throws and returns to id
assert.equal(sessions.state, 'idle');
});
test('GameSessionHost preserves create and contract failures when open cleanup succeeds', () => {
const createError = new Error('create failed');
let createCalls = 0;
const createSessions = new GameSessionHost(makeEntry(() => {
createCalls += 1;
if (createCalls === 1) return makeModule([]);
throw createError;
}));
assert.equal(caughtError(() => createSessions.open(makeHost())), createError);
assert.equal(createSessions.state, 'idle');
let contractCalls = 0;
let contractDisposals = 0;
const contractSessions = new GameSessionHost(makeEntry(() => {
contractCalls += 1;
if (contractCalls === 1) return makeModule([]);
return {
handlePlatformEvent() {},
handleGameMessage() {},
restore() {},
dispose() { contractDisposals += 1; },
} as unknown as GameModule;
}));
assert.match(caughtError(() => contractSessions.open(makeHost())).message, /implement attach/);
assert.equal(contractDisposals, 1);
assert.equal(contractSessions.state, 'idle');
});
test('GameSessionHost preserves attach then dispose failures by identity and occurrence order', () => {
const attachError = new Error('attach primary');
const disposeError = new Error('open cleanup');
let createCalls = 0;
let disposals = 0;
const sessions = new GameSessionHost(makeEntry(() => {
createCalls += 1;
if (createCalls === 1) return makeModule([]);
return {
...makeModule([]),
attach() { throw attachError; },
dispose() {
disposals += 1;
throw disposeError;
},
};
}));
const error = caughtError(() => sessions.open(makeHost()));
assert.deepEqual(
(error as Error & { errors?: readonly unknown[] }).errors,
[attachError, disposeError],
);
assert.equal(disposals, 1);
assert.equal(sessions.state, 'idle');
});
test('GameSessionHost disposes a module exactly once and becomes terminal after dispose', () => {
const log: string[] = [];
const sessions = new GameSessionHost(makeEntry(() => makeModule(log)));