mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
fix(nuxt): use undefined
rather than null
for data fetching defaults (#27294)
This commit is contained in:
parent
a531e6f466
commit
8a759bc6fe
@ -189,6 +189,37 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
#### Default `data` and `error` values in `useAsyncData` and `useFetch`
|
||||
|
||||
🚦 **Impact Level**: Minimal
|
||||
|
||||
##### What Changed
|
||||
|
||||
`data` and `error` objects returned from `useAsyncData` will now default to `undefined`.
|
||||
|
||||
##### Reasons for Change
|
||||
|
||||
Previously `data` was initialized to `null` but reset in `clearNuxtData` to `undefined`. `error` was initialized to `null`. This change is to bring greater consistency.
|
||||
|
||||
##### Migration Steps
|
||||
|
||||
If you encounter any issues you can revert back to the previous behavior with:
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
experimental: {
|
||||
defaults: {
|
||||
useAsyncData: {
|
||||
value: 'null',
|
||||
errorValue: 'null'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Please report an issue if you are doing this, as we do not plan to keep this as configurable.
|
||||
|
||||
#### Shallow Data Reactivity in `useAsyncData` and `useFetch`
|
||||
|
||||
🚦 **Impact Level**: Minimal
|
||||
|
6
packages/nuxt/index.d.ts
vendored
6
packages/nuxt/index.d.ts
vendored
@ -19,4 +19,10 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
declare module '#app/defaults' {
|
||||
type DefaultAsyncDataErrorValue = undefined
|
||||
type DefaultAsyncDataValue = undefined
|
||||
type DefaultErrorValue = undefined
|
||||
}
|
||||
|
||||
export {}
|
||||
|
@ -10,6 +10,9 @@ import { onNuxtReady } from './ready'
|
||||
// @ts-expect-error virtual file
|
||||
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
||||
|
||||
export type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
||||
|
||||
export type _Transform<Input = any, Output = any> = (input: Input) => Output | Promise<Output>
|
||||
@ -42,7 +45,7 @@ export interface AsyncDataOptions<
|
||||
ResT,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> {
|
||||
/**
|
||||
* Whether to fetch on the server side.
|
||||
@ -117,7 +120,7 @@ export interface _AsyncData<DataT, ErrorT> {
|
||||
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||
clear: () => void
|
||||
error: Ref<ErrorT | null>
|
||||
error: Ref<ErrorT | DefaultAsyncDataErrorValue>
|
||||
status: Ref<AsyncDataRequestStatus>
|
||||
}
|
||||
|
||||
@ -138,11 +141,11 @@ export function useAsyncData<
|
||||
NuxtErrorDataT = unknown,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
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>) | DefaultAsyncDataErrorValue>
|
||||
/**
|
||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||
@ -158,7 +161,7 @@ export function useAsyncData<
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
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>) | DefaultAsyncDataErrorValue>
|
||||
/**
|
||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||
@ -171,12 +174,12 @@ export function useAsyncData<
|
||||
NuxtErrorDataT = unknown,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
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>) | DefaultAsyncDataErrorValue>
|
||||
/**
|
||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||
@ -194,14 +197,14 @@ export function useAsyncData<
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
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>) | DefaultAsyncDataErrorValue>
|
||||
export function useAsyncData<
|
||||
ResT,
|
||||
NuxtErrorDataT = unknown,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | null> {
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue> {
|
||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||
|
||||
@ -233,7 +236,7 @@ export function useAsyncData<
|
||||
}
|
||||
|
||||
// Used to get default values
|
||||
const getDefault = () => null
|
||||
const getDefault = () => asyncDataDefaults.value
|
||||
const getDefaultCachedData = () => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key]
|
||||
|
||||
// Apply defaults
|
||||
@ -250,11 +253,12 @@ export function useAsyncData<
|
||||
console.warn('[nuxt] `boolean` values are deprecated for the `dedupe` option of `useAsyncData` and will be removed in the future. Use \'cancel\' or \'defer\' instead.')
|
||||
}
|
||||
|
||||
// TODO: make more precise when v4 lands
|
||||
const hasCachedData = () => options.getCachedData!(key, nuxtApp) != null
|
||||
|
||||
// Create or use a shared asyncData entity
|
||||
if (!nuxtApp._asyncData[key] || !options.immediate) {
|
||||
nuxtApp.payload._errors[key] ??= null
|
||||
nuxtApp.payload._errors[key] ??= asyncDataDefaults.errorValue
|
||||
|
||||
const _ref = options.deep ? ref : shallowRef
|
||||
|
||||
@ -307,7 +311,7 @@ export function useAsyncData<
|
||||
nuxtApp.payload.data[key] = result
|
||||
|
||||
asyncData.data.value = result
|
||||
asyncData.error.value = null
|
||||
asyncData.error.value = asyncDataDefaults.errorValue
|
||||
asyncData.status.value = 'success'
|
||||
})
|
||||
.catch((error: any) => {
|
||||
@ -404,11 +408,11 @@ export function useLazyAsyncData<
|
||||
DataE = Error,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
@ -418,18 +422,18 @@ export function useLazyAsyncData<
|
||||
> (
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
@ -440,15 +444,15 @@ export function useLazyAsyncData<
|
||||
key: string,
|
||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
||||
|
||||
export function useLazyAsyncData<
|
||||
ResT,
|
||||
DataE = Error,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | null> {
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue> {
|
||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||
const [key, handler, options = {}] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>]
|
||||
@ -463,12 +467,12 @@ export function useLazyAsyncData<
|
||||
}
|
||||
|
||||
/** @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 | DefaultAsyncDataValue> } {
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
// Initialize value when key is not already set
|
||||
if (!(key in nuxtApp.payload.data)) {
|
||||
nuxtApp.payload.data[key] = null
|
||||
nuxtApp.payload.data[key] = asyncDataDefaults.value
|
||||
}
|
||||
|
||||
return {
|
||||
@ -520,12 +524,12 @@ function clearNuxtDataByKey (nuxtApp: NuxtApp, key: string): void {
|
||||
}
|
||||
|
||||
if (key in nuxtApp.payload._errors) {
|
||||
nuxtApp.payload._errors[key] = null
|
||||
nuxtApp.payload._errors[key] = asyncDataDefaults.errorValue
|
||||
}
|
||||
|
||||
if (nuxtApp._asyncData[key]) {
|
||||
nuxtApp._asyncData[key]!.data.value = undefined
|
||||
nuxtApp._asyncData[key]!.error.value = null
|
||||
nuxtApp._asyncData[key]!.error.value = asyncDataDefaults.errorValue
|
||||
nuxtApp._asyncData[key]!.pending.value = false
|
||||
nuxtApp._asyncData[key]!.status.value = 'idle'
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ import { toRef } from 'vue'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
import { useRouter } from './router'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
import { nuxtDefaultErrorValue } from '#build/nuxt.config.mjs'
|
||||
|
||||
export const NUXT_ERROR_SIGNATURE = '__nuxt_error'
|
||||
|
||||
/** @since 3.0.0 */
|
||||
@ -47,7 +50,7 @@ export const clearError = async (options: { redirect?: string } = {}) => {
|
||||
await useRouter().replace(options.redirect)
|
||||
}
|
||||
|
||||
error.value = null
|
||||
error.value = nuxtDefaultErrorValue
|
||||
}
|
||||
|
||||
/** @since 3.0.0 */
|
||||
|
@ -8,6 +8,9 @@ import { useRequestFetch } from './ssr'
|
||||
import type { AsyncData, AsyncDataOptions, KeysOf, MultiWatchSources, PickFrom } from './asyncData'
|
||||
import { useAsyncData } from './asyncData'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
import { fetchDefaults } from '#build/nuxt.config.mjs'
|
||||
|
||||
@ -30,7 +33,7 @@ export interface UseFetchOptions<
|
||||
ResT,
|
||||
DataT = ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
R extends NitroFetchRequest = string & {},
|
||||
M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>,
|
||||
> extends Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'watch'>, ComputedFetchOptions<R, M> {
|
||||
@ -54,11 +57,11 @@ export function useFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
/**
|
||||
* Fetch data from an API endpoint with an SSR-friendly composable.
|
||||
* See {@link https://nuxt.com/docs/api/composables/use-fetch}
|
||||
@ -77,7 +80,7 @@ export function useFetch<
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
export function useFetch<
|
||||
ResT = void,
|
||||
ErrorT = FetchError,
|
||||
@ -86,7 +89,7 @@ export function useFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
arg1?: string | UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
|
||||
@ -190,11 +193,11 @@ export function useLazyFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
export function useLazyFetch<
|
||||
ResT = void,
|
||||
ErrorT = FetchError,
|
||||
@ -207,7 +210,7 @@ export function useLazyFetch<
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | null>
|
||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
||||
export function useLazyFetch<
|
||||
ResT = void,
|
||||
ErrorT = FetchError,
|
||||
@ -216,7 +219,7 @@ export function useLazyFetch<
|
||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||
DataT = _ResT,
|
||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||
DefaultT = null,
|
||||
DefaultT = DefaultAsyncDataValue,
|
||||
> (
|
||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
|
||||
|
2
packages/nuxt/src/app/defaults.js
Normal file
2
packages/nuxt/src/app/defaults.js
Normal file
@ -0,0 +1,2 @@
|
||||
// TODO: temporary module for backwards compatibility
|
||||
export {}
|
@ -23,6 +23,8 @@ import type { ViewTransition } from './plugins/view-transitions.client'
|
||||
// @ts-expect-error virtual file
|
||||
import { appId } from '#build/nuxt.config.mjs'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DefaultAsyncDataErrorValue, DefaultErrorValue } from '#app/defaults'
|
||||
import type { NuxtAppLiterals } from '#app'
|
||||
|
||||
function getNuxtAppCtx (appName = appId || 'nuxt-app') {
|
||||
@ -92,8 +94,8 @@ export interface NuxtPayload {
|
||||
state: Record<string, any>
|
||||
once: Set<string>
|
||||
config?: Pick<RuntimeConfig, 'public' | 'app'>
|
||||
error?: NuxtError | null
|
||||
_errors: Record<string, NuxtError | null>
|
||||
error?: NuxtError | DefaultErrorValue
|
||||
_errors: Record<string, NuxtError | DefaultAsyncDataErrorValue>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
@ -122,7 +124,7 @@ interface _NuxtApp {
|
||||
_asyncData: Record<string, {
|
||||
data: Ref<any>
|
||||
pending: Ref<boolean>
|
||||
error: Ref<Error | null>
|
||||
error: Ref<Error | DefaultAsyncDataErrorValue>
|
||||
status: Ref<AsyncDataRequestStatus>
|
||||
} | undefined>
|
||||
|
||||
|
@ -130,6 +130,12 @@ declare module '#app' {
|
||||
}
|
||||
}
|
||||
|
||||
declare module '#app/defaults' {
|
||||
type DefaultAsyncDataErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'}
|
||||
type DefaultAsyncDataValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'}
|
||||
type DefaultErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'}
|
||||
}
|
||||
|
||||
declare module 'vue' {
|
||||
interface ComponentCustomProperties extends NuxtAppInjections { }
|
||||
}
|
||||
@ -393,7 +399,12 @@ export const nuxtConfigTemplate: NuxtTemplate = {
|
||||
`export const devRootDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.rootDir) : 'null'}`,
|
||||
`export const devLogs = ${JSON.stringify(ctx.nuxt.options.features.devLogs)}`,
|
||||
`export const nuxtLinkDefaults = ${JSON.stringify(ctx.nuxt.options.experimental.defaults.nuxtLink)}`,
|
||||
`export const asyncDataDefaults = ${JSON.stringify(ctx.nuxt.options.experimental.defaults.useAsyncData)}`,
|
||||
`export const asyncDataDefaults = ${JSON.stringify({
|
||||
...ctx.nuxt.options.experimental.defaults.useAsyncData,
|
||||
value: ctx.nuxt.options.experimental.defaults.useAsyncData.value === 'null' ? null : undefined,
|
||||
errorValue: ctx.nuxt.options.experimental.defaults.useAsyncData.errorValue === 'null' ? null : undefined,
|
||||
})}`,
|
||||
`export const nuxtDefaultErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'}`,
|
||||
`export const fetchDefaults = ${JSON.stringify(fetchDefaults)}`,
|
||||
`export const vueAppRootContainer = ${ctx.nuxt.options.app.rootId ? `'#${ctx.nuxt.options.app.rootId}'` : `'body > ${ctx.nuxt.options.app.rootTag}'`}`,
|
||||
`export const viewTransition = ${ctx.nuxt.options.experimental.viewTransition}`,
|
||||
|
@ -415,6 +415,18 @@ export default defineUntypedSchema({
|
||||
* Options that apply to `useAsyncData` (and also therefore `useFetch`)
|
||||
*/
|
||||
useAsyncData: {
|
||||
/** @type {'undefined' | 'null'} */
|
||||
value: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion === 4 ? 'undefined' : 'null')
|
||||
},
|
||||
},
|
||||
/** @type {'undefined' | 'null'} */
|
||||
errorValue: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion === 4 ? 'undefined' : 'null')
|
||||
},
|
||||
},
|
||||
deep: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? !((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||
|
@ -2433,21 +2433,23 @@ describe.skipIf(isWindows)('useAsyncData', () => {
|
||||
})
|
||||
|
||||
it('data is null after navigation when immediate false', async () => {
|
||||
const defaultValue = isV4 ? 'undefined' : 'null'
|
||||
|
||||
const { page } = await renderPage('/useAsyncData/immediate-remove-unmounted')
|
||||
expect(await page.locator('#immediate-data').getByText('null').textContent()).toBe('null')
|
||||
expect(await page.locator('#immediate-data').getByText(defaultValue).textContent()).toBe(defaultValue)
|
||||
|
||||
await page.click('#execute-btn')
|
||||
expect(await page.locator('#immediate-data').getByText(',').textContent()).not.toContain('null')
|
||||
expect(await page.locator('#immediate-data').getByText(',').textContent()).not.toContain(defaultValue)
|
||||
|
||||
await page.click('#to-index')
|
||||
await page.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/')
|
||||
|
||||
await page.click('#to-immediate-remove-unmounted')
|
||||
await page.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/useAsyncData/immediate-remove-unmounted')
|
||||
expect(await page.locator('#immediate-data').getByText('null').textContent()).toBe('null')
|
||||
expect(await page.locator('#immediate-data').getByText(defaultValue).textContent()).toBe(defaultValue)
|
||||
|
||||
await page.click('#execute-btn')
|
||||
expect(await page.locator('#immediate-data').getByText(',').textContent()).not.toContain('null')
|
||||
expect(await page.locator('#immediate-data').getByText(',').textContent()).not.toContain(defaultValue)
|
||||
|
||||
await page.close()
|
||||
})
|
||||
|
97
test/fixtures/basic-types/types.ts
vendored
97
test/fixtures/basic-types/types.ts
vendored
@ -11,6 +11,9 @@ import type { NavigateToOptions } from '#app/composables/router'
|
||||
import { NuxtLayout, NuxtLink, NuxtPage, ServerComponent, WithTypes } from '#components'
|
||||
import { useRouter } from '#imports'
|
||||
|
||||
// TODO: temporary module for backwards compatibility
|
||||
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
||||
|
||||
interface TestResponse { message: string }
|
||||
|
||||
describe('API routes', () => {
|
||||
@ -31,61 +34,61 @@ describe('API routes', () => {
|
||||
})
|
||||
|
||||
it('works with useAsyncData', () => {
|
||||
expectTypeOf(useAsyncData('api-hello', () => $fetch('/api/hello')).data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useAsyncData('api-hey', () => $fetch('/api/hey')).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | null>>()
|
||||
expectTypeOf(useAsyncData('api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | null>>()
|
||||
expectTypeOf(useAsyncData('api-union', () => $fetch('/api/union')).data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | null>>()
|
||||
expectTypeOf(useAsyncData('api-union-with-pick', () => $fetch('/api/union'), { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | null>>()
|
||||
expectTypeOf(useAsyncData('api-hello', () => $fetch('/api/hello')).data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useAsyncData('api-hey', () => $fetch('/api/hey')).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useAsyncData('api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useAsyncData('api-union', () => $fetch('/api/union')).data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useAsyncData('api-union-with-pick', () => $fetch('/api/union'), { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useAsyncData('api-other', () => $fetch('/api/other')).data).toEqualTypeOf<Ref<unknown>>()
|
||||
expectTypeOf(useAsyncData<TestResponse>('api-generics', () => $fetch('/test')).data).toEqualTypeOf<Ref<TestResponse | null>>()
|
||||
expectTypeOf(useAsyncData<TestResponse>('api-generics', () => $fetch('/test')).data).toEqualTypeOf<Ref<TestResponse | DefaultAsyncDataValue>>()
|
||||
|
||||
expectTypeOf(useAsyncData('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<NuxtError<unknown> | null>>()
|
||||
expectTypeOf(useAsyncData<any, string>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<NuxtError<string> | null>>()
|
||||
expectTypeOf(useAsyncData('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<NuxtError<unknown> | DefaultAsyncDataErrorValue>>()
|
||||
expectTypeOf(useAsyncData<any, string>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<NuxtError<string> | DefaultAsyncDataErrorValue>>()
|
||||
// backwards compatibility
|
||||
expectTypeOf(useAsyncData<any, Error>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | null>>()
|
||||
expectTypeOf(useAsyncData<any, NuxtError<string>>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<NuxtError<string> | null>>()
|
||||
expectTypeOf(useAsyncData<any, Error>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | DefaultAsyncDataErrorValue>>()
|
||||
expectTypeOf(useAsyncData<any, NuxtError<string>>('api-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<NuxtError<string> | DefaultAsyncDataErrorValue>>()
|
||||
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-hello', () => $fetch('/api/hello')).data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-hey', () => $fetch('/api/hey')).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | null>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | null>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-union', () => $fetch('/api/union')).data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | null>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-union-with-pick', () => $fetch('/api/union'), { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | null>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-hello', () => $fetch('/api/hello')).data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-hey', () => $fetch('/api/hey')).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-union', () => $fetch('/api/union')).data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-union-with-pick', () => $fetch('/api/union'), { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-api-other', () => $fetch('/api/other')).data).toEqualTypeOf<Ref<unknown>>()
|
||||
expectTypeOf(useLazyAsyncData<TestResponse>('lazy-api-generics', () => $fetch('/test')).data).toEqualTypeOf<Ref<TestResponse | null>>()
|
||||
expectTypeOf(useLazyAsyncData<TestResponse>('lazy-api-generics', () => $fetch('/test')).data).toEqualTypeOf<Ref<TestResponse | DefaultAsyncDataValue>>()
|
||||
|
||||
expectTypeOf(useLazyAsyncData('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | null>>()
|
||||
expectTypeOf(useLazyAsyncData<any, string>('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyAsyncData('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<Error | DefaultAsyncDataErrorValue>>()
|
||||
expectTypeOf(useLazyAsyncData<any, string>('lazy-error-generics', () => $fetch('/error')).error).toEqualTypeOf<Ref<string | DefaultAsyncDataErrorValue>>()
|
||||
})
|
||||
|
||||
it('works with useFetch', () => {
|
||||
expectTypeOf(useFetch('/api/hello').data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useFetch('/api/hey').data).toEqualTypeOf<Ref<{ foo: string, baz: string } | null>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'GET' }).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | null>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'get' }).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | null>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'POST' }).data).toEqualTypeOf<Ref<{ method: 'post' } | null>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'post' }).data).toEqualTypeOf<Ref<{ method: 'post' } | null>>()
|
||||
expectTypeOf(useFetch('/api/hello').data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/hey').data).toEqualTypeOf<Ref<{ foo: string, baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'GET' }).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'get' }).data).toEqualTypeOf<Ref<{ foo: string, baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'POST' }).data).toEqualTypeOf<Ref<{ method: 'post' } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/hey', { method: 'post' }).data).toEqualTypeOf<Ref<{ method: 'post' } | DefaultAsyncDataValue>>()
|
||||
// @ts-expect-error not a valid method
|
||||
useFetch('/api/hey', { method: 'PATCH' })
|
||||
expectTypeOf(useFetch('/api/hey', { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | null>>()
|
||||
expectTypeOf(useFetch('/api/union').data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | null>>()
|
||||
expectTypeOf(useFetch('/api/union', { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | null>>()
|
||||
expectTypeOf(useFetch('/api/hey', { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/union').data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/union', { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch('/api/other').data).toEqualTypeOf<Ref<unknown>>()
|
||||
expectTypeOf(useFetch<TestResponse>('/test').data).toEqualTypeOf<Ref<TestResponse | null>>()
|
||||
expectTypeOf(useFetch<TestResponse>('/test', { method: 'POST' }).data).toEqualTypeOf<Ref<TestResponse | null>>()
|
||||
expectTypeOf(useFetch<TestResponse>('/test').data).toEqualTypeOf<Ref<TestResponse | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useFetch<TestResponse>('/test', { method: 'POST' }).data).toEqualTypeOf<Ref<TestResponse | DefaultAsyncDataValue>>()
|
||||
|
||||
expectTypeOf(useFetch('/error').error).toEqualTypeOf<Ref<FetchError | null>>()
|
||||
expectTypeOf(useFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useFetch('/error').error).toEqualTypeOf<Ref<FetchError | DefaultAsyncDataErrorValue>>()
|
||||
expectTypeOf(useFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | DefaultAsyncDataErrorValue>>()
|
||||
|
||||
expectTypeOf(useLazyFetch('/api/hello').data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyFetch('/api/hey').data).toEqualTypeOf<Ref<{ foo: string, baz: string } | null>>()
|
||||
expectTypeOf(useLazyFetch('/api/hey', { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | null>>()
|
||||
expectTypeOf(useLazyFetch('/api/union').data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | null>>()
|
||||
expectTypeOf(useLazyFetch('/api/union', { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | null>>()
|
||||
expectTypeOf(useLazyFetch('/api/hello').data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch('/api/hey').data).toEqualTypeOf<Ref<{ foo: string, baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch('/api/hey', { pick: ['baz'] }).data).toEqualTypeOf<Ref<{ baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch('/api/union').data).toEqualTypeOf<Ref<{ type: 'a', foo: string } | { type: 'b', baz: string } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch('/api/union', { pick: ['type'] }).data).toEqualTypeOf<Ref<{ type: 'a' } | { type: 'b' } | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch('/api/other').data).toEqualTypeOf<Ref<unknown>>()
|
||||
expectTypeOf(useLazyFetch<TestResponse>('/test').data).toEqualTypeOf<Ref<TestResponse | null>>()
|
||||
expectTypeOf(useLazyFetch<TestResponse>('/test').data).toEqualTypeOf<Ref<TestResponse | DefaultAsyncDataValue>>()
|
||||
|
||||
expectTypeOf(useLazyFetch('/error').error).toEqualTypeOf<Ref<FetchError | null>>()
|
||||
expectTypeOf(useLazyFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyFetch('/error').error).toEqualTypeOf<Ref<FetchError | DefaultAsyncDataErrorValue>>()
|
||||
expectTypeOf(useLazyFetch<any, string>('/error').error).toEqualTypeOf<Ref<string | DefaultAsyncDataErrorValue>>()
|
||||
})
|
||||
})
|
||||
|
||||
@ -421,10 +424,10 @@ describe('composables', () => {
|
||||
expectTypeOf(useLazyAsyncData<string>(() => $fetch('/test'), { default: () => 'test' }).data).toEqualTypeOf<Ref<string>>()
|
||||
|
||||
// transform must match the explicit generic because of typescript limitations microsoft/TypeScript#14400
|
||||
expectTypeOf(useFetch<string>('/test', { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyFetch<string>('/test', { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useAsyncData<string>(() => $fetch('/test'), { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyAsyncData<string>(() => $fetch('/test'), { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useFetch<string>('/test', { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch<string>('/test', { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useAsyncData<string>(() => $fetch('/test'), { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyAsyncData<string>(() => $fetch('/test'), { transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
|
||||
expectTypeOf(useFetch<string>('/test', { default: () => 'test', transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string>>()
|
||||
expectTypeOf(useLazyFetch<string>('/test', { default: () => 'test', transform: () => 'transformed' }).data).toEqualTypeOf<Ref<string>>()
|
||||
@ -439,7 +442,7 @@ describe('composables', () => {
|
||||
return data.foo
|
||||
},
|
||||
})
|
||||
expectTypeOf(data).toEqualTypeOf<Ref<'bar' | null>>()
|
||||
expectTypeOf(data).toEqualTypeOf<Ref<'bar' | DefaultAsyncDataValue>>()
|
||||
})
|
||||
|
||||
it('infer request url string literal from server/api routes', () => {
|
||||
@ -448,8 +451,8 @@ describe('composables', () => {
|
||||
expectTypeOf(useFetch(dynamicStringUrl).data).toEqualTypeOf<Ref<unknown>>()
|
||||
|
||||
// request param should infer string literal type / show auto-complete hint base on server routes, ex: '/api/hello'
|
||||
expectTypeOf(useFetch('/api/hello').data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useLazyFetch('/api/hello').data).toEqualTypeOf<Ref<string | null>>()
|
||||
expectTypeOf(useFetch('/api/hello').data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
expectTypeOf(useLazyFetch('/api/hello').data).toEqualTypeOf<Ref<string | DefaultAsyncDataValue>>()
|
||||
|
||||
// request can accept string literal and Request object type
|
||||
expectTypeOf(useFetch('https://example.com/api').data).toEqualTypeOf<Ref<unknown>>()
|
||||
@ -519,7 +522,7 @@ describe('composables', () => {
|
||||
it('correctly types returns when using with getCachedData', () => {
|
||||
expectTypeOf(useAsyncData('test', () => Promise.resolve({ foo: 1 }), {
|
||||
getCachedData: key => useNuxtApp().payload.data[key],
|
||||
}).data).toEqualTypeOf<Ref<{ foo: number } | null>>()
|
||||
}).data).toEqualTypeOf<Ref<{ foo: number } | DefaultAsyncDataValue>>()
|
||||
useAsyncData('test', () => Promise.resolve({ foo: 1 }), {
|
||||
// @ts-expect-error cached data should return the same as value of fetcher
|
||||
getCachedData: () => ({ bar: 2 }),
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div>
|
||||
<div>immediate-remove-unmounted.vue</div>
|
||||
<div id="immediate-data">
|
||||
{{ data === null ? "null" : data }}
|
||||
{{ data === null ? "null" : (data === undefined ? 'undefined' : data) }}
|
||||
</div>
|
||||
<button
|
||||
id="execute-btn"
|
||||
@ -20,9 +20,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
|
||||
|
||||
const { data, execute } = await useAsyncData('immediateFalse', () => $fetch('/api/random'), { immediate: false })
|
||||
|
||||
if (data.value !== null) {
|
||||
throw new Error('Initial data should be null: ' + data.value)
|
||||
if (data.value !== asyncDataDefaults.errorValue) {
|
||||
throw new Error(`Initial data should be ${asyncDataDefaults.errorValue}: ` + data.value)
|
||||
}
|
||||
</script>
|
||||
|
@ -20,6 +20,9 @@ import { callOnce } from '#app/composables/once'
|
||||
import { useLoadingIndicator } from '#app/composables/loading-indicator'
|
||||
import { useRouteAnnouncer } from '#app/composables/route-announcer'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
import { asyncDataDefaults, nuxtDefaultErrorValue } from '#build/nuxt.config.mjs'
|
||||
|
||||
registerEndpoint('/api/test', defineEventHandler(event => ({
|
||||
method: event.method,
|
||||
headers: Object.fromEntries(event.headers.entries()),
|
||||
@ -126,7 +129,7 @@ describe('useAsyncData', () => {
|
||||
]
|
||||
`)
|
||||
expect(res instanceof Promise).toBeTruthy()
|
||||
expect(res.data.value).toBe(null)
|
||||
expect(res.data.value).toBe(asyncDataDefaults.value)
|
||||
await res
|
||||
expect(res.data.value).toBe('test')
|
||||
})
|
||||
@ -138,7 +141,7 @@ describe('useAsyncData', () => {
|
||||
expect(immediate.pending.value).toBe(false)
|
||||
|
||||
const nonimmediate = await useAsyncData(() => Promise.resolve('test'), { immediate: false })
|
||||
expect(nonimmediate.data.value).toBe(null)
|
||||
expect(nonimmediate.data.value).toBe(asyncDataDefaults.value)
|
||||
expect(nonimmediate.status.value).toBe('idle')
|
||||
expect(nonimmediate.pending.value).toBe(true)
|
||||
})
|
||||
@ -163,9 +166,9 @@ describe('useAsyncData', () => {
|
||||
// https://github.com/nuxt/nuxt/issues/23411
|
||||
it('should initialize with error set to null when immediate: false', async () => {
|
||||
const { error, execute } = useAsyncData(() => ({}), { immediate: false })
|
||||
expect(error.value).toBe(null)
|
||||
expect(error.value).toBe(asyncDataDefaults.errorValue)
|
||||
await execute()
|
||||
expect(error.value).toBe(null)
|
||||
expect(error.value).toBe(asyncDataDefaults.errorValue)
|
||||
})
|
||||
|
||||
it('should be accessible with useNuxtData', async () => {
|
||||
@ -206,8 +209,9 @@ describe('useAsyncData', () => {
|
||||
|
||||
clear()
|
||||
|
||||
// TODO: update to asyncDataDefaults.value in v4
|
||||
expect(data.value).toBeUndefined()
|
||||
expect(error.value).toBeNull()
|
||||
expect(error.value).toBe(asyncDataDefaults.errorValue)
|
||||
expect(pending.value).toBe(false)
|
||||
expect(status.value).toBe('idle')
|
||||
})
|
||||
@ -345,13 +349,12 @@ describe('errors', () => {
|
||||
})
|
||||
|
||||
it('global nuxt errors', () => {
|
||||
const err = useError()
|
||||
expect(err.value).toBeUndefined()
|
||||
const error = useError()
|
||||
expect(error.value).toBeUndefined()
|
||||
showError('new error')
|
||||
expect(err.value).toMatchInlineSnapshot('[Error: new error]')
|
||||
expect(error.value).toMatchInlineSnapshot('[Error: new error]')
|
||||
clearError()
|
||||
// TODO: should this return to being undefined?
|
||||
expect(err.value).toBeNull()
|
||||
expect(error.value).toBe(nuxtDefaultErrorValue)
|
||||
})
|
||||
})
|
||||
|
||||
@ -616,7 +619,7 @@ describe('routing utilities: `abortNavigation`', () => {
|
||||
it('should throw an error if one is provided', () => {
|
||||
const error = useError()
|
||||
expect(() => abortNavigation({ message: 'Page not found' })).toThrowErrorMatchingInlineSnapshot('[Error: Page not found]')
|
||||
expect(error.value).toBeFalsy()
|
||||
expect(error.value).toBe(nuxtDefaultErrorValue)
|
||||
})
|
||||
it('should block navigation if no error is provided', () => {
|
||||
expect(abortNavigation()).toMatchInlineSnapshot('false')
|
||||
|
Loading…
Reference in New Issue
Block a user