Skip to content

Commit

Permalink
test: add useMutation
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Dec 25, 2023
1 parent 638f626 commit cee4a36
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 32 deletions.
55 changes: 38 additions & 17 deletions src/data-fetching-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,26 +137,35 @@ export const useDataFetchingStore = defineStore('PiniaColada', () => {
error: null as TError | null,
} satisfies UseQueryPropertiesEntry<TResult, TError>['previous']

entry.pending = {
// we create an object and verify we are the most recent pending request
// before doing anything
const pendingEntry = {
refreshCall: fetcher()
.then((data) => {
nextPrevious.data = data
entry.data.value = data
entry.status.value = 'success'
if (pendingEntry === entry.pending) {
nextPrevious.data = data
entry.data.value = data
entry.status.value = 'success'
}
})
.catch((error) => {
nextPrevious.error = error
entry.error.value = error
entry.status.value = 'error'
if (pendingEntry === entry.pending) {
nextPrevious.error = error
entry.error.value = error
entry.status.value = 'error'
}
})
.finally(() => {
entry.pending = null
nextPrevious.when = Date.now()
entry.previous = nextPrevious
entry.isFetching.value = false
if (pendingEntry === entry.pending) {
entry.pending = null
nextPrevious.when = Date.now()
entry.previous = nextPrevious
entry.isFetching.value = false
}
}),
when: Date.now(),
}
entry.pending = pendingEntry
}

await entry.pending.refreshCall
Expand Down Expand Up @@ -190,14 +199,12 @@ export const useDataFetchingStore = defineStore('PiniaColada', () => {
* @param refetch - whether to force a refresh of the data
*/
function invalidateEntry(key: UseQueryKey, refetch = false) {
if (!entryPropertiesRegistry.has(key)) {
// TODO: dev only
console.warn(
`⚠️ trying to invalidate "${String(key)}" but it's not in the registry`
)
const entry = entryPropertiesRegistry.get(key)

// nothing to invalidate
if (!entry) {
return
}
const entry = entryPropertiesRegistry.get(key)!

if (entry.previous) {
// will force a fetch next time
Expand All @@ -212,6 +219,19 @@ export const useDataFetchingStore = defineStore('PiniaColada', () => {
}
}

function setEntryData<TResult = unknown>(key: UseQueryKey, data: TResult) {
const entry = entryStateRegistry.get(key) as
| UseQueryStateEntry<TResult>
| undefined
if (!entry) {
return
}

entry.data.value = data
// TODO: complete and test
entry.error.value = null
}

function prefetch(key: UseQueryKey) {
const entry = entryPropertiesRegistry.get(key)
if (!entry) {
Expand All @@ -228,6 +248,7 @@ export const useDataFetchingStore = defineStore('PiniaColada', () => {

ensureEntry,
invalidateEntry,
setEntryData,
}
})

Expand Down
57 changes: 57 additions & 0 deletions src/use-mutation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { mount } from '@vue/test-utils'
import { createPinia } from 'pinia'
import { defineComponent } from 'vue'
import { GlobalMountOptions } from 'node_modules/@vue/test-utils/dist/types'
import { UseMutationOptions, useMutation } from './use-mutation'
import { delay, runTimers } from '../test/utils'

describe('useMutation', () => {
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.restoreAllMocks()
})

function mountSimple<TResult = number, TParams extends any[] = []>(
options: Partial<UseMutationOptions<TResult, TParams>> = {},
mountOptions?: GlobalMountOptions
) {
const mutator = options.mutator
? vi.fn(options.mutator)
: vi.fn(async () => {
await delay(0)
return 42
})
const wrapper = mount(
defineComponent({
render: () => null,
setup() {
return {
...useMutation<TResult>({
...options,
// @ts-expect-error: generic unmatched but types work
mutator,
}),
}
},
}),
{
global: {
plugins: [createPinia()],
...mountOptions,
},
}
)
return Object.assign([wrapper, mutator] as const, { wrapper, mutator })
}
it('invokes the mutator', async () => {
const { wrapper } = mountSimple()

wrapper.vm.mutate()
await runTimers()

expect(wrapper.vm.data).toBe(42)
})
})
3 changes: 1 addition & 2 deletions src/use-mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@ export interface UseMutationReturn<

export function useMutation<
TResult,
TParams extends readonly unknown[],
TParams extends readonly unknown[] = readonly [],
TError = Error,
>(
options: UseMutationOptions<TResult, TParams>
): UseMutationReturn<TResult, TParams, TError> {
console.log(options)
const store = useDataFetchingStore()

const isPending = ref(false)
Expand Down
15 changes: 2 additions & 13 deletions src/use-query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { UseQueryOptions, useQuery } from './use-query'
import { mount } from '@vue/test-utils'
import { createPinia } from 'pinia'
import { defineComponent, nextTick } from 'vue'
import { defineComponent } from 'vue'
import { GlobalMountOptions } from 'node_modules/@vue/test-utils/dist/types'

const delay = (ms: number) => new Promise((r) => setTimeout(r, ms))
import { delay, runTimers } from '../test/utils'

describe('useQuery', () => {
beforeEach(() => {
Expand All @@ -15,16 +14,6 @@ describe('useQuery', () => {
vi.restoreAllMocks()
})

const runTimers = async (onlyPending = true) => {
if (onlyPending) {
await vi.runOnlyPendingTimersAsync()
} else {
// vi.runAllTimers()
await vi.runAllTimersAsync()
}
await nextTick()
}

const mountSimple = <TResult = number>(
options: Partial<UseQueryOptions<TResult>> = {},
mountOptions?: GlobalMountOptions
Expand Down
14 changes: 14 additions & 0 deletions test/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { vi } from 'vitest'
import { nextTick } from 'vue'

export const delay = (ms: number) => new Promise((r) => setTimeout(r, ms))

export const runTimers = async (onlyPending = true) => {
if (onlyPending) {
await vi.runOnlyPendingTimersAsync()
} else {
// vi.runAllTimers()
await vi.runAllTimersAsync()
}
await nextTick()
}

0 comments on commit cee4a36

Please sign in to comment.