11import { describe , it , expect , vi , beforeEach , afterEach } from "vitest" ;
2- import { render , screen } from "@testing-library/react" ;
3- import ShareProjectButton from "@/components/share-project-button" ;
2+ import { render , screen , waitFor } from "@testing-library/react" ;
3+ import userEvent from "@testing-library/user-event" ;
4+
5+ const encryptProjectIdMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
6+ vi . mock ( "@/utils/crypto" , ( ) => ( {
7+ encryptProjectId : encryptProjectIdMock ,
8+ } ) ) ;
49
5- const originalFetch = globalThis . fetch ;
10+ const copyMock = vi . hoisted ( ( ) => vi . fn ( ( ) => true ) ) ;
11+ vi . mock ( "copy-to-clipboard" , ( ) => ( {
12+ default : copyMock ,
13+ } ) ) ;
14+
15+ import ShareProjectButton from "@/components/share-project-button" ;
616
717beforeEach ( ( ) => {
8- globalThis . fetch = vi . fn ( async ( ) => ( {
9- ok : true ,
10- status : 200 ,
11- json : async ( ) => ( { encrypted_id : "enc-123" } ) ,
12- } ) ) as unknown as typeof fetch ;
18+ encryptProjectIdMock . mockReset ( ) ;
19+ encryptProjectIdMock . mockResolvedValue ( "enc-token-xyz" ) ;
20+ copyMock . mockReset ( ) ;
21+ copyMock . mockReturnValue ( true ) ;
1322} ) ;
1423
1524afterEach ( ( ) => {
16- globalThis . fetch = originalFetch ;
1725 vi . restoreAllMocks ( ) ;
1826} ) ;
1927
@@ -23,6 +31,7 @@ describe("ShareProjectButton", () => {
2331 < ShareProjectButton projectId = "p1" isPublic = { false } /> ,
2432 ) ;
2533 expect ( container . textContent ) . toBe ( "" ) ;
34+ expect ( encryptProjectIdMock ) . not . toHaveBeenCalled ( ) ;
2635 } ) ;
2736
2837 it ( "renders the share trigger for public projects" , ( ) => {
@@ -31,4 +40,27 @@ describe("ShareProjectButton", () => {
3140 screen . getByRole ( "button" , { name : / s h a r e p r o j e c t / i } ) ,
3241 ) . toBeInTheDocument ( ) ;
3342 } ) ;
43+
44+ it ( "computes the encrypted id client-side when the popover opens" , async ( ) => {
45+ render ( < ShareProjectButton projectId = "p1" isPublic = { true } /> ) ;
46+
47+ await userEvent . click (
48+ screen . getByRole ( "button" , { name : / s h a r e p r o j e c t / i } ) ,
49+ ) ;
50+
51+ await waitFor ( ( ) =>
52+ expect ( encryptProjectIdMock ) . toHaveBeenCalledWith ( "p1" ) ,
53+ ) ;
54+
55+ // The encrypted token shows up in the share-link input.
56+ const input = await screen . findByDisplayValue (
57+ / \/ p u b l i c \/ p r o j e c t s \/ e n c - t o k e n - x y z $ / ,
58+ ) ;
59+ expect ( input ) . toBeInTheDocument ( ) ;
60+ } ) ;
61+
62+ it ( "does not call the encryptor before the popover is opened" , ( ) => {
63+ render ( < ShareProjectButton projectId = "p1" isPublic = { true } /> ) ;
64+ expect ( encryptProjectIdMock ) . not . toHaveBeenCalled ( ) ;
65+ } ) ;
3466} ) ;
0 commit comments