Skip to content

Conversation

@timothyfroehlich
Copy link
Owner

Fixes layout shift in WatchButton by removing dynamic text changes (Watching.../Unwatching...) and relying on the loading spinner state.

@timothyfroehlich timothyfroehlich added the jules:copilot-review Waiting for Copilot review (auto-triggered) label Jan 19, 2026
Copilot AI review requested due to automatic review settings January 19, 2026 18:37
@timothyfroehlich timothyfroehlich added the jules:copilot-review Waiting for Copilot review (auto-triggered) label Jan 19, 2026
@vercel
Copy link

vercel bot commented Jan 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
pin-point Ready Ready Preview, Comment Jan 19, 2026 7:35pm

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes layout shift in the WatchButton component by removing dynamic text changes during loading states and relying solely on the loading spinner for visual feedback.

Changes:

  • Removed conditional text ("Watching..." / "Unwatching...") in favor of static labels ("Watch Issue" / "Unwatch Issue")
  • Added unit tests for the WatchButton component to verify rendering and action behavior

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
src/components/issues/WatchButton.tsx Simplified button text to remain static during loading, eliminating layout shift
src/components/issues/WatchButton.test.tsx Added unit tests covering basic rendering states and action invocation

@@ -0,0 +1,40 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import { WatchButton } from "./WatchButton";
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file should be located in src/test/unit/components/issues/ instead of directly alongside the component file. This follows the established pattern seen in src/test/unit/components/auth/login-form.test.tsx and maintains clear separation between source and test code as documented in src/test/README.md.

Suggested change
import { WatchButton } from "./WatchButton";
import { WatchButton } from "~/components/issues/WatchButton";

Copilot uses AI. Check for mistakes.
});

it("calls toggleWatcherAction on click", async () => {
(toggleWatcherAction as any).mockResolvedValue({
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using any type violates the TypeScript strictest patterns guideline. Instead, mock the function with proper typing. For example: vi.mocked(toggleWatcherAction).mockResolvedValue({ ok: true, value: { isWatching: true } }) after importing the function, or create a properly typed mock variable.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +51 to +56
Unwatch Issue
</>
) : (
<>
{!isPending && <Eye className="size-4" />}
{isPending ? "Watching..." : "Watch Issue"}
Watch Issue
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change to static text in WatchButton creates an inconsistency with InviteUserDialog (line 224-225), which still uses dynamic text: {isPending ? "Inviting..." : "Invite User"}. Consider updating InviteUserDialog to follow the same pattern for consistency, or document why different components handle loading states differently. The auth forms (login, signup, etc.) already use static text with the loading spinner, which aligns with this change.

Copilot uses AI. Check for mistakes.
Comment on lines 4 to 12
import React from "react";

// Mock the server action
vi.mock("~/app/(app)/issues/watcher-actions", () => ({
toggleWatcherAction: vi.fn(),
}));

import { toggleWatcherAction } from "~/app/(app)/issues/watcher-actions";

Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The React import on line 4 is unnecessary since React is already implicitly available in JSX transform. Additionally, line 4 appears after the mock setup (lines 6-11), which places imports out of standard order. Consider removing the explicit React import or moving all imports to the top before any mock setup code.

Suggested change
import React from "react";
// Mock the server action
vi.mock("~/app/(app)/issues/watcher-actions", () => ({
toggleWatcherAction: vi.fn(),
}));
import { toggleWatcherAction } from "~/app/(app)/issues/watcher-actions";
import { toggleWatcherAction } from "~/app/(app)/issues/watcher-actions";
// Mock the server action
vi.mock("~/app/(app)/issues/watcher-actions", () => ({
toggleWatcherAction: vi.fn(),
}));

Copilot uses AI. Check for mistakes.
Comment on lines 26 to 39
it("calls toggleWatcherAction on click", async () => {
(toggleWatcherAction as any).mockResolvedValue({
ok: true,
value: { isWatching: true },
});

render(<WatchButton issueId="123" initialIsWatching={false} />);

fireEvent.click(screen.getByRole("button"));

await waitFor(() => {
expect(toggleWatcherAction).toHaveBeenCalledWith("123");
});
});
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should verify that the loading spinner is shown during the pending state, similar to how login-form.test.tsx validates the spinner presence (lines 59-61 in that file). Since the PR's purpose is to rely on the loading spinner instead of dynamic text, validating spinner behavior is important to ensure the change achieves its stated goal of indicating loading state.

Copilot uses AI. Check for mistakes.
- Move test to src/test/unit/components/issues/\n- Use vi.mocked instead of any\n- Verify loading spinner and static text stability
@timothyfroehlich timothyfroehlich merged commit 4b4586d into main Jan 19, 2026
17 checks passed
@timothyfroehlich timothyfroehlich deleted the feature/stabilize-watch-button-v2 branch January 19, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jules:copilot-review Waiting for Copilot review (auto-triggered)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants