fix: pass tests

This commit is contained in:
Alexander 2024-02-18 17:53:31 +01:00
parent 561f34927e
commit 3366268fb7
3 changed files with 44 additions and 30 deletions

View File

@ -138,7 +138,7 @@ export function useAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
> ( >(
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT> options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null> ): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
@ -154,7 +154,7 @@ export function useAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = DataT, DefaultT = DataT,
> ( >(
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT> options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null> ): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null>
@ -171,7 +171,7 @@ export function useAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
> ( >(
key: string, key: string,
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT> options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
@ -189,7 +189,7 @@ export function useAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = DataT, DefaultT = DataT,
> ( >(
key: string, key: string,
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT> options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
@ -200,7 +200,7 @@ export function useAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null> { >(...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) } if (typeof args[0] !== 'string') { args.unshift(autoKey) }
@ -274,9 +274,17 @@ export function useAsyncData<
(nuxtApp._asyncDataPromises[key] as any).cancelled = true (nuxtApp._asyncDataPromises[key] as any).cancelled = true
} }
// Avoid fetching same key that is already fetched // Avoid fetching same key that is already fetched
if (!opts.force && hasCachedData(opts._triggeredBy)) { if(opts._triggeredBy === 'initial' && !opts.force && nuxtApp.isHydrating && hasCachedData(opts._triggeredBy)) {
return Promise.resolve(options.getCachedData!(key, opts._triggeredBy)) return Promise.resolve(options.getCachedData!(key, opts._triggeredBy))
} }
// If cache changed based on the triggeredBy, set new data result
if (!opts.force && hasCachedData(opts._triggeredBy)) {
const result = options.getCachedData!(key, opts._triggeredBy)
asyncData.data.value = result
return Promise.resolve(result)
}
asyncData.pending.value = true asyncData.pending.value = true
asyncData.status.value = 'pending' asyncData.status.value = 'pending'
// TODO: Cancel previous promise // TODO: Cancel previous promise
@ -325,7 +333,7 @@ export function useAsyncData<
return nuxtApp._asyncDataPromises[key]! return nuxtApp._asyncDataPromises[key]!
} }
const initialFetch = () => asyncData.refresh({ _triggeredBy: 'refresh:manual' }) const initialFetch = () => asyncData.refresh({ _triggeredBy: 'initial' })
const fetchOnServer = options.server !== false && nuxtApp.payload.serverRendered const fetchOnServer = options.server !== false && nuxtApp.payload.serverRendered
@ -372,7 +380,7 @@ export function useAsyncData<
initialFetch() initialFetch()
} }
if (options.watch) { if (options.watch) {
watch(options.watch, () => asyncData.refresh({ _triggeredBy: 'watch'})) watch(options.watch, () => asyncData.refresh({ _triggeredBy: 'watch' }))
} }
const off = nuxtApp.hook('app:data:refresh', async (keys, force) => { const off = nuxtApp.hook('app:data:refresh', async (keys, force) => {
if (!keys || keys.includes(key)) { if (!keys || keys.includes(key)) {
@ -397,7 +405,7 @@ export function useLazyAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
> ( >(
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'> options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> ): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null>
@ -407,7 +415,7 @@ export function useLazyAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = DataT, DefaultT = DataT,
> ( >(
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'> options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> ): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null>
@ -417,7 +425,7 @@ export function useLazyAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
> ( >(
key: string, key: string,
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'> options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
@ -428,7 +436,7 @@ export function useLazyAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = DataT, DefaultT = DataT,
> ( >(
key: string, key: string,
handler: (ctx?: NuxtApp) => Promise<ResT>, handler: (ctx?: NuxtApp) => Promise<ResT>,
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'> options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
@ -440,7 +448,7 @@ export function useLazyAsyncData<
DataT = ResT, DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> { >(...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> {
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
if (typeof args[0] !== 'string') { args.unshift(autoKey) } if (typeof args[0] !== 'string') { args.unshift(autoKey) }
const [key, handler, options = {}] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>] const [key, handler, options = {}] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>]
@ -455,7 +463,7 @@ export function useLazyAsyncData<
} }
/** @since 3.1.0 */ /** @since 3.1.0 */
export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | null> } { export function useNuxtData<DataT = any>(key: string): { data: Ref<DataT | null> } {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
// Initialize value when key is not already set // Initialize value when key is not already set
@ -469,7 +477,7 @@ export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | null
} }
/** @since 3.0.0 */ /** @since 3.0.0 */
export async function refreshNuxtData (keys?: string | string[], force?: boolean): Promise<void> { export async function refreshNuxtData(keys?: string | string[], force?: boolean): Promise<void> {
if (import.meta.server) { if (import.meta.server) {
return Promise.resolve() return Promise.resolve()
} }
@ -481,7 +489,7 @@ export async function refreshNuxtData (keys?: string | string[], force?: boolean
} }
/** @since 3.0.0 */ /** @since 3.0.0 */
export function clearNuxtData (keys?: string | string[] | ((key: string) => boolean)): void { export function clearNuxtData(keys?: string | string[] | ((key: string) => boolean)): void {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
const _allKeys = Object.keys(nuxtApp.payload.data) const _allKeys = Object.keys(nuxtApp.payload.data)
const _keys: string[] = !keys const _keys: string[] = !keys
@ -509,7 +517,7 @@ export function clearNuxtData (keys?: string | string[] | ((key: string) => bool
} }
} }
function pick (obj: Record<string, any>, keys: string[]) { function pick(obj: Record<string, any>, keys: string[]) {
const newObj = {} const newObj = {}
for (const key of keys) { for (const key of keys) {
(newObj as any)[key] = obj[key] (newObj as any)[key] = obj[key]

View File

@ -1,13 +1,20 @@
<script setup lang="ts"> <script setup lang="ts">
const { data, refresh } = await useAsyncData('key', () => Promise.resolve('something'), {
getCachedData: (_, triggeredBy) => {
if(triggeredBy === 'refresh:manual') {
return 1
}
return 0
}
})
</script> </script>
<template> <template>
<!-- Edit this file to play around with Nuxt but never commit changes! --> <!-- Edit this file to play around with Nuxt but never commit changes! -->
<div> <div>
Nuxt 3 Playground {{ data }}
<button @click="refresh()" />
</div> </div>
</template> </template>
<style scoped> <style scoped></style>
</style>

View File

@ -239,19 +239,16 @@ describe('useAsyncData', () => {
}) })
it('will use cache on refresh by default', async () => { it('will use cache on refresh by default', async () => {
let called = 0 const { data, refresh } = await useAsyncData(() => 'other value', { getCachedData: () => 'cached' })
const fn = () => called++ expect(data.value).toBe('cached')
const { data, refresh } = await useAsyncData(() => 'other value', { getCachedData: () => fn() })
expect(data.value).toBe(0)
await refresh() await refresh()
expect(data.value).toBe(0) expect(data.value).toBe('cached')
}) })
it('will not use cache with force option', async () => { it('will not use cache with force option', async () => {
let called = 0 let called = 0
const fn = () => called++ const fn = () => called++
const { data, refresh } = await useAsyncData(() => 'other value', { getCachedData: () => fn() }) const { data, refresh } = await useAsyncData(() => 'other value', { getCachedData: () => fn() })
expect(data.value).toBe(0)
await refresh({ force: true }) await refresh({ force: true })
expect(data.value).toBe('other value') expect(data.value).toBe('other value')
}) })
@ -262,16 +259,18 @@ describe('useAsyncData', () => {
}) })
it('getCachedData should receive triggeredBy on manual refresh', async () => { it('getCachedData should receive triggeredBy on manual refresh', async () => {
const { data, refresh } = await useAsyncData(() => '', { getCachedData: (_, triggeredBy) => triggeredBy }) const { data, refresh } = await useAsyncData(() => '', {
getCachedData: (_, triggeredBy) => triggeredBy
})
await refresh() await refresh()
expect(data.value).toBe('refresh:manual') expect(data.value).toBe('refresh:manual')
}) })
it('getCachedData should receive triggeredBy on watch', async () => { it('getCachedData should receive triggeredBy on watch', async () => {
const number = ref(0) const number = ref(0)
const { data } = await useAsyncData(() => '', { getCachedData: (_, triggeredBy) => triggeredBy }) const { data } = await useAsyncData(() => '', { getCachedData: (_, triggeredBy) => triggeredBy, watch: [number] })
number.value = 1 number.value = 1
// TODO: Maybe setTimeout or similar await new Promise(resolve => setTimeout(resolve, 1))
expect(data.value).toBe('watch') expect(data.value).toBe('watch')
}) })