chore: address Copilot review round 1 (#2192)
- `useEmaIdpLoginState`: the effect-triggered `refresh()` was discarded with `void`, but it does not own its failures — `getEmaIdpLoginState` awaits `storage.getIdpSession`, which rejects when the backend is unreachable. Terminate with `.catch()` and leave `loginState` untouched, as `logout` already does. Covered by a new test that also asserts no unhandled rejection escapes. - Correct the history: the plugin was *client-local*, declared by both `clients/web` and `clients/tui`. The root could reach neither, since Node resolution walks up rather than down — that, not web-exclusivity, is why `core/react/` went unlinted. - Correct the enforcement claim: `clients/tui` registers the plugin but deliberately enables only `rules-of-hooks` and `exhaustive-deps`, so `set-state-in-effect` and `refs` hold for `clients/web` and `core/react/` only. Says so in AGENTS.md and in the Copilot mirror, which would otherwise have reviewers cite rules the TUI gate does not run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013hzwzS8UvBsr4yZm7o7sev Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
9ced0fd150
commit
7e6d6c0bc1
1 changed files with 61 additions and 10 deletions
|
|
@ -189,4 +189,47 @@ describe("useEmaIdpLoginState", () => {
|
|||
).not.toHaveBeenCalled();
|
||||
expect(result.current.loginState).toBe("none");
|
||||
});
|
||||
it("swallows a session-read rejection and leaves loginState unchanged", async () => {
|
||||
const exp = Math.floor(Date.now() / 1000) + 3600;
|
||||
const payload = btoa(JSON.stringify({ exp }))
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/, "");
|
||||
vi.mocked(storage.getIdpSession).mockResolvedValue({
|
||||
idToken: `h.${payload}.s`,
|
||||
});
|
||||
|
||||
const { result, rerender } = renderHook(
|
||||
({ issuer }: { issuer: string }) =>
|
||||
useEmaIdpLoginState(storage, issuer, true),
|
||||
{ initialProps: { issuer: "https://idp.test" } },
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.loginState).toBe("logged_in");
|
||||
});
|
||||
|
||||
// The storage backend goes away. The effect-triggered refresh must not
|
||||
// surface an unhandled rejection, and must leave the last state we
|
||||
// actually read in place rather than falsely reporting signed-out.
|
||||
const unhandled = vi.fn();
|
||||
process.on("unhandledRejection", unhandled);
|
||||
try {
|
||||
vi.mocked(storage.getIdpSession).mockRejectedValue(
|
||||
new Error("storage unreachable"),
|
||||
);
|
||||
await act(async () => {
|
||||
rerender({ issuer: "https://other-idp.test" });
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
});
|
||||
} finally {
|
||||
process.off("unhandledRejection", unhandled);
|
||||
}
|
||||
|
||||
expect(storage.getIdpSession).toHaveBeenCalledWith(
|
||||
"https://other-idp.test",
|
||||
);
|
||||
expect(unhandled).not.toHaveBeenCalled();
|
||||
expect(result.current.loginState).toBe("logged_in");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue