Skip to content

Commit bca65db

Browse files
committed
test(storage): add tests
1 parent affb5ef commit bca65db

File tree

4 files changed

+148
-21
lines changed

4 files changed

+148
-21
lines changed

Diff for: src/storage/index.ts

+22-19
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,16 @@ export function useStorageUrl(
5656
url.value
5757
) as string
5858
const promise = ref<Promise<string | null>>(Promise.resolve(null))
59+
// TODO: pending and error states?
5960
let removePendingPromise = noop
6061

6162
function refresh() {
6263
const storageSource = unref(storageRef)
6364
if (storageSource) {
64-
promise.value = getDownloadURL(storageSource).then(
65-
(downloadUrl) => (url.value = downloadUrl)
66-
)
65+
promise.value = getDownloadURL(storageSource)
66+
.then((downloadUrl) => (url.value = downloadUrl))
67+
// TODO: refactor with error states
68+
.catch(() => null)
6769
} else {
6870
promise.value = Promise.resolve((url.value = null))
6971
}
@@ -117,9 +119,10 @@ export function useStorageMetadata(
117119
function refresh() {
118120
const storageSource = unref(storageRef)
119121
if (storageSource) {
120-
promise.value = getMetadata(storageSource).then(
121-
(data) => (metadata.value = data)
122-
)
122+
promise.value = getMetadata(storageSource)
123+
.then((data) => (metadata.value = data))
124+
// TODO: refactor with error states
125+
.catch(() => null)
123126
} else {
124127
promise.value = Promise.resolve((metadata.value = null))
125128
}
@@ -215,19 +218,19 @@ export function useStorageObject(
215218
snapshot.value = newSnapshot
216219
})
217220

218-
newTask.then((finalSnapshot) => {
219-
uploadTask.value = null
220-
unsub()
221-
metadata.value = finalSnapshot.metadata
222-
// get the new download URL
223-
refreshUrl()
224-
})
225-
226-
newTask.catch((err) => {
227-
unsub()
228-
uploadTask.value = null
229-
uploadError.value = err
230-
})
221+
return newTask
222+
.then((finalSnapshot) => {
223+
metadata.value = finalSnapshot.metadata
224+
// get the new download URL
225+
refreshUrl()
226+
})
227+
.catch((err) => {
228+
uploadError.value = err
229+
})
230+
.finally(() => {
231+
unsub()
232+
uploadTask.value = null
233+
})
231234
}
232235
}
233236

