diff --git a/site/src/api/queries/workspaces.ts b/site/src/api/queries/workspaces.ts index 5bad8cee66..42e1988cfd 100644 --- a/site/src/api/queries/workspaces.ts +++ b/site/src/api/queries/workspaces.ts @@ -211,7 +211,7 @@ async function findMatchWorkspace(q: string): Promise { } } -function workspacesKey(req: WorkspacesRequest = {}) { +export function workspacesKey(req: WorkspacesRequest = {}) { return ["workspaces", req] as const; } diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.stories.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.stories.tsx index 53aff3701f..a50bbe0ed1 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.stories.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.stories.tsx @@ -14,6 +14,7 @@ import { getTemplatesQueryKey, templateVersionsQueryKey, } from "#/api/queries/templates"; +import { workspacesKey } from "#/api/queries/workspaces"; import type { Workspace } from "#/api/typesGenerated"; import { workspaceChecks } from "#/modules/workspaces/permissions"; import { @@ -22,6 +23,7 @@ import { MockTemplate, MockTemplateVersion, MockUserOwner, + MockWorkspace, } from "#/testHelpers/entities"; import { withAuthProvider, @@ -55,7 +57,7 @@ const deletingWorkspace: Workspace = { }, }; -const meta: Meta = { +const meta = { title: "pages/WorkspacesPage/WorkspacesPage", component: WorkspacesPage, decorators: [withAuthProvider, withDashboardProvider, withProxyProvider()], @@ -108,10 +110,10 @@ const meta: Meta = { spyOn(API, "getOrganizations").mockResolvedValue([MockDefaultOrganization]); spyOn(API, "getWorkspaceBuildParameters").mockResolvedValue([]); }, -}; +} satisfies Meta; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const DeleteWorkspaceShowsDeletingStateImmediately: Story = { beforeEach: () => { @@ -170,3 +172,47 @@ export const DeleteWorkspaceShowsDeletingStateImmediately: Story = { ); }, }; + +const makePage = (prefix: string) => + Array.from({ length: 25 }, (_, i) => ({ + ...MockWorkspace, + id: `${prefix}-workspace-${i}`, + name: `${prefix}-workspace-${i}`, + })); + +export const PaginationChangesQueryKey: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + queries: [ + ...meta.parameters.queries, + { + key: workspacesKey({ q: "owner:me", limit: 25, offset: 0 }), + data: { workspaces: makePage("page1"), count: 50 }, + }, + { + key: workspacesKey({ q: "owner:me", limit: 25, offset: 25 }), + data: { workspaces: makePage("page2"), count: 50 }, + }, + ], + }, + play: async ({ canvasElement, step }) => { + const canvas = within(canvasElement); + const user = userEvent.setup(); + + await step("Page 1 renders from cache", async () => { + await canvas.findByText("page1-workspace-0"); + }); + + await step("Clicking next page shows page 2 data", async () => { + const nextButton = await canvas.findByRole("button", { + name: /next page/i, + }); + await user.click(nextButton); + + await canvas.findByText("page2-workspace-0"); + await waitFor(() => { + expect(canvas.queryByText("page1-workspace-0")).not.toBeInTheDocument(); + }); + }); + }, +}; diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx index 896f09742b..6dae88d1ff 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.test.tsx @@ -296,67 +296,6 @@ describe("WorkspacesPage", () => { MockStoppedWorkspace.latest_build.template_version_id, ); }); - - it("correctly handles pagination by including pagination parameters in query key", async () => { - const totalWorkspaces = 50; - const workspacesPage1 = Array.from({ length: 25 }, (_, i) => ({ - ...MockWorkspace, - id: `page1-workspace-${i}`, - name: `page1-workspace-${i}`, - })); - const workspacesPage2 = Array.from({ length: 25 }, (_, i) => ({ - ...MockWorkspace, - id: `page2-workspace-${i}`, - name: `page2-workspace-${i}`, - })); - - const getWorkspacesSpy = vi.spyOn(API, "getWorkspaces"); - - getWorkspacesSpy.mockImplementation(({ offset }) => { - switch (offset) { - case 0: - return Promise.resolve({ - workspaces: workspacesPage1, - count: totalWorkspaces, - }); - case 25: - return Promise.resolve({ - workspaces: workspacesPage2, - count: totalWorkspaces, - }); - default: - return Promise.reject(new Error("Unexpected offset")); - } - }); - - const user = userEvent.setup(); - renderWithAuth(); - - await waitFor(() => { - expect(screen.getByText("page1-workspace-0")).toBeInTheDocument(); - }); - - expect(getWorkspacesSpy).toHaveBeenLastCalledWith({ - q: "owner:me", - offset: 0, - limit: 25, - }); - - const nextPageButton = screen.getByRole("button", { name: /next page/i }); - await user.click(nextPageButton); - - await waitFor(() => { - expect(screen.getByText("page2-workspace-0")).toBeInTheDocument(); - }); - - expect(getWorkspacesSpy).toHaveBeenLastCalledWith({ - q: "owner:me", - offset: 25, - limit: 25, - }); - - expect(screen.queryByText("page1-workspace-0")).not.toBeInTheDocument(); - }); }); const getWorkspaceCheckbox = (workspace: Workspace) => {