Skip to content

Commit 53baa96

Browse files
committed
test: refs in docs
1 parent 6e62abf commit 53baa96

File tree

1 file changed

+203
-0
lines changed

1 file changed

+203
-0
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import { mount } from '@vue/test-utils'
2+
import { beforeEach, describe, it, expect, afterEach } from 'vitest'
3+
import {
4+
CollectionReference,
5+
doc as originalDoc,
6+
DocumentData,
7+
DocumentReference,
8+
} from 'firebase/firestore'
9+
import { setupFirestoreRefs, sleep } from '../utils'
10+
import { unref } from 'vue'
11+
import { _InferReferenceType, _RefFirestore } from '../../src/firestore'
12+
import {
13+
UseDocumentOptions,
14+
usePendingPromises,
15+
VueFirestoreQueryData,
16+
useDocument,
17+
} from '../../src'
18+
import { _MaybeRef } from '../../src/shared'
19+
20+
describe('Firestore refs in documents', async () => {
21+
const { collection, query, addDoc, setDoc, updateDoc, deleteDoc, doc } =
22+
setupFirestoreRefs()
23+
24+
function factory<T = DocumentData>({
25+
options,
26+
ref = doc(),
27+
}: {
28+
options?: UseDocumentOptions
29+
ref?: _MaybeRef<DocumentReference<T>>
30+
} = {}) {
31+
let data!: _RefFirestore<VueFirestoreQueryData<T>>
32+
33+
const wrapper = mount({
34+
template: 'no',
35+
setup() {
36+
// @ts-expect-error: generic forced
37+
data =
38+
// split for ts
39+
useDocument(ref, options)
40+
const { data: list, pending, error, promise, unbind } = data
41+
return { list, pending, error, promise, unbind }
42+
},
43+
})
44+
45+
return {
46+
wrapper,
47+
listRef: unref(ref),
48+
// non enumerable properties cannot be spread
49+
data: data.data,
50+
pending: data.pending,
51+
error: data.error,
52+
promise: data.promise,
53+
unbind: data.unbind,
54+
}
55+
}
56+
57+
const listOfRefs = collection()
58+
// NOTE: it doesn't work in tests if it's the same collection but works in dev
59+
// const listOfRefs = listRef
60+
const aRef = originalDoc(listOfRefs, 'a')
61+
const bRef = originalDoc(listOfRefs, 'b')
62+
const cRef = originalDoc(listOfRefs, 'c')
63+
const emptyRef = originalDoc(listOfRefs, 'empty')
64+
65+
beforeEach(async () => {
66+
await setDoc(aRef, { name: 'a' })
67+
await setDoc(bRef, { name: 'b' })
68+
await setDoc(cRef, { name: 'c' })
69+
})
70+
71+
afterEach(async () => {
72+
await deleteDoc(emptyRef)
73+
})
74+
75+
it('waits for refs in a document', async () => {
76+
const docRef = await addDoc(listOfRefs, { a: aRef })
77+
const { data, pending, promise } = factory({ ref: docRef })
78+
79+
await promise.value
80+
expect(data.value).toEqual({
81+
a: { name: 'a' },
82+
})
83+
})
84+
85+
it('binds newly added refs', async () => {
86+
const docRef = await addDoc(listOfRefs, { a: aRef })
87+
const { data, pending, promise } = factory({ ref: docRef })
88+
89+
await promise.value
90+
await updateDoc(docRef, { b: bRef })
91+
await sleep(20)
92+
await promise.value
93+
94+
expect(data.value).toEqual({
95+
a: { name: 'a' },
96+
b: { name: 'b' },
97+
})
98+
})
99+
100+
it('subscribes to changes in nested refs', async () => {
101+
const docRef = await addDoc(listOfRefs, { a: aRef })
102+
const { data, pending, promise } = factory({ ref: docRef })
103+
104+
await promise.value
105+
await setDoc(aRef, { b: bRef })
106+
await sleep(20)
107+
await promise.value
108+
109+
expect(data.value).toEqual({
110+
a: { b: { name: 'b' } },
111+
})
112+
113+
await updateDoc(bRef, { name: 'b2' })
114+
115+
await sleep(20)
116+
expect(data.value).toEqual({
117+
a: { b: { name: 'b2' } },
118+
})
119+
})
120+
121+
it('unsubscribes from a ref if it is replaced', async () => {
122+
const docRef = await addDoc(listOfRefs, { a: aRef })
123+
const { data, pending, promise } = factory({ ref: docRef })
124+
125+
await promise.value
126+
await updateDoc(docRef, { a: 'plain' })
127+
await updateDoc(aRef, { name: 'a2' })
128+
await sleep(20)
129+
await promise.value
130+
131+
expect(data.value).toEqual({ a: 'plain' })
132+
})
133+
134+
it('keeps null for non existing refs', async () => {
135+
const docRef = await addDoc(listOfRefs, { a: emptyRef })
136+
const { data, pending, promise } = factory({ ref: docRef })
137+
138+
await promise.value
139+
expect(data.value).toEqual({ a: null })
140+
141+
await setDoc(emptyRef, { name: 'a' })
142+
await sleep(20)
143+
expect(data.value).not.toEqual({ a: null })
144+
145+
await deleteDoc(emptyRef)
146+
await sleep(20)
147+
expect(data.value).toEqual({ a: null })
148+
})
149+
150+
it('can have a max depth of 0', async () => {
151+
const docRef = await addDoc(listOfRefs, { a: aRef })
152+
const { data, pending, promise } = factory({
153+
ref: docRef,
154+
options: { maxRefDepth: 0 },
155+
})
156+
157+
await promise.value
158+
expect(data.value).toEqual({ a: aRef.path })
159+
})
160+
161+
it('does not fail with cyclic refs', async () => {
162+
const docRef = await addDoc(listOfRefs, {})
163+
await setDoc(docRef, { ref: docRef })
164+
const { data, pending, promise } = factory({ ref: docRef })
165+
166+
await promise.value
167+
expect(data.value).toEqual({
168+
ref: {
169+
ref: {
170+
ref: expect.any(String),
171+
},
172+
},
173+
})
174+
})
175+
176+
it('should remove elements from arays', async () => {
177+
const docRef = await addDoc(listOfRefs, { a: [aRef, bRef, cRef] })
178+
const { data, pending, promise } = factory({
179+
ref: docRef,
180+
options: { maxRefDepth: 0 },
181+
})
182+
183+
await promise.value
184+
expect(data.value).toEqual({ a: [aRef.path, bRef.path, cRef.path] })
185+
await updateDoc(docRef, { a: [aRef, cRef] })
186+
await promise.value
187+
188+
expect(data.value).toEqual({ a: [aRef.path, cRef.path] })
189+
})
190+
191+
it('keeps empty refs when a document is updated', async () => {
192+
const docRef = await addDoc(listOfRefs, { a: emptyRef, b: 'b' })
193+
const { data, pending, promise } = factory({ ref: docRef })
194+
195+
await updateDoc(docRef, { b: 'other' })
196+
await promise.value
197+
198+
expect(data.value).toEqual({
199+
a: null,
200+
b: 'other',
201+
})
202+
})
203+
})

0 commit comments

Comments
 (0)