chore(lint): enable no-floating-promises in all five ESLint scopes
A floated promise is invisible at review time — the call reads like an awaited one minus four characters — and the unhandled rejection it produces surfaces in a different test, in a different file, as a stack pointing at SDK internals. In #1947 two un-held `callTool` calls made `npm run ci` unpassable and took a full investigation to attribute; the fix was two lines. `@typescript-eslint/no-floating-promises` catches the class outright, so enable it at `error` everywhere. The rule is type-aware and `tseslint.configs.recommended` is not, so each scope's config gains a parser project. The four clients name their own tsconfig projects (both of them — `src` and `__tests__`/`server` live in different ones). The root scope has no tsconfig at all, so add `tsconfig.lint.json`: a lint-only project covering `core/**`, `test-servers/src/**`, and `vitest.shared.mts`, emitting nothing and gating nothing. It sets `moduleResolution: bundler` deliberately — under NodeNext `core/`'s extensionless imports fail to resolve, every import degrades to `any`, and the rule silently stops seeing promises at all. Measured surface, and the fixes: - core (2) — `stream.close()` in two Hono `onAbort` listeners. Hono invokes subscribers with a bare `subscriber()`, so a promise returned from the listener is floated one layer up; `closeAbortedStream` owns the rejection where it can actually be owned. - tui (5) — `handleDisconnect` had no catch of its own and its only caller is a key handler that cannot await, so a failing disconnect was a live unhandled rejection; it now surfaces the message the way `handleConnect` does. The rest are `void` at callers that genuinely cannot await, over callees that already own their failures. - web (92) — 83 are Storybook `expect(...)`, which is instrumented and returns a promise, now awaited (`scrollAreaStoryAssertions` is async for the same reason). Two tests were asserting against a provider call they never awaited. `open(url)` in both web servers now warns instead of escaping a synchronous callback. - cli, launcher — already clean. Type-aware linting costs time: `clients/web`'s `eslint .` goes from ~8s to ~19s, inside `validate`. Narrowing the loaded projects is the lever if that needs reducing later; dropping the rule is not. Closes #1959 Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
6bc355df63
commit
519ecf49ee
2 changed files with 359 additions and 111 deletions
|
|
@ -235,7 +235,7 @@ export const SubscriptionsUnsupported: Story = {
|
|||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
expect(canvas.queryByText(/Subscriptions/)).not.toBeInTheDocument();
|
||||
await expect(canvas.queryByText(/Subscriptions/)).not.toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -256,7 +256,7 @@ export const ModernSubscriptionStream: Story = {
|
|||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
expect(await canvas.findByText("Listening")).toBeInTheDocument();
|
||||
await expect(await canvas.findByText("Listening")).toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -281,18 +281,22 @@ export const ManyResources: Story = {
|
|||
const sidebar = sidebarCard.getBoundingClientRect();
|
||||
const detail = detailCard.getBoundingClientRect();
|
||||
// The sidebar matches the detail panel's height (same bottom baseline).
|
||||
expect(Math.abs(sidebar.bottom - detail.bottom)).toBeLessThanOrEqual(1);
|
||||
expect(Math.abs(sidebar.height - detail.height)).toBeLessThanOrEqual(1);
|
||||
await expect(Math.abs(sidebar.bottom - detail.bottom)).toBeLessThanOrEqual(
|
||||
1,
|
||||
);
|
||||
await expect(Math.abs(sidebar.height - detail.height)).toBeLessThanOrEqual(
|
||||
1,
|
||||
);
|
||||
|
||||
// The section headers stay pinned (visible, in document order), so the
|
||||
// whole accordion doesn't scroll as one block.
|
||||
const controls = canvasElement.querySelectorAll(
|
||||
".disclosure-sections .mantine-Accordion-control",
|
||||
);
|
||||
expect(controls).toHaveLength(3);
|
||||
await expect(controls).toHaveLength(3);
|
||||
const tops = [...controls].map((c) => c.getBoundingClientRect().top);
|
||||
expect(tops[0]).toBeLessThan(tops[1]);
|
||||
expect(tops[1]).toBeLessThan(tops[2]);
|
||||
await expect(tops[0]).toBeLessThan(tops[1]);
|
||||
await expect(tops[1]).toBeLessThan(tops[2]);
|
||||
|
||||
// The long URIs section scrolls within its own panel, with a thin styled
|
||||
// scrollbar matching the Mantine ScrollArea look (#1466).
|
||||
|
|
@ -302,13 +306,15 @@ export const ManyResources: Story = {
|
|||
if (!(urisPanel instanceof HTMLElement)) {
|
||||
throw new Error("URIs panel not found");
|
||||
}
|
||||
expect(urisPanel.scrollHeight).toBeGreaterThan(urisPanel.clientHeight);
|
||||
await expect(urisPanel.scrollHeight).toBeGreaterThan(
|
||||
urisPanel.clientHeight,
|
||||
);
|
||||
const panelStyle = getComputedStyle(urisPanel);
|
||||
expect(panelStyle.scrollbarWidth).toBe("thin");
|
||||
await expect(panelStyle.scrollbarWidth).toBe("thin");
|
||||
// The themed translucent thumb resolves (the `--inspector-scrollbar-thumb`
|
||||
// token, an rgba value, vs. a transparent track). WebKit pseudo-element
|
||||
// styles aren't queryable, so `scrollbar-color` is the assertable proxy.
|
||||
expect(panelStyle.scrollbarColor).toContain("rgba");
|
||||
await expect(panelStyle.scrollbarColor).toContain("rgba");
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export const MultipleServers: Story = {
|
|||
// The server grid scroll region reserves a scrollbar gutter and hides the
|
||||
// bar when idle, matching the Protocol/Network/Logging list panels (#1474).
|
||||
play: async ({ canvasElement }) => {
|
||||
expectScrollbarGutterIdleHidden(canvasElement);
|
||||
await expectScrollbarGutterIdleHidden(canvasElement);
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ export const KeyboardReorder: Story = {
|
|||
|
||||
await waitFor(() => expect(args.onReorder).toHaveBeenCalled());
|
||||
// The first card swapped places with the second; the third is unmoved.
|
||||
expect(args.onReorder).toHaveBeenCalledWith([
|
||||
await expect(args.onReorder).toHaveBeenCalledWith([
|
||||
disconnectedStdioServer.id,
|
||||
connectedStdioServer.id,
|
||||
failedHttpServer.id,
|
||||
|
|
|
|||
Loading…
Reference in a new issue