Fix attachment preview test act helpers

This commit is contained in:
Dotta 2026-06-01 21:48:43 +00:00
parent 8af359b656
commit 63a2b5ba1c
2 changed files with 40 additions and 6 deletions

View file

@ -2,7 +2,8 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import type { IssueAttachment } from "@paperclipai/shared"; import type { IssueAttachment } from "@paperclipai/shared";
import { act, type ComponentProps, type ReactNode } from "react"; import type { ComponentProps, ReactNode } from "react";
import { flushSync } from "react-dom";
import { createRoot, type Root } from "react-dom/client"; import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { IssueAttachmentsSection } from "./IssueAttachmentsSection"; import { IssueAttachmentsSection } from "./IssueAttachmentsSection";
@ -33,6 +34,14 @@ vi.mock("@/components/ui/button", () => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; (globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
async function act(callback: () => void | Promise<void>) {
let result: void | Promise<void> = undefined;
flushSync(() => {
result = callback();
});
await result;
}
function makeAttachment(overrides: Partial<IssueAttachment> = {}): IssueAttachment { function makeAttachment(overrides: Partial<IssueAttachment> = {}): IssueAttachment {
return { return {
id: "attachment-1", id: "attachment-1",
@ -64,6 +73,20 @@ async function flushReact() {
}); });
} }
async function waitForAssertion(assertion: () => void, attempts = 20) {
let lastError: unknown;
for (let index = 0; index < attempts; index += 1) {
try {
assertion();
return;
} catch (error) {
lastError = error;
await flushReact();
}
}
throw lastError;
}
describe("IssueAttachmentsSection", () => { describe("IssueAttachmentsSection", () => {
let container: HTMLDivElement; let container: HTMLDivElement;
let root: Root; let root: Root;
@ -122,10 +145,12 @@ describe("IssueAttachmentsSection", () => {
headers: expect.objectContaining({ Accept: expect.stringContaining("text/markdown") }), headers: expect.objectContaining({ Accept: expect.stringContaining("text/markdown") }),
}), }),
); );
expect(container.querySelector('[data-testid="fold-curtain"]')).toBeTruthy(); await waitForAssertion(() => {
const markdownBody = container.querySelector('[data-testid="markdown-body"]'); expect(container.querySelector('[data-testid="fold-curtain"]')).toBeTruthy();
expect(markdownBody?.textContent).toContain("Imported plan"); const markdownBody = container.querySelector('[data-testid="markdown-body"]');
expect(markdownBody?.className).toContain("paperclip-edit-in-place-content"); expect(markdownBody?.textContent).toContain("Imported plan");
expect(markdownBody?.className).toContain("paperclip-edit-in-place-content");
});
}); });
it("renders video attachments through the same player used for artifact outputs", async () => { it("renders video attachments through the same player used for artifact outputs", async () => {

View file

@ -2,7 +2,8 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import type { Agent, Issue, IssueTreeControlPreview, IssueTreeHold } from "@paperclipai/shared"; import type { Agent, Issue, IssueTreeControlPreview, IssueTreeHold } from "@paperclipai/shared";
import { act, type AnchorHTMLAttributes, type ButtonHTMLAttributes, type ReactNode } from "react"; import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from "react";
import { flushSync } from "react-dom";
import { createRoot, type Root } from "react-dom/client"; import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { canBoardResolveRecoveryAction, IssueDetail } from "./IssueDetail"; import { canBoardResolveRecoveryAction, IssueDetail } from "./IssueDetail";
@ -357,6 +358,14 @@ vi.mock("@/components/ui/textarea", () => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; (globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
async function act(callback: () => void | Promise<void>) {
let result: void | Promise<void> = undefined;
flushSync(() => {
result = callback();
});
await result;
}
function createDeferred<T>() { function createDeferred<T>() {
let resolve!: (value: T) => void; let resolve!: (value: T) => void;
const promise = new Promise<T>((innerResolve) => { const promise = new Promise<T>((innerResolve) => {