Skip to content

Commit 4b510e2

Browse files
committed
refactor: firestoreBind and some tests
1 parent 2862cd1 commit 4b510e2

File tree

14 files changed

+959
-40
lines changed

14 files changed

+959
-40
lines changed

.vscode/settings.json

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

__tests__/src/index.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Vue from 'vue'
1+
import Vue, { nextTick } from 'vue'
22
import { MockFirebase, MockedReference } from 'firebase-mock'
33
import { firestore } from 'firebase'
44
import { walkSet } from '../../src/core'
@@ -60,11 +60,7 @@ export function delayUpdate(ref: firestore.DocumentReference, time = 0) {
6060
})
6161
}
6262

63-
export function tick() {
64-
return new Promise((resolve) => {
65-
Vue.nextTick(resolve)
66-
})
67-
}
63+
export const tick = nextTick
6864

6965
export function delay(time: number) {
7066
return new Promise((resolve) => setTimeout(resolve, time))
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
import { firestorePlugin } from '../../../src'
2+
import { db, tick, delayUpdate } from '../../src'
3+
import { firestore } from 'firebase'
4+
import { ComponentPublicInstance } from 'vue'
5+
import { mount, VueWrapper } from '@vue/test-utils'
6+
7+
describe('Firestore: binding', () => {
8+
let collection: firestore.CollectionReference
9+
let document: firestore.DocumentReference
10+
let vm: ComponentPublicInstance & { items: any[]; item: any }
11+
let wrapper: VueWrapper<ComponentPublicInstance & { items: any[]; item: any }>
12+
beforeEach(async () => {
13+
// @ts-ignore
14+
collection = db.collection()
15+
// @ts-ignore
16+
document = db.collection().doc()
17+
18+
wrapper = mount(
19+
{
20+
template: 'no',
21+
// purposely set items as null
22+
// but it's a good practice to set it to an empty array
23+
data: () => ({
24+
items: null,
25+
item: null,
26+
}),
27+
},
28+
{ global: { plugins: [firestorePlugin] } }
29+
)
30+
await tick()
31+
vm = wrapper.vm
32+
})
33+
34+
it.only('manually binds a collection', async () => {
35+
expect(vm.items).toEqual(null)
36+
await vm.$bind('items', collection)
37+
expect(vm.items).toEqual([])
38+
await collection.add({ text: 'foo' })
39+
expect(vm.items).toEqual([{ text: 'foo' }])
40+
})
41+
42+
it('manually binds a document', async () => {
43+
expect(vm.item).toEqual(null)
44+
await vm.$bind('item', document)
45+
expect(vm.item).toEqual(null)
46+
await document.update({ text: 'foo' })
47+
expect(vm.item).toEqual({ text: 'foo' })
48+
})
49+
50+
it('removes items', async () => {
51+
collection.add({ name: 'one' })
52+
collection.add({ name: 'two' })
53+
54+
await vm.$bind('items', collection)
55+
await collection.doc(vm.items[1].id).delete()
56+
expect(vm.items).toEqual([{ name: 'one' }])
57+
})
58+
59+
it('returs a promise', () => {
60+
expect(vm.$bind('items', collection) instanceof Promise).toBe(true)
61+
expect(vm.$bind('item', document) instanceof Promise).toBe(true)
62+
})
63+
64+
it('unbinds previously bound refs', async () => {
65+
await document.update({ foo: 'foo' })
66+
// @ts-ignore
67+
const doc2: firestore.DocumentReference = db.collection().doc()
68+
await doc2.update({ bar: 'bar' })
69+
await vm.$bind('item', document)
70+
expect(vm.$firestoreRefs.item).toBe(document)
71+
expect(vm.item).toEqual({ foo: 'foo' })
72+
await vm.$bind('item', doc2)
73+
expect(vm.item).toEqual({ bar: 'bar' })
74+
await document.update({ foo: 'baz' })
75+
expect(vm.$firestoreRefs.item).toBe(doc2)
76+
expect(vm.item).toEqual({ bar: 'bar' })
77+
})
78+
79+
it('waits for all refs in document', async () => {
80+
const a = db.collection().doc()
81+
// @ts-ignore
82+
const b: firestore.DocumentReference = db.collection().doc()
83+
delayUpdate(b)
84+
await document.update({ a, b })
85+
86+
await vm.$bind('item', document)
87+
88+
expect(vm.item).toEqual({
89+
a: null,
90+
b: null,
91+
})
92+
})
93+
94+
test('waits for all refs in document with interrupting by new ref', async () => {
95+
const a = db.collection().doc()
96+
// @ts-ignore
97+
const b: firestore.DocumentReference = db.collection().doc()
98+
const c = db.collection().doc()
99+
delayUpdate(b)
100+
await document.update({ a, b })
101+
102+
const promise = vm.$bind('item', document)
103+
104+
document.update({ c })
105+
106+
await promise
107+
108+
expect(vm.item).toEqual({
109+
a: null,
110+
b: null,
111+
c: null,
112+
})
113+
})
114+
115+
it('waits for all refs in collection', async () => {
116+
const a = db.collection().doc()
117+
// @ts-ignore
118+
const b: firestore.DocumentReference = db.collection().doc()
119+
delayUpdate(b)
120+
await collection.add({ a })
121+
await collection.add({ b })
122+
123+
await vm.$bind('items', collection)
124+
125+
expect(vm.items).toEqual([{ a: null }, { b: null }])
126+
})
127+
128+
it('waits for nested refs in document', async () => {
129+
const a = db.collection().doc()
130+
// @ts-ignore
131+
const b: firestore.DocumentReference = db.collection().doc()
132+
// @ts-ignore
133+
const c: firestore.DocumentReference = db.collection().doc()
134+
await b.update({ c })
135+
delayUpdate(b)
136+
delayUpdate(c, 5)
137+
await document.update({ a, b })
138+
139+
await vm.$bind('item', document)
140+
141+
expect(vm.item).toEqual({
142+
a: null,
143+
b: { c: null },
144+
})
145+
})
146+
147+
it('waits for nested refs with data in document', async () => {
148+
const a = db.collection().doc()
149+
// @ts-ignore
150+
const b: firestore.DocumentReference = db.collection().doc()
151+
// @ts-ignore
152+
const c: firestore.DocumentReference = db.collection().doc()
153+
await a.update({ isA: true })
154+
await c.update({ isC: true })
155+
await b.update({ c })
156+
delayUpdate(b)
157+
delayUpdate(c, 5)
158+
await document.update({ a, b })
159+
160+
await vm.$bind('item', document)
161+
162+
expect(vm.item).toEqual({
163+
a: { isA: true },
164+
b: { c: { isC: true } },
165+
})
166+
})
167+
168+
it('waits for nested refs in collections', async () => {
169+
const a = db.collection().doc()
170+
// @ts-ignore
171+
const b: firestore.DocumentReference = db.collection().doc()
172+
// @ts-ignore
173+
const c: firestore.DocumentReference = db.collection().doc()
174+
await b.update({ c })
175+
delayUpdate(b)
176+
delayUpdate(c, 5)
177+
await collection.add({ a })
178+
await collection.add({ b })
179+
180+
await vm.$bind('items', collection)
181+
182+
expect(vm.items).toEqual([{ a: null }, { b: { c: null } }])
183+
})
184+
185+
it('waits for nested refs with data in collections', async () => {
186+
const a = db.collection().doc()
187+
// @ts-ignore
188+
const b: firestore.DocumentReference = db.collection().doc()
189+
// @ts-ignore
190+
const c: firestore.DocumentReference = db.collection().doc()
191+
await a.update({ isA: true })
192+
await c.update({ isC: true })
193+
await b.update({ c })
194+
delayUpdate(b)
195+
delayUpdate(c, 5)
196+
await collection.add({ a })
197+
await collection.add({ b })
198+
199+
await vm.$bind('items', collection)
200+
201+
expect(vm.items).toEqual([
202+
{ a: { isA: true } },
203+
{ b: { c: { isC: true } } },
204+
])
205+
})
206+
207+
it('can customize the reset option through $bind', async () => {
208+
await document.update({ foo: 'foo' })
209+
// @ts-ignore
210+
const doc2: firestore.DocumentReference = db.collection().doc()
211+
await doc2.update({ bar: 'bar' })
212+
await vm.$bind('item', document)
213+
expect(vm.item).toEqual({ foo: 'foo' })
214+
const p = vm.$bind('item', doc2, { reset: false })
215+
expect(vm.item).toEqual({ foo: 'foo' })
216+
await p
217+
expect(vm.item).toEqual({ bar: 'bar' })
218+
vm.$bind('item', document)
219+
expect(vm.item).toEqual(null)
220+
})
221+
222+
it('can customize the reset option through $unbind', async () => {
223+
await document.update({ foo: 'foo' })
224+
// @ts-ignore
225+
const doc2: firestore.DocumentReference = db.collection().doc()
226+
await doc2.update({ bar: 'bar' })
227+
await vm.$bind('item', document)
228+
vm.$unbind('item', false)
229+
expect(vm.item).toEqual({ foo: 'foo' })
230+
// the reset option should have no effect on the latter unbind
231+
await vm.$bind('item', document, { reset: () => ({ bar: 'bar' }) })
232+
vm.$unbind('item')
233+
expect(vm.item).toEqual(null)
234+
})
235+
236+
it('do not reset if wait: true', async () => {
237+
await collection.add({ foo: 'foo' })
238+
await vm.$bind('items', collection)
239+
// @ts-ignore
240+
const col2: firestore.CollectionReference = db.collection()
241+
await col2.add({ bar: 'bar' })
242+
const p = vm.$bind('items', col2, { wait: true, reset: true })
243+
expect(vm.items).toEqual([{ foo: 'foo' }])
244+
await p
245+
expect(vm.items).toEqual([{ bar: 'bar' }])
246+
})
247+
248+
it('wait + reset can be overriden with a function', async () => {
249+
await collection.add({ foo: 'foo' })
250+
await vm.$bind('items', collection)
251+
// @ts-ignore
252+
const col2: firestore.CollectionReference = db.collection()
253+
await col2.add({ bar: 'bar' })
254+
const p = vm.$bind('items', col2, { wait: true, reset: () => ['foo'] })
255+
expect(vm.items).toEqual(['foo'])
256+
await p
257+
expect(vm.items).toEqual([{ bar: 'bar' }])
258+
})
259+
})
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { firestorePlugin } from '../../src'
2+
import { db, tick, Vue } from '@posva/vuefire-test-helpers'
3+
import { firestore } from 'firebase'
4+
import { CombinedVueInstance } from 'vue/types/vue'
5+
6+
Vue.use(firestorePlugin)
7+
8+
describe('Firestore: firestore option', () => {
9+
let collection: firestore.CollectionReference,
10+
document: firestore.DocumentReference,
11+
vm: CombinedVueInstance<
12+
Vue,
13+
{ items: any[]; item: any },
14+
object,
15+
object,
16+
Record<never, any>
17+
>
18+
beforeEach(async () => {
19+
// @ts-ignore
20+
collection = db.collection()
21+
document = collection.doc()
22+
// @ts-ignore
23+
vm = new Vue({
24+
// purposely set items as null
25+
// but it's a good practice to set it to an empty array
26+
data: () => ({
27+
items: null,
28+
item: null,
29+
}),
30+
firestore: {
31+
items: collection,
32+
item: document,
33+
},
34+
})
35+
await tick()
36+
})
37+
38+
it('does nothing with no firestore', () => {
39+
const vm = new Vue({
40+
data: () => ({ items: null }),
41+
})
42+
expect(vm.items).toEqual(null)
43+
})
44+
45+
it('setups _firestoreUnbinds', () => {
46+
expect(vm._firestoreUnbinds).toBeTruthy()
47+
expect(Object.keys(vm._firestoreUnbinds).sort()).toEqual(['item', 'items'])
48+
})
49+
50+
it('setups _firestoreUnbinds with no firestore options', () => {
51+
const vm = new Vue({
52+
data: () => ({ items: null }),
53+
})
54+
expect(vm._firestoreUnbinds).toBeTruthy()
55+
expect(Object.keys(vm._firestoreUnbinds)).toEqual([])
56+
})
57+
58+
it('setups $firestoreRefs', () => {
59+
expect(Object.keys(vm.$firestoreRefs).sort()).toEqual(['item', 'items'])
60+
expect(vm.$firestoreRefs.item).toBe(document)
61+
expect(vm.$firestoreRefs.items).toBe(collection)
62+
})
63+
64+
it('clears $firestoreRefs on $destroy', () => {
65+
vm.$destroy()
66+
expect(vm.$firestoreRefs).toEqual(null)
67+
})
68+
})

0 commit comments

Comments
 (0)