fix(review): resolve deep-review findings across quickfix batch #2
- Button: `loading` always disables (|| not ??) — stops a double-submit when a call-site passes an explicit boolean `disabled` (VideoEditor). - playlists: track un-ingestable-but-live YouTube ids in the sync baseline so a linked playlist containing a private/deleted video converges instead of re-classifying it as a pending pull forever; re-attempt ingestion each sync so a restored (private->public) video heals, and prune ids that leave YouTube. - SettingsPanel: download-auth section renders an honest error/loading state (StateMessage + retry) instead of a bare empty section on a failed credentials fetch; HU+EN loadError string. - tests: reorder-order, partial-failure baseline hold, un-ingestable converge/heal/prune, Button loading-disables, download-auth error/retry.
This commit is contained in:
@@ -55,6 +55,22 @@ describe("Button primitive (S5)", () => {
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("loading disables even when an explicit disabled={false} is passed", () => {
|
||||
// Regression: `disabled ?? loading` let an explicit boolean disabled shadow loading, so a
|
||||
// call-site with `disabled={!valid} loading={pending}` (valid → disabled=false) stayed
|
||||
// clickable mid-mutation and double-submitted. The contract is: loading always disables.
|
||||
const onClick = vi.fn();
|
||||
render(
|
||||
<Button disabled={false} loading onClick={onClick}>
|
||||
Create
|
||||
</Button>,
|
||||
);
|
||||
const btn = screen.getByRole("button", { name: "Create" }) as HTMLButtonElement;
|
||||
expect(btn.disabled).toBe(true);
|
||||
fireEvent.click(btn);
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("fullWidth adds the w-full utility", () => {
|
||||
render(<Button fullWidth>Wide</Button>);
|
||||
expect(screen.getByRole("button", { name: "Wide" }).className).toContain("w-full");
|
||||
|
||||
@@ -86,7 +86,10 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
||||
<button
|
||||
ref={ref}
|
||||
type={type ?? "button"}
|
||||
disabled={disabled ?? loading}
|
||||
// `loading` must always disable (see the prop's contract above), even when a call-site also
|
||||
// passes an explicit boolean `disabled` — so `||`, not `??`. With `??`, `disabled={false}`
|
||||
// would shadow `loading` and leave the button clickable mid-mutation (double-submit).
|
||||
disabled={disabled || loading}
|
||||
aria-busy={loading || undefined}
|
||||
aria-label={label}
|
||||
title={label}
|
||||
|
||||
Reference in New Issue
Block a user