From 0795ef197cca04f6a8e7d50d10ed4dc71bd1a0cc Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Sun, 25 Oct 2026 18:59:48 +0200 Subject: [PATCH] test(chatgpt): await repeated sign-in completion --- tests/chatgpt-auth.test.ts | 42 ++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/tests/chatgpt-auth.test.ts b/tests/chatgpt-auth.test.ts index fb09716..14c3baa 100644 --- a/tests/chatgpt-auth.test.ts +++ b/tests/chatgpt-auth.test.ts @@ -445,20 +445,50 @@ test("scope-disabled credentials remain revocable and unconfirmed revoke never c } finally { f.service.close(); } }); -test("repeated real verified sign-in creates one visible account while preserving separately bound registrations until explicit forgetting", async () => { - const f = await loggedIn(); +for (const holdVerification of [false, true]) test(`repeated real verified sign-in creates one visible account while preserving separately bound registrations until explicit forgetting${holdVerification ? " (held JWKS regression)" : ""}`, { timeout: 10000 }, async () => { + const repeatComplete = deferred(); + const verificationEntered = deferred(), verificationRelease = deferred(); + let repeatArmed = false, sawPending = false, completed = false; + const f = await loggedIn({ + change: (push) => { + if (!repeatArmed) return; + if (push.status.pending) sawPending = true; + else if (sawPending) { completed = true; repeatComplete.resolve(push.status); } + }, + provider: async (url) => { + if (holdVerification && repeatArmed && url.endsWith("jwks.json")) { + verificationEntered.resolve(); await verificationRelease.promise; + } + return undefined; + }, + }); try { const original = f.saved.registrations[0]; - await f.service.login(); await f.callback({ client_id: "oaiapp_repeat" }); - for (let i = 0; i < 100 && (await f.service.status()).pending; i++) await new Promise((r) => setImmediate(r)); - const status = await f.service.status(); + const writesBeforeRepeat = f.writeCount; + // Initial login already settled fixture.changed; arm for this attempt's terminal notification. + repeatArmed = true; + await f.service.login(); assert.equal(sawPending, true); + assert.equal((await f.callback({ client_id: "oaiapp_repeat" })).status, 200); + if (holdVerification) { + await verificationEntered.promise; + assert.equal(completed, false, "HTTP acknowledgement cannot complete pending identity verification"); + const held = await f.service.status(); + assert.equal(held.pending, true); assert.equal(held.error, null); + assert.equal(held.activeId, original.id); assert.equal(held.accounts.length, 1); + assert.deepEqual(f.saved.registrations, [original]); + assert.equal(f.writeCount, writesBeforeRepeat, "unverified repeat sign-in cannot persist credentials"); + } + verificationRelease.resolve(); + const status = await repeatComplete.promise; + assert.equal(status.pending, false); assert.equal(status.error, null); + assert.equal(f.writeCount, writesBeforeRepeat + 1, "repeat sign-in completes after durable credential persistence"); assert.equal(f.saved.registrations.length, 2); assert.equal(status.accounts.length, 1); assert.equal(status.activeId, status.accounts[0].id); assert.notEqual(status.activeId, original.id); assert.equal(f.saved.registrations[0].clientId, original.clientId); assert.equal(f.saved.registrations[1].clientId, "oaiapp_repeat"); await f.service.disconnect(status.activeId); assert.deepEqual(f.saved.registrations, []); assert.equal((await f.service.status()).accounts.length, 0); assert.equal(f.requests.filter((r) => r.form?.has("token_type_hint")).length, 2); - } finally { f.service.close(); } + } finally { verificationRelease.resolve(); f.service.close(); } }); test("verified identity grouping hides legacy duplicate registrations without merging client credentials or matching emails", async () => {