Diff for: storage.rules

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
rules_version = '2';
22
service firebase.storage {
33
match /b/{bucket}/o {
4+
match /tests/{allPaths=**} {
5+
allow read, write: if true;
6+
}
47
match /{allPaths=**} {
58
allow read, write: if false;
69
}

Diff for: tests/storage/index.spec.ts

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { mount } from '@vue/test-utils'
2+
import { it, describe, expect } from 'vitest'
3+
import { uploadString } from 'firebase/storage'
4+
import { nextTick, ref } from 'vue'
5+
import {
6+
useStorage,
7+
useStorageMetadata,
8+
useStorageObject,
9+
useStorageUrl,
10+
} from '../../src'
11+
import { setupStorageRefs } from '../utils'
12+
13+
describe('Storage', () => {
14+
const { storageRef } = setupStorageRefs()
15+
16+
it('generates a URL', async () => {
17+
const objectRef = storageRef('my-url.jpg')
18+
await uploadString(objectRef, 'test', 'raw')
19+
const wrapper = mount({
20+
template: 'no',
21+
setup() {
22+
const { url, promise } = useStorageUrl(objectRef)
23+
24+
return { url, promise }
25+
},
26+
})
27+
28+
await wrapper.vm.promise
29+
30+
expect(wrapper.vm.url).toBeTypeOf('string')
31+
expect(wrapper.vm.url).toMatch(/my-url\.jpg/)
32+
})
33+
34+
it('generates the metadata', async () => {
35+
const objectRef = storageRef('my-url.jpg')
36+
await uploadString(objectRef, 'test', 'raw')
37+
const wrapper = mount({
38+
template: 'no',
39+
setup() {
40+
const { metadata, promise } = useStorageMetadata(objectRef)
41+
42+
return { metadata, promise }
43+
},
44+
})
45+
46+
await wrapper.vm.promise
47+
48+
expect(wrapper.vm.metadata).toBeTypeOf('object')
49+
expect(wrapper.vm.metadata).toMatchObject({
50+
name: 'my-url.jpg',
51+
})
52+
})
53+
54+
it('can create upload tasks', async () => {
55+
const objectRef = storageRef('my-url.jpg')
56+
await uploadString(objectRef, 'test', 'raw')
57+
const wrapper = mount({
58+
template: 'no',
59+
setup() {
60+
const { uploadTask, upload, uploadProgress } =
61+
useStorageObject(objectRef)
62+
63+
return { uploadTask, upload, uploadProgress }
64+
},
65+
})
66+
67+
await nextTick()
68+
69+
expect(wrapper.vm.uploadTask).toBeFalsy()
70+
expect(wrapper.vm.uploadProgress).toBe(null)
71+
72+
// add a task
73+
const p = wrapper.vm.upload(new Uint8Array([0x48, 0x65]))
74+
expect(wrapper.vm.uploadTask).toBeTruthy()
75+
expect(wrapper.vm.uploadProgress).toBeTypeOf('number')
76+
77+
await p
78+
expect(wrapper.vm.uploadTask).toBeFalsy()
79+
expect(wrapper.vm.uploadProgress).toBe(1) // 100%
80+
})
81+
})

Diff for: tests/utils.ts

+42-2
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,59 @@ import {
3030
SetOptions,
3131
WithFieldValue,
3232
} from 'firebase/firestore'
33+
import {
34+
connectStorageEmulator,
35+
getStorage,
36+
ref as storageRef,
37+
StorageReference,
38+
deleteObject,
39+
listAll,
40+
} from 'firebase/storage'
3341
import { afterAll, beforeAll } from 'vitest'
3442
import { nextTick } from 'vue'
3543
import { isCollectionRef, isDocumentRef } from '../src/shared'
3644

37-
export const firebaseApp = initializeApp({ projectId: 'vue-fire-store' })
45+
export const firebaseApp = initializeApp({
46+
projectId: 'vue-fire-store',
47+
storageBucket: 'vue-fire-store.appspot.com',
48+
})
3849
export const firestore = getFirestore(firebaseApp)
3950
export const database = getDatabase(firebaseApp)
51+
export const storage = getStorage(firebaseApp)
4052

4153
connectFirestoreEmulator(firestore, 'localhost', 8080)
4254
connectDatabaseEmulator(database, 'localhost', 8081)
55+
connectStorageEmulator(storage, 'localhost', 9199)
4356

4457
let _id = 0
4558

59+
// Storage
60+
export function setupStorageRefs() {
61+
const bucket = `tests/${Date.now()}-${_id++}/`
62+
function _storageRef(
63+
storageRefOrPath?: string | StorageReference,
64+
path?: string
65+
): StorageReference {
66+
const _storage =
67+
(typeof storageRefOrPath === 'string' ? storage : storageRefOrPath) ||
68+
storage
69+
const _path =
70+
(typeof storageRefOrPath === 'string' ? storageRefOrPath : path) ||
71+
`test/${_id++}.jpg`
72+
return storageRef(_storage, bucket + _path)
73+
}
74+
75+
afterAll(async () => {
76+
const list = await listAll(storageRef(storage, bucket))
77+
await Promise.all(list.items.map((item) => deleteObject(item)))
78+
})
79+
80+
return { storageRef: _storageRef }
81+
}
82+
4683
// Firestore
47-
export function setupFirestoreRefs() {
84+
// TODO: use the id in all tests to try if it makes them more stable
85+
export function setupFirestoreRefs(id?: string) {
4886
const testId = _id++
4987
const testsCollection = collection(firestore, `__tests`)
5088
const itemRef = doc(testsCollection)
@@ -65,9 +103,11 @@ export function setupFirestoreRefs() {
65103
deleteDoc(itemRef),
66104
...[...docsToClean].map((doc) => deleteDoc(doc)),
67105
])
106+
68107
await Promise.all(
69108
[...collectionsToClean].map((collection) => clearCollection(collection))
70109
)
110+
71111
await clearCollection(forDocRefs)
72112
// must be done after the cleanup of its docs
73113
await deleteDoc(forCollectionRefs)

0 commit comments

Comments
 (0)