Skip to content

Commit 0c26c49

Browse files
authored
Merge pull request #101 from HassanBahati/add-usefirestoredocument-tests
2 parents 74d675d + ba9babb commit 0c26c49

File tree

5 files changed

+170
-59
lines changed

5 files changed

+170
-59
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { useFirestoreDocument } from "./useFirestoreDocument";
1+
export { useDocumentQuery } from "./useDocumentQuery";
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import React, { type ReactNode } from "react";
2+
import { describe, expect, test, beforeEach } from "vitest";
3+
import { useDocumentQuery } from "./useDocumentQuery";
4+
import { renderHook, waitFor } from "@testing-library/react";
5+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
6+
import { doc, setDoc } from "firebase/firestore";
7+
8+
import {
9+
expectFirestoreError,
10+
firestore,
11+
wipeFirestore,
12+
} from "~/testing-utils";
13+
14+
const queryClient = new QueryClient({
15+
defaultOptions: {
16+
queries: {
17+
retry: false,
18+
},
19+
},
20+
});
21+
22+
const wrapper = ({ children }: { children: ReactNode }) => (
23+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
24+
);
25+
26+
describe("useDocumentQuery", () => {
27+
beforeEach(async () => {
28+
await wipeFirestore();
29+
});
30+
31+
test("it works", async () => {
32+
const ref = doc(firestore, "tests", "useDocumentQuery");
33+
34+
// Set some data
35+
await setDoc(ref, { foo: "bar" });
36+
37+
// Test the hook
38+
const { result } = renderHook(
39+
() =>
40+
useDocumentQuery(ref, {
41+
queryKey: ["some", "doc"],
42+
}),
43+
{ wrapper }
44+
);
45+
46+
// Wait for the query to finish
47+
await waitFor(() => {
48+
expect(result.current.isSuccess).toBe(true);
49+
});
50+
51+
// It shoiuld exist and have data.
52+
expect(result.current.data).toBeDefined();
53+
54+
const snapshot = result.current.data!;
55+
expect(snapshot.exists()).toBe(true);
56+
expect(snapshot.data()?.foo).toBe("bar");
57+
});
58+
59+
test("fetches document from server source", async () => {
60+
const ref = doc(firestore, "tests", "serverSource");
61+
62+
// set data
63+
await setDoc(ref, { foo: "fromServer" });
64+
65+
//test the hook
66+
const { result } = renderHook(
67+
() =>
68+
useDocumentQuery(ref, {
69+
queryKey: ["server", "doc"],
70+
firestore: { source: "server" },
71+
}),
72+
{ wrapper }
73+
);
74+
75+
// await the query
76+
await waitFor(() => {
77+
expect(result.current.isSuccess).toBe(true);
78+
});
79+
80+
// snapshot should exist, data should be fetched from the server and should contain the correct data
81+
const snapshot = result.current.data;
82+
expect(snapshot?.exists()).toBe(true);
83+
expect(snapshot?.data()?.foo).toBe("fromServer");
84+
});
85+
86+
test("handles restricted collections appropriately", async () => {
87+
const ref = doc(firestore, "restrictedCollection", "someDoc");
88+
89+
const { result } = renderHook(
90+
() =>
91+
useDocumentQuery(ref, {
92+
queryKey: ["restricted", "doc"],
93+
}),
94+
{ wrapper }
95+
);
96+
97+
await waitFor(() => {
98+
expect(result.current.isError).toBe(true);
99+
});
100+
101+
expectFirestoreError(result.current.error, "permission-denied");
102+
});
103+
104+
test("returns pending state initially", async () => {
105+
const ref = doc(firestore, "tests", "pendingState");
106+
107+
setDoc(ref, { foo: "pending" });
108+
109+
const { result } = renderHook(
110+
() =>
111+
useDocumentQuery(ref, {
112+
queryKey: ["pending", "state"],
113+
}),
114+
{ wrapper }
115+
);
116+
117+
// initially isPending should be true
118+
expect(result.current.isPending).toBe(true);
119+
120+
// wait for the query to finish, and should have isSuccess true
121+
await waitFor(() => {
122+
expect(result.current.isSuccess).toBe(true);
123+
});
124+
125+
const snapshot = result.current.data;
126+
expect(snapshot?.exists()).toBe(true);
127+
expect(snapshot?.data()?.foo).toBe("pending");
128+
});
129+
130+
test("returns correct data type", async () => {
131+
const ref = doc(firestore, "tests", "typedDoc");
132+
133+
setDoc(ref, { foo: "bar", num: 23 } as { foo: string; num: number });
134+
135+
const { result } = renderHook(
136+
() =>
137+
useDocumentQuery(ref, {
138+
queryKey: ["typed", "doc"],
139+
}),
140+
{ wrapper }
141+
);
142+
143+
await waitFor(() => {
144+
expect(result.current.isSuccess).toBe(true);
145+
});
146+
147+
const snapshot = result.current.data;
148+
expect(snapshot?.exists()).toBe(true);
149+
expect(snapshot?.data()?.foo).toBe("bar");
150+
expect(snapshot?.data()?.num).toBe(23);
151+
});
152+
});

packages/react/src/firestore/useFirestoreDocument.ts renamed to packages/react/src/firestore/useDocumentQuery.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type FirestoreUseQueryOptions<TData = unknown, TError = Error> = Omit<
1818
};
1919
};
2020

21-
export function useFirestoreDocument<
21+
export function useDocumentQuery<
2222
FromFirestore extends DocumentData = DocumentData,
2323
ToFirestore extends DocumentData = DocumentData
2424
>(
@@ -29,7 +29,7 @@ export function useFirestoreDocument<
2929
>
3030
) {
3131
const { firestore, ...queryOptions } = options;
32-
32+
3333
return useQuery<DocumentSnapshot<FromFirestore, ToFirestore>, FirestoreError>(
3434
{
3535
...queryOptions,

packages/react/src/firestore/useFirestoreDocument.test.tsx

Lines changed: 0 additions & 54 deletions
This file was deleted.

vitest/utils.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { type FirebaseApp, initializeApp } from "firebase/app";
1+
import { type FirebaseApp, FirebaseError, initializeApp } from "firebase/app";
22
import {
33
getFirestore,
44
connectFirestoreEmulator,
55
type Firestore,
66
} from "firebase/firestore";
7+
import { expect } from "vitest";
78

89
const firebaseTestingOptions = {
910
projectId: "test-project",
@@ -32,4 +33,16 @@ async function wipeFirestore() {
3233
}
3334
}
3435

35-
export { firestore, wipeFirestore };
36+
function expectFirestoreError(error: unknown, expectedCode: string) {
37+
if (error instanceof FirebaseError) {
38+
expect(error).toBeDefined();
39+
expect(error.code).toBeDefined();
40+
expect(error.code).toBe(expectedCode);
41+
} else {
42+
throw new Error(
43+
"Expected a Firestore error, but received a different type."
44+
);
45+
}
46+
}
47+
48+
export { firestore, wipeFirestore, expectFirestoreError };

0 commit comments

Comments
 (0)