diff --git a/packages/angular-query-experimental/src/__tests__/infinite-query-options.test-d.ts b/packages/angular-query-experimental/src/__tests__/infinite-query-options.test-d.ts index a20596788e..17ce85b9d4 100644 --- a/packages/angular-query-experimental/src/__tests__/infinite-query-options.test-d.ts +++ b/packages/angular-query-experimental/src/__tests__/infinite-query-options.test-d.ts @@ -1,4 +1,5 @@ import { assertType, describe, expectTypeOf, it, test } from 'vitest' +import { queryKey } from '@tanstack/query-test-utils' import { QueryClient, dataTagSymbol } from '@tanstack/query-core' import { infiniteQueryOptions } from '../infinite-query-options' import { injectInfiniteQuery } from '../inject-infinite-query' @@ -11,9 +12,10 @@ import type { describe('infiniteQueryOptions', () => { it('should not allow excess properties', () => { + const key = queryKey() assertType( infiniteQueryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve('data'), getNextPageParam: () => 1, initialPageParam: 1, @@ -23,8 +25,9 @@ describe('infiniteQueryOptions', () => { ) }) it('should infer types for callbacks', () => { + const key = queryKey() infiniteQueryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve('data'), staleTime: 1000, getNextPageParam: () => 1, @@ -35,8 +38,9 @@ describe('infiniteQueryOptions', () => { }) }) it('should work when passed to useInfiniteQuery', () => { + const key = queryKey() const options = infiniteQueryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve('string'), getNextPageParam: () => 1, initialPageParam: 1, @@ -51,8 +55,9 @@ describe('infiniteQueryOptions', () => { }) it('should work when passed to fetchInfiniteQuery', async () => { + const key = queryKey() const options = infiniteQueryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve('string'), getNextPageParam: () => 1, initialPageParam: 1, @@ -63,61 +68,66 @@ describe('infiniteQueryOptions', () => { expectTypeOf(data).toEqualTypeOf>() }) it('should tag the queryKey with the result type of the QueryFn', () => { - const { queryKey } = infiniteQueryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = infiniteQueryOptions({ + queryKey: key, queryFn: () => Promise.resolve('string'), getNextPageParam: () => 1, initialPageParam: 1, }) - expectTypeOf(queryKey[dataTagSymbol]).toEqualTypeOf>() + expectTypeOf(tagged[dataTagSymbol]).toEqualTypeOf>() }) it('should tag the queryKey even if no promise is returned', () => { - const { queryKey } = infiniteQueryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = infiniteQueryOptions({ + queryKey: key, queryFn: () => 'string', getNextPageParam: () => 1, initialPageParam: 1, }) - expectTypeOf(queryKey[dataTagSymbol]).toEqualTypeOf>() + expectTypeOf(tagged[dataTagSymbol]).toEqualTypeOf>() }) it('should tag the queryKey with the result type of the QueryFn if select is used', () => { - const { queryKey } = infiniteQueryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = infiniteQueryOptions({ + queryKey: key, queryFn: () => Promise.resolve('string'), select: (data) => data.pages, getNextPageParam: () => 1, initialPageParam: 1, }) - expectTypeOf(queryKey[dataTagSymbol]).toEqualTypeOf>() + expectTypeOf(tagged[dataTagSymbol]).toEqualTypeOf>() }) it('should return the proper type when passed to getQueryData', () => { - const { queryKey } = infiniteQueryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = infiniteQueryOptions({ + queryKey: key, queryFn: () => Promise.resolve('string'), getNextPageParam: () => 1, initialPageParam: 1, }) const queryClient = new QueryClient() - const data = queryClient.getQueryData(queryKey) + const data = queryClient.getQueryData(tagged) expectTypeOf(data).toEqualTypeOf< InfiniteData | undefined >() }) it('should properly type when passed to setQueryData', () => { - const { queryKey } = infiniteQueryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = infiniteQueryOptions({ + queryKey: key, queryFn: () => Promise.resolve('string'), getNextPageParam: () => 1, initialPageParam: 1, }) const queryClient = new QueryClient() - const data = queryClient.setQueryData(queryKey, (prev) => { + const data = queryClient.setQueryData(tagged, (prev) => { expectTypeOf(prev).toEqualTypeOf< InfiniteData | undefined >() @@ -130,9 +140,10 @@ describe('infiniteQueryOptions', () => { }) test('should not be allowed to be passed to non-infinite query functions', () => { + const key = queryKey() const queryClient = new QueryClient() const options = infiniteQueryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve('string'), getNextPageParam: () => 1, initialPageParam: 1, @@ -156,9 +167,10 @@ describe('infiniteQueryOptions', () => { }) test('allow optional initialData function', () => { + const key = queryKey() const initialData: { example: boolean } | undefined = { example: true } const queryOptions = infiniteQueryOptions({ - queryKey: ['example'], + queryKey: key, queryFn: () => initialData, initialData: initialData ? () => ({ pages: [initialData], pageParams: [] }) @@ -174,9 +186,10 @@ describe('infiniteQueryOptions', () => { }) test('allow optional initialData object', () => { + const key = queryKey() const initialData: { example: boolean } | undefined = { example: true } const queryOptions = infiniteQueryOptions({ - queryKey: ['example'], + queryKey: key, queryFn: () => initialData, initialData: initialData ? { pages: [initialData], pageParams: [] } diff --git a/packages/angular-query-experimental/src/__tests__/infinite-query-options.test.ts b/packages/angular-query-experimental/src/__tests__/infinite-query-options.test.ts index 225a63f3b1..9459d96839 100644 --- a/packages/angular-query-experimental/src/__tests__/infinite-query-options.test.ts +++ b/packages/angular-query-experimental/src/__tests__/infinite-query-options.test.ts @@ -1,12 +1,14 @@ import { describe, expect, it } from 'vitest' +import { queryKey } from '@tanstack/query-test-utils' import { infiniteQueryOptions } from '../infinite-query-options' import type { CreateInfiniteQueryOptions } from '../types' describe('infiniteQueryOptions', () => { it('should return the object received as a parameter without any modification.', () => { + const key = queryKey() const object: CreateInfiniteQueryOptions = { - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve(5), getNextPageParam: () => null, initialPageParam: null, diff --git a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts index 7ec133adfb..e9db0edafb 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test-d.ts @@ -1,7 +1,7 @@ import { TestBed } from '@angular/core/testing' import { afterEach, beforeEach, describe, expectTypeOf, test, vi } from 'vitest' import { provideZonelessChangeDetection } from '@angular/core' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { QueryClient, injectInfiniteQuery, provideTanStackQuery } from '..' import type { InfiniteData } from '@tanstack/query-core' @@ -24,9 +24,10 @@ describe('injectInfiniteQuery', () => { }) test('should narrow type after isSuccess', () => { + const key = queryKey() const query = TestBed.runInInjectionContext(() => { return injectInfiniteQuery(() => ({ - queryKey: ['infiniteQuery'], + queryKey: key, queryFn: ({ pageParam }) => sleep(0).then(() => 'data on page ' + pageParam), initialPageParam: 0, diff --git a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts index 23fcc4ba0f..55890b38d2 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-infinite-query.test.ts @@ -1,7 +1,7 @@ import { TestBed } from '@angular/core/testing' import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { Injector, provideZonelessChangeDetection } from '@angular/core' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { QueryClient, injectInfiniteQuery, provideTanStackQuery } from '..' import { expectSignals } from './test-utils' @@ -24,9 +24,10 @@ describe('injectInfiniteQuery', () => { }) test('should properly execute infinite query', async () => { + const key = queryKey() const query = TestBed.runInInjectionContext(() => { return injectInfiniteQuery(() => ({ - queryKey: ['infiniteQuery'], + queryKey: key, queryFn: ({ pageParam }) => sleep(10).then(() => 'data on page ' + pageParam), initialPageParam: 0, @@ -64,9 +65,10 @@ describe('injectInfiniteQuery', () => { describe('injection context', () => { test('throws NG0203 with descriptive error outside injection context', () => { + const key = queryKey() expect(() => { injectInfiniteQuery(() => ({ - queryKey: ['injectionContextError'], + queryKey: key, queryFn: ({ pageParam }) => sleep(0).then(() => 'data on page ' + pageParam), initialPageParam: 0, @@ -76,9 +78,10 @@ describe('injectInfiniteQuery', () => { }) test('can be used outside injection context when passing an injector', () => { + const key = queryKey() const query = injectInfiniteQuery( () => ({ - queryKey: ['manualInjector'], + queryKey: key, queryFn: ({ pageParam }) => sleep(0).then(() => 'data on page ' + pageParam), initialPageParam: 0, diff --git a/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts b/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts index 9e5126b5a8..983f5d16ca 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-is-fetching.test.ts @@ -1,7 +1,7 @@ import { TestBed } from '@angular/core/testing' import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { Injector, provideZonelessChangeDetection } from '@angular/core' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { QueryClient, injectIsFetching, @@ -29,9 +29,10 @@ describe('injectIsFetching', () => { }) test('Returns number of fetching queries', async () => { + const key = queryKey() const isFetching = TestBed.runInInjectionContext(() => { injectQuery(() => ({ - queryKey: ['isFetching1'], + queryKey: key, queryFn: () => sleep(100).then(() => 'Some data'), })) return injectIsFetching() diff --git a/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts b/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts index 69685d9188..b24dfd88f1 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-is-mutating.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { TestBed } from '@angular/core/testing' import { Injector, provideZonelessChangeDetection } from '@angular/core' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { QueryClient, injectIsMutating, @@ -29,9 +29,10 @@ describe('injectIsMutating', () => { }) test('should properly return isMutating state', async () => { + const key = queryKey() const [mutation, isMutating] = TestBed.runInInjectionContext(() => [ injectMutation(() => ({ - mutationKey: ['isMutating1'], + mutationKey: key, mutationFn: (params: { par1: string }) => sleep(10).then(() => params), })), injectIsMutating(), diff --git a/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts b/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts index cd75f4e1e3..e06d032235 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-mutation-state.test.ts @@ -8,7 +8,7 @@ import { import { TestBed } from '@angular/core/testing' import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { By } from '@angular/platform-browser' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { QueryClient, injectMutation, @@ -37,7 +37,7 @@ describe('injectMutationState', () => { describe('injectMutationState', () => { test('should return variables after calling mutate 1', () => { - const mutationKey = ['mutation'] + const mutationKey = queryKey() const variables = 'foo123' const mutation = TestBed.runInInjectionContext(() => { @@ -60,8 +60,8 @@ describe('injectMutationState', () => { }) test('reactive options should update injectMutationState', () => { - const mutationKey1 = ['mutation1'] - const mutationKey2 = ['mutation2'] + const mutationKey1 = queryKey() + const mutationKey2 = queryKey() const variables1 = 'foo123' const variables2 = 'bar234' @@ -98,7 +98,7 @@ describe('injectMutationState', () => { test('should return variables after calling mutate 2', () => { queryClient.clear() - const mutationKey = ['mutation'] + const mutationKey = queryKey() const variables = 'bar234' const mutation = TestBed.runInInjectionContext(() => { diff --git a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts index b4d923707e..7a7120ce02 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts @@ -9,7 +9,7 @@ import { import { TestBed } from '@angular/core/testing' import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { By } from '@angular/platform-browser' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { QueryClient, injectMutation, provideTanStackQuery } from '..' import { expectSignals, setFixtureSignalInputs } from './test-utils' @@ -118,7 +118,9 @@ describe('injectMutation', () => { const mutationCache = queryClient.getMutationCache() // Signal will be updated before the mutation is called // this test confirms that the mutation uses the updated value - const mutationKey = signal(['1']) + const key1 = queryKey() + const key2 = queryKey() + const mutationKey = signal(key1) const mutation = TestBed.runInInjectionContext(() => { return injectMutation(() => ({ mutationKey: mutationKey(), @@ -126,13 +128,13 @@ describe('injectMutation', () => { })) }) - mutationKey.set(['2']) + mutationKey.set(key2) mutation.mutate('xyz') - const mutations = mutationCache.find({ mutationKey: ['2'] }) + const mutations = mutationCache.find({ mutationKey: key2 }) - expect(mutations?.options.mutationKey).toEqual(['2']) + expect(mutations?.options.mutationKey).toEqual(key2) }) test('should reset state after invoking mutation.reset', async () => { @@ -391,11 +393,12 @@ describe('injectMutation', () => { describe('throwOnError', () => { test('should evaluate throwOnError when mutation is expected to throw', async () => { + const key = queryKey() const err = new Error('Expected mock error. All is well!') const boundaryFn = vi.fn() const { mutate } = TestBed.runInInjectionContext(() => { return injectMutation(() => ({ - mutationKey: ['fake'], + mutationKey: key, mutationFn: () => { return Promise.reject(err) }, @@ -414,9 +417,10 @@ describe('injectMutation', () => { }) test('should throw when throwOnError is true and mutate is used', async () => { + const key = queryKey() const { mutate } = TestBed.runInInjectionContext(() => { return injectMutation(() => ({ - mutationKey: ['fake'], + mutationKey: key, mutationFn: () => { return Promise.reject( new Error('Expected mock error. All is well!'), @@ -437,10 +441,11 @@ describe('injectMutation', () => { }) test('should throw when throwOnError is true', async () => { + const key = queryKey() const err = new Error('Expected mock error. All is well!') const { mutateAsync } = TestBed.runInInjectionContext(() => { return injectMutation(() => ({ - mutationKey: ['fake'], + mutationKey: key, mutationFn: () => { return Promise.reject(err) }, @@ -452,10 +457,11 @@ describe('injectMutation', () => { }) test('should throw when throwOnError function returns true', async () => { + const key = queryKey() const err = new Error('Expected mock error. All is well!') const { mutateAsync } = TestBed.runInInjectionContext(() => { return injectMutation(() => ({ - mutationKey: ['fake'], + mutationKey: key, mutationFn: () => { return Promise.reject(err) }, @@ -468,19 +474,21 @@ describe('injectMutation', () => { describe('injection context', () => { test('throws NG0203 with descriptive error outside injection context', () => { + const key = queryKey() expect(() => { injectMutation(() => ({ - mutationKey: ['injectionContextError'], + mutationKey: key, mutationFn: () => Promise.resolve(), })) }).toThrow(/NG0203(.*?)injectMutation/) }) test('can be used outside injection context when passing an injector', () => { + const key = queryKey() expect(() => { injectMutation( () => ({ - mutationKey: ['injectionContextError'], + mutationKey: key, mutationFn: () => Promise.resolve(), }), { @@ -495,9 +503,10 @@ describe('injectMutation', () => { let mutationStarted = false let mutationCompleted = false + const key = queryKey() const mutation = TestBed.runInInjectionContext(() => injectMutation(() => ({ - mutationKey: ['pendingTasksTest'], + mutationKey: key, mutationFn: async (data: string) => { mutationStarted = true await sleep(50) @@ -588,9 +597,11 @@ describe('injectMutation', () => { const app = TestBed.inject(ApplicationRef) let callCount = 0 + const key = queryKey() + const mutation1 = TestBed.runInInjectionContext(() => injectMutation(() => ({ - mutationKey: ['sync-mutation-key'], + mutationKey: key, mutationFn: async (data: string) => { callCount++ return `mutation1: ${data}` @@ -600,7 +611,7 @@ describe('injectMutation', () => { const mutation2 = TestBed.runInInjectionContext(() => injectMutation(() => ({ - mutationKey: ['sync-mutation-key'], + mutationKey: key, mutationFn: async (data: string) => { callCount++ return `mutation2: ${data}` @@ -638,7 +649,7 @@ describe('injectMutation', () => { }) const app = TestBed.inject(ApplicationRef) - const testQueryKey = ['sync-optimistic'] + const testQueryKey = queryKey() let onMutateCalled = false let onSuccessCalled = false @@ -691,9 +702,10 @@ describe('injectMutation', () => { const app = TestBed.inject(ApplicationRef) + const key = queryKey() const mutation = TestBed.runInInjectionContext(() => injectMutation(() => ({ - mutationKey: ['cancel-sync'], + mutationKey: key, mutationFn: async (data: string) => `processed: ${data}`, // Synchronous resolution })), ) diff --git a/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts b/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts index de3f7e6857..b133575746 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-queries.test-d.ts @@ -1,4 +1,5 @@ import { describe, expectTypeOf, it } from 'vitest' +import { queryKey } from '@tanstack/query-test-utils' import { skipToken } from '..' import { injectQueries } from '../inject-queries' import { queryOptions } from '../query-options' @@ -8,8 +9,12 @@ import type { Signal } from '@angular/core' describe('injectQueries', () => { describe('config object overload', () => { it('TData should always be defined when initialData is provided as an object', () => { + const key1 = queryKey() + const key2 = queryKey() + const key3 = queryKey() + const query1 = { - queryKey: ['key1'], + queryKey: key1, queryFn: () => { return { wow: true, @@ -21,13 +26,13 @@ describe('injectQueries', () => { } const query2 = { - queryKey: ['key2'], + queryKey: key2, queryFn: () => 'Query Data', initialData: 'initial data', } const query3 = { - queryKey: ['key2'], + queryKey: key3, queryFn: () => 'Query Data', } @@ -45,8 +50,9 @@ describe('injectQueries', () => { }) it('TData should be defined when passed through queryOptions', () => { + const key = queryKey() const options = queryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -64,14 +70,17 @@ describe('injectQueries', () => { }) it('should be possible to define a different TData than TQueryFnData using select with queryOptions spread into injectQuery', () => { + const key1 = queryKey() + const key2 = queryKey() + const query1 = queryOptions({ - queryKey: ['key'], + queryKey: key1, queryFn: () => Promise.resolve(1), select: (data) => data > 1, }) const query2 = { - queryKey: ['key'], + queryKey: key2, queryFn: () => Promise.resolve(1), select: (data: number) => data > 1, } @@ -85,10 +94,11 @@ describe('injectQueries', () => { }) it('TData should have undefined in the union when initialData is provided as a function which can return undefined', () => { + const key = queryKey() const queryResults = injectQueries(() => ({ queries: [ { - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -107,6 +117,7 @@ describe('injectQueries', () => { describe('custom injectable', () => { it('should allow custom hooks using UseQueryOptions', () => { type Data = string + const key = queryKey() const injectCustomQueries = ( options?: OmitKeyof, 'queryKey' | 'queryFn'>, @@ -115,7 +126,7 @@ describe('injectQueries', () => { queries: [ { ...options, - queryKey: ['todos-key'], + queryKey: key, queryFn: () => Promise.resolve('data'), }, ], @@ -130,10 +141,11 @@ describe('injectQueries', () => { }) it('TData should have correct type when conditional skipToken is passed', () => { + const key = queryKey() const queryResults = injectQueries(() => ({ queries: [ { - queryKey: ['withSkipToken'], + queryKey: key, queryFn: Math.random() > 0.5 ? skipToken : () => Promise.resolve(5), }, ], @@ -148,17 +160,20 @@ describe('injectQueries', () => { }) it('should return correct data for dynamic queries with mixed result types', () => { + const key1 = queryKey() + const key2 = queryKey() + const Queries1 = { get: () => queryOptions({ - queryKey: ['key1'], + queryKey: key1, queryFn: () => Promise.resolve(1), }), } const Queries2 = { get: () => queryOptions({ - queryKey: ['key2'], + queryKey: key2, queryFn: () => Promise.resolve(true), }), } diff --git a/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts b/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts index a220ccfa6f..d48146aa67 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-query.test-d.ts @@ -1,5 +1,5 @@ import { describe, expectTypeOf, it, test } from 'vitest' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { injectQuery, queryOptions } from '..' import type { Signal } from '@angular/core' @@ -7,8 +7,9 @@ describe('injectQuery', () => { describe('initialData', () => { describe('Config object overload', () => { it('TData should always be defined when initialData is provided as an object', () => { + const key = queryKey() const { data } = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => ({ wow: true }), initialData: { wow: true }, })) @@ -17,9 +18,10 @@ describe('injectQuery', () => { }) it('TData should be defined when passed through queryOptions', () => { + const key = queryKey() const options = () => queryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -35,8 +37,9 @@ describe('injectQuery', () => { }) it('should be possible to define a different TData than TQueryFnData using select with queryOptions spread into useQuery', () => { + const key = queryKey() const options = queryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve(1), }) @@ -49,8 +52,9 @@ describe('injectQuery', () => { }) it('TData should always be defined when initialData is provided as a function which ALWAYS returns the data', () => { + const key = queryKey() const { data } = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -65,8 +69,9 @@ describe('injectQuery', () => { }) it('TData should have undefined in the union when initialData is NOT provided', () => { + const key = queryKey() const { data } = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -78,8 +83,9 @@ describe('injectQuery', () => { }) it('TData should have undefined in the union when initialData is provided as a function which can return undefined', () => { + const key = queryKey() const { data } = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -92,8 +98,9 @@ describe('injectQuery', () => { }) it('TData should be narrowed after an isSuccess check when initialData is provided as a function which can return undefined', () => { + const key = queryKey() const query = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => { return { wow: true, @@ -110,9 +117,10 @@ describe('injectQuery', () => { describe('structuralSharing', () => { it('should be able to use structuralSharing with unknown types', () => { + const key = queryKey() // https://github.com/TanStack/query/issues/6525#issuecomment-1938411343 injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => 5, structuralSharing: (oldData, newData) => { expectTypeOf(oldData).toBeUnknown() @@ -126,8 +134,9 @@ describe('injectQuery', () => { describe('Discriminated union return type', () => { test('data should be possibly undefined by default', () => { + const key = queryKey() const query = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), })) @@ -135,8 +144,9 @@ describe('injectQuery', () => { }) test('data should be defined when query is success', () => { + const key = queryKey() const query = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), })) @@ -146,8 +156,9 @@ describe('injectQuery', () => { }) test('error should be null when query is success', () => { + const key = queryKey() const query = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), })) @@ -157,8 +168,9 @@ describe('injectQuery', () => { }) test('data should be undefined when query is pending', () => { + const key = queryKey() const query = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), })) @@ -168,8 +180,9 @@ describe('injectQuery', () => { }) test('error should be defined when query is error', () => { + const key = queryKey() const query = injectQuery(() => ({ - queryKey: ['key'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), })) diff --git a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts index 29eab92d64..9b1a92f533 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts @@ -267,9 +267,10 @@ describe('injectQuery', () => { }) test('should return pending status initially', () => { + const key = queryKey() const query = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key1'], + queryKey: key, queryFn: () => sleep(10).then(() => 'Some data'), })) }) @@ -282,9 +283,10 @@ describe('injectQuery', () => { }) test('should resolve to success and update signal: injectQuery()', async () => { + const key = queryKey() const query = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key2'], + queryKey: key, queryFn: () => sleep(10).then(() => 'result2'), })) }) @@ -299,10 +301,11 @@ describe('injectQuery', () => { }) test('should reject and update signal', async () => { + const key = queryKey() const query = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ retry: false, - queryKey: ['key3'], + queryKey: key, queryFn: () => sleep(10).then(() => Promise.reject(new Error('Some error'))), })) @@ -320,7 +323,9 @@ describe('injectQuery', () => { }) test('should update query on options contained signal change', async () => { - const key = signal(['key6', 'key7']) + const key1 = queryKey() + const key2 = queryKey() + const key = signal(key1) const spy = vi.fn(() => sleep(10).then(() => 'Some data')) const query = TestBed.runInInjectionContext(() => { @@ -336,7 +341,7 @@ describe('injectQuery', () => { await vi.advanceTimersByTimeAsync(11) expect(query.status()).toBe('success') - key.set(['key8']) + key.set(key2) TestBed.tick() expect(spy).toHaveBeenCalledTimes(2) @@ -344,18 +349,19 @@ describe('injectQuery', () => { expect(spy).toBeCalledWith({ client: queryClient, meta: undefined, - queryKey: ['key8'], + queryKey: key2, signal: expect.anything(), }) }) test('should only run query once enabled signal is set to true', async () => { + const key = queryKey() const spy = vi.fn(() => sleep(10).then(() => 'Some data')) const enabled = signal(false) const query = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key9'], + queryKey: key, queryFn: spy, enabled: enabled(), })) @@ -372,9 +378,12 @@ describe('injectQuery', () => { }) test('should properly execute dependent queries', async () => { + const key1 = queryKey() + const key2 = queryKey() + const query1 = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['dependent1'], + queryKey: key1, queryFn: () => sleep(10).then(() => 'Some data'), })) }) @@ -386,7 +395,7 @@ describe('injectQuery', () => { const query2 = TestBed.runInInjectionContext(() => { return injectQuery( computed(() => ({ - queryKey: ['dependent2'], + queryKey: key2, queryFn: dependentQueryFn, enabled: !!query1.data(), })), @@ -408,17 +417,18 @@ describe('injectQuery', () => { expect(query2.status()).toStrictEqual('success') expect(dependentQueryFn).toHaveBeenCalledTimes(1) expect(dependentQueryFn).toHaveBeenCalledWith( - expect.objectContaining({ queryKey: ['dependent2'] }), + expect.objectContaining({ queryKey: key2 }), ) }) test('should use the current value for the queryKey when refetch is called', async () => { + const key = queryKey() const fetchFn = vi.fn(() => sleep(10).then(() => 'Some data')) const keySignal = signal('key11') const query = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key10', keySignal()], + queryKey: [...key, keySignal()], queryFn: fetchFn, enabled: false, })) @@ -430,7 +440,7 @@ describe('injectQuery', () => { expect(fetchFn).toHaveBeenCalledTimes(1) expect(fetchFn).toHaveBeenCalledWith( expect.objectContaining({ - queryKey: ['key10', 'key11'], + queryKey: [...key, 'key11'], }), ) }) @@ -443,7 +453,7 @@ describe('injectQuery', () => { expect(fetchFn).toHaveBeenCalledTimes(2) expect(fetchFn).toHaveBeenCalledWith( expect.objectContaining({ - queryKey: ['key10', 'key12'], + queryKey: [...key, 'key12'], }), ) }) @@ -453,10 +463,11 @@ describe('injectQuery', () => { describe('throwOnError', () => { test('should evaluate throwOnError when query is expected to throw', async () => { + const key = queryKey() const boundaryFn = vi.fn() TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key12'], + queryKey: key, queryFn: () => sleep(10).then(() => Promise.reject(new Error('Some error'))), retry: false, @@ -475,9 +486,10 @@ describe('injectQuery', () => { }) test('should throw when throwOnError is true', async () => { + const key = queryKey() TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key13'], + queryKey: key, queryFn: () => sleep(0).then(() => Promise.reject(new Error('Some error'))), throwOnError: true, @@ -488,9 +500,10 @@ describe('injectQuery', () => { }) test('should throw when throwOnError function returns true', async () => { + const key = queryKey() TestBed.runInInjectionContext(() => { return injectQuery(() => ({ - queryKey: ['key14'], + queryKey: key, queryFn: () => sleep(0).then(() => Promise.reject(new Error('Some error'))), throwOnError: () => true, @@ -502,10 +515,11 @@ describe('injectQuery', () => { }) test('should set state to error when queryFn returns reject promise', async () => { + const key = queryKey() const query = TestBed.runInInjectionContext(() => { return injectQuery(() => ({ retry: false, - queryKey: ['key15'], + queryKey: key, queryFn: () => sleep(10).then(() => Promise.reject(new Error('Some error'))), })) @@ -584,18 +598,20 @@ describe('injectQuery', () => { describe('injection context', () => { test('throws NG0203 with descriptive error outside injection context', () => { + const key = queryKey() expect(() => { injectQuery(() => ({ - queryKey: ['injectionContextError'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), })) }).toThrow(/NG0203(.*?)injectQuery/) }) test('can be used outside injection context when passing an injector', () => { + const key = queryKey() const query = injectQuery( () => ({ - queryKey: ['manualInjector'], + queryKey: key, queryFn: () => sleep(0).then(() => 'Some data'), }), { @@ -607,11 +623,12 @@ describe('injectQuery', () => { }) test('should complete queries before whenStable() resolves', async () => { + const key = queryKey() const app = TestBed.inject(ApplicationRef) const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['pendingTasksTest'], + queryKey: key, queryFn: () => sleep(50).then(() => 'test data'), })), ) @@ -643,9 +660,10 @@ describe('injectQuery', () => { const httpTestingController = TestBed.inject(HttpTestingController) // Create a query using HttpClient + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['httpClientTest'], + queryKey: key, queryFn: () => lastValueFrom(httpClient.get<{ message: string }>('/api/test')), })), @@ -684,9 +702,10 @@ describe('injectQuery', () => { const app = TestBed.inject(ApplicationRef) let callCount = 0 + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['sync-stale'], + queryKey: key, staleTime: 1000, queryFn: () => { callCount++ @@ -728,9 +747,10 @@ describe('injectQuery', () => { const enabledSignal = signal(false) let callCount = 0 + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['sync-enabled'], + queryKey: key, enabled: enabledSignal(), queryFn: () => { callCount++ @@ -766,7 +786,7 @@ describe('injectQuery', () => { }) const app = TestBed.inject(ApplicationRef) - const testKey = ['sync-invalidate'] + const testKey = queryKey() let callCount = 0 const query = TestBed.runInInjectionContext(() => diff --git a/packages/angular-query-experimental/src/__tests__/mutation-options.test-d.ts b/packages/angular-query-experimental/src/__tests__/mutation-options.test-d.ts index 968eda7b30..89691bf81a 100644 --- a/packages/angular-query-experimental/src/__tests__/mutation-options.test-d.ts +++ b/packages/angular-query-experimental/src/__tests__/mutation-options.test-d.ts @@ -1,4 +1,5 @@ import { assertType, describe, expectTypeOf, it } from 'vitest' +import { queryKey } from '@tanstack/query-test-utils' import { QueryClient } from '@tanstack/query-core' import { injectIsMutating, @@ -16,10 +17,11 @@ import type { CreateMutationOptions, CreateMutationResult } from '../types' describe('mutationOptions', () => { it('should not allow excess properties', () => { + const key = queryKey() // @ts-expect-error this is a good error, because onMutates does not exist! mutationOptions({ mutationFn: () => Promise.resolve(5), - mutationKey: ['key'], + mutationKey: key, onMutates: 1000, onSuccess: (data) => { expectTypeOf(data).toEqualTypeOf() @@ -28,9 +30,10 @@ describe('mutationOptions', () => { }) it('should infer types for callbacks', () => { + const key = queryKey() mutationOptions({ mutationFn: () => Promise.resolve(5), - mutationKey: ['key'], + mutationKey: key, onSuccess: (data) => { expectTypeOf(data).toEqualTypeOf() }, @@ -38,11 +41,12 @@ describe('mutationOptions', () => { }) it('should infer types for onError callback', () => { + const key = queryKey() mutationOptions({ mutationFn: () => { throw new Error('fail') }, - mutationKey: ['key'], + mutationKey: key, onError: (error) => { expectTypeOf(error).toEqualTypeOf() }, @@ -50,19 +54,21 @@ describe('mutationOptions', () => { }) it('should infer types for variables', () => { + const key = queryKey() mutationOptions({ mutationFn: (vars) => { expectTypeOf(vars).toEqualTypeOf<{ id: string }>() return Promise.resolve(5) }, - mutationKey: ['with-vars'], + mutationKey: key, }) }) it('should infer result type correctly', () => { + const key = queryKey() mutationOptions({ mutationFn: () => Promise.resolve(5), - mutationKey: ['key'], + mutationKey: key, onMutate: () => { return { name: 'onMutateResult' } }, @@ -73,12 +79,13 @@ describe('mutationOptions', () => { }) it('should infer context type correctly', () => { + const key = queryKey() mutationOptions({ mutationFn: (_variables, context) => { expectTypeOf(context).toEqualTypeOf() return Promise.resolve(5) }, - mutationKey: ['key'], + mutationKey: key, onMutate: (_variables, context) => { expectTypeOf(context).toEqualTypeOf() }, @@ -113,10 +120,11 @@ describe('mutationOptions', () => { }) it('should infer all types when not explicitly provided', () => { + const key = queryKey() expectTypeOf( mutationOptions({ mutationFn: (id: string) => Promise.resolve(id.length), - mutationKey: ['key'], + mutationKey: key, onSuccess: (data) => { expectTypeOf(data).toEqualTypeOf() }, @@ -140,9 +148,10 @@ describe('mutationOptions', () => { }) it('should infer types when used with injectMutation', () => { + const key = queryKey() const mutation = injectMutation(() => mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => Promise.resolve('data'), onSuccess: (data) => { expectTypeOf(data).toEqualTypeOf() @@ -166,9 +175,10 @@ describe('mutationOptions', () => { }) it('should infer types when used with injectIsMutating', () => { + const key = queryKey() const isMutating = injectIsMutating( mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => Promise.resolve(5), }), ) @@ -183,11 +193,12 @@ describe('mutationOptions', () => { }) it('should infer types when used with queryClient.isMutating', () => { + const key = queryKey() const queryClient = new QueryClient() const isMutating = queryClient.isMutating( mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => Promise.resolve(5), }), ) @@ -202,9 +213,10 @@ describe('mutationOptions', () => { }) it('should infer types when used with injectMutationState', () => { + const key = queryKey() const mutationState = injectMutationState(() => ({ filters: mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => Promise.resolve(5), }), })) diff --git a/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts b/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts index e07b371c6a..538e353852 100644 --- a/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts +++ b/packages/angular-query-experimental/src/__tests__/mutation-options.test.ts @@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { provideZonelessChangeDetection } from '@angular/core' import { TestBed } from '@angular/core/testing' import { QueryClient } from '@tanstack/query-core' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { injectIsMutating, injectMutation, @@ -31,8 +31,9 @@ describe('mutationOptions', () => { }) it('should return the object received as a parameter without any modification (with mutationKey in mutationOptions)', () => { + const key = queryKey() const object: CreateMutationOptions = { - mutationKey: ['key'], + mutationKey: key, mutationFn: () => sleep(10).then(() => 5), } as const @@ -48,8 +49,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with injectIsMutating (with mutationKey in mutationOptions)', async () => { + const key = queryKey() const mutationOpts = mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => sleep(50).then(() => 'data'), }) @@ -89,8 +91,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with injectIsMutating', async () => { + const key = queryKey() const mutationOpts1 = mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => sleep(50).then(() => 'data1'), }) const mutationOpts2 = mutationOptions({ @@ -117,8 +120,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with injectIsMutating (filter mutationOpts1.mutationKey)', async () => { + const key = queryKey() const mutationOpts1 = mutationOptions({ - mutationKey: ['key'], + mutationKey: key, mutationFn: () => sleep(50).then(() => 'data1'), }) const mutationOpts2 = mutationOptions({ @@ -145,8 +149,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with queryClient.isMutating (with mutationKey in mutationOptions)', async () => { + const key = queryKey() const mutationOpts = mutationOptions({ - mutationKey: ['mutation'], + mutationKey: key, mutationFn: () => sleep(500).then(() => 'data'), }) @@ -180,8 +185,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with queryClient.isMutating', async () => { + const key = queryKey() const mutationOpts1 = mutationOptions({ - mutationKey: ['mutation'], + mutationKey: key, mutationFn: () => sleep(500).then(() => 'data1'), }) const mutationOpts2 = mutationOptions({ @@ -203,8 +209,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with queryClient.isMutating (filter mutationOpt1.mutationKey)', async () => { + const key = queryKey() const mutationOpts1 = mutationOptions({ - mutationKey: ['mutation'], + mutationKey: key, mutationFn: () => sleep(500).then(() => 'data1'), }) const mutationOpts2 = mutationOptions({ @@ -232,8 +239,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with injectMutationState (with mutationKey in mutationOptions)', async () => { + const key = queryKey() const mutationOpts = mutationOptions({ - mutationKey: ['mutation'], + mutationKey: key, mutationFn: () => sleep(10).then(() => 'data'), }) @@ -273,8 +281,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with injectMutationState', async () => { + const key = queryKey() const mutationOpts1 = mutationOptions({ - mutationKey: ['mutation'], + mutationKey: key, mutationFn: () => sleep(10).then(() => 'data1'), }) const mutationOpts2 = mutationOptions({ @@ -302,8 +311,9 @@ describe('mutationOptions', () => { }) it('should return the number of fetching mutations when used with injectMutationState (filter mutationOpt1.mutationKey)', async () => { + const key = queryKey() const mutationOpts1 = mutationOptions({ - mutationKey: ['mutation'], + mutationKey: key, mutationFn: () => sleep(10).then(() => 'data1'), }) const mutationOpts2 = mutationOptions({ diff --git a/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts b/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts index 643e140589..65f1395f93 100644 --- a/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts +++ b/packages/angular-query-experimental/src/__tests__/pending-tasks.test.ts @@ -10,7 +10,7 @@ import { provideHttpClientTesting, } from '@angular/common/http/testing' import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' -import { sleep } from '@tanstack/query-test-utils' +import { queryKey, sleep } from '@tanstack/query-test-utils' import { lastValueFrom } from 'rxjs' import { QueryClient, @@ -55,9 +55,10 @@ describe('PendingTasks Integration', () => { test('should handle synchronous queryFn with whenStable()', async () => { const app = TestBed.inject(ApplicationRef) + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['sync'], + queryKey: key, queryFn: () => 'instant-data', // Resolves synchronously })), ) @@ -80,9 +81,10 @@ describe('PendingTasks Integration', () => { test('should handle synchronous error with whenStable()', async () => { const app = TestBed.inject(ApplicationRef) + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['sync-error'], + queryKey: key, queryFn: () => { throw new Error('instant-error') }, // Throws synchronously @@ -155,6 +157,7 @@ describe('PendingTasks Integration', () => { describe('Race Conditions', () => { test('should handle query that completes during initial subscription', async () => { + const key = queryKey() const app = TestBed.inject(ApplicationRef) let resolveQuery: (value: string) => void @@ -164,7 +167,7 @@ describe('PendingTasks Integration', () => { const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['race-condition'], + queryKey: key, queryFn: () => queryPromise, })), ) @@ -185,9 +188,10 @@ describe('PendingTasks Integration', () => { const app = TestBed.inject(ApplicationRef) let callCount = 0 + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['rapid-refetch'], + queryKey: key, queryFn: async () => { callCount++ await sleep(10) @@ -213,9 +217,10 @@ describe('PendingTasks Integration', () => { const app = TestBed.inject(ApplicationRef) let attempt = 0 + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['paused-offline'], + queryKey: key, retry: 1, retryDelay: 50, // Longer delay to ensure we can go offline before retry queryFn: async () => { @@ -328,25 +333,28 @@ describe('PendingTasks Integration', () => { describe('Concurrent Operations', () => { test('should handle multiple queries running simultaneously', async () => { + const key1 = queryKey() + const key2 = queryKey() + const key3 = queryKey() const app = TestBed.inject(ApplicationRef) const query1 = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['concurrent-1'], + queryKey: key1, queryFn: () => sleep(30).then(() => 'data-1'), })), ) const query2 = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['concurrent-2'], + queryKey: key2, queryFn: () => sleep(50).then(() => 'data-2'), })), ) const query3 = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['concurrent-3'], + queryKey: key3, queryFn: () => 'instant-data', // Synchronous })), ) @@ -418,9 +426,10 @@ describe('PendingTasks Integration', () => { test('should handle mixed queries and mutations', async () => { const app = TestBed.inject(ApplicationRef) + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['mixed-query'], + queryKey: key, queryFn: () => sleep(40).then(() => 'query-data'), })), ) @@ -465,9 +474,12 @@ describe('PendingTasks Integration', () => { const httpClient = TestBed.inject(HttpClient) const httpTestingController = TestBed.inject(HttpTestingController) + const key1 = queryKey() + const key2 = queryKey() + const query1 = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['http-1'], + queryKey: key1, queryFn: () => lastValueFrom(httpClient.get<{ id: number }>('/api/1')), })), @@ -475,7 +487,7 @@ describe('PendingTasks Integration', () => { const query2 = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['http-2'], + queryKey: key2, queryFn: () => lastValueFrom(httpClient.get<{ id: number }>('/api/2')), })), @@ -507,9 +519,10 @@ describe('PendingTasks Integration', () => { const httpClient = TestBed.inject(HttpClient) const httpTestingController = TestBed.inject(HttpTestingController) + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['http-cancel'], + queryKey: key, queryFn: () => lastValueFrom(httpClient.get<{ data: string }>('/api/cancel')), })), @@ -536,18 +549,19 @@ describe('PendingTasks Integration', () => { describe('Edge Cases', () => { test('should handle query cancellation mid-flight', async () => { + const key = queryKey() const app = TestBed.inject(ApplicationRef) const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['cancel-test'], + queryKey: key, queryFn: () => sleep(100).then(() => 'data'), })), ) // Cancel the query after a short delay setTimeout(() => { - queryClient.cancelQueries({ queryKey: ['cancel-test'] }) + queryClient.cancelQueries({ queryKey: key }) }, 20) // Advance to the cancellation point @@ -568,9 +582,10 @@ describe('PendingTasks Integration', () => { const app = TestBed.inject(ApplicationRef) let attemptCount = 0 + const key = queryKey() const query = TestBed.runInInjectionContext(() => injectQuery(() => ({ - queryKey: ['retry-test'], + queryKey: key, retry: 2, retryDelay: 10, queryFn: async () => { @@ -594,7 +609,7 @@ describe('PendingTasks Integration', () => { test('should handle mutation with optimistic updates', async () => { const app = TestBed.inject(ApplicationRef) - const testQueryKey = ['optimistic-test'] + const testQueryKey = queryKey() queryClient.setQueryData(testQueryKey, 'initial-data') diff --git a/packages/angular-query-experimental/src/__tests__/query-options.test-d.ts b/packages/angular-query-experimental/src/__tests__/query-options.test-d.ts index 350ab3dda2..cfd1890d1c 100644 --- a/packages/angular-query-experimental/src/__tests__/query-options.test-d.ts +++ b/packages/angular-query-experimental/src/__tests__/query-options.test-d.ts @@ -1,4 +1,5 @@ import { assertType, describe, expectTypeOf, test } from 'vitest' +import { queryKey } from '@tanstack/query-test-utils' import { QueryClient, dataTagSymbol, injectQuery, queryOptions } from '..' import type { Signal } from '@angular/core' @@ -8,8 +9,9 @@ describe('queryOptions', () => { }) test('should infer types for callbacks', () => { + const key = queryKey() queryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve(5), staleTime: 1000, select: (data) => { @@ -19,9 +21,10 @@ describe('queryOptions', () => { }) test('should allow undefined response in initialData', () => { + const key = queryKey() const options = (id: string | null) => queryOptions({ - queryKey: ['todo', id], + queryKey: [...key, id], queryFn: () => Promise.resolve({ id: '1', @@ -43,8 +46,9 @@ describe('queryOptions', () => { }) test('should work when passed to injectQuery', () => { + const key = queryKey() const options = queryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve(5), }) @@ -53,8 +57,9 @@ test('should work when passed to injectQuery', () => { }) test('should work when passed to fetchQuery', () => { + const key = queryKey() const options = queryOptions({ - queryKey: ['key'], + queryKey: key, queryFn: () => Promise.resolve(5), }) @@ -63,59 +68,65 @@ test('should work when passed to fetchQuery', () => { }) test('should tag the queryKey with the result type of the QueryFn', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, queryFn: () => Promise.resolve(5), }) - assertType(queryKey[dataTagSymbol]) + assertType(tagged[dataTagSymbol]) }) test('should tag the queryKey even if no promise is returned', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, queryFn: () => 5, }) - assertType(queryKey[dataTagSymbol]) + assertType(tagged[dataTagSymbol]) }) test('should tag the queryKey with unknown if there is no queryFn', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, }) - assertType(queryKey[dataTagSymbol]) + assertType(tagged[dataTagSymbol]) }) test('should tag the queryKey with the result type of the QueryFn if select is used', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, queryFn: () => Promise.resolve(5), select: (data) => data.toString(), }) - assertType(queryKey[dataTagSymbol]) + assertType(tagged[dataTagSymbol]) }) test('should return the proper type when passed to getQueryData', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, queryFn: () => Promise.resolve(5), }) const queryClient = new QueryClient() - const data = queryClient.getQueryData(queryKey) + const data = queryClient.getQueryData(tagged) expectTypeOf(data).toEqualTypeOf() }) test('should properly type updaterFn when passed to setQueryData', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, queryFn: () => Promise.resolve(5), }) const queryClient = new QueryClient() - const data = queryClient.setQueryData(queryKey, (prev) => { + const data = queryClient.setQueryData(tagged, (prev) => { expectTypeOf(prev).toEqualTypeOf() return prev }) @@ -124,19 +135,20 @@ test('should properly type updaterFn when passed to setQueryData', () => { }) test('should properly type value when passed to setQueryData', () => { - const { queryKey } = queryOptions({ - queryKey: ['key'], + const key = queryKey() + const { queryKey: tagged } = queryOptions({ + queryKey: key, queryFn: () => Promise.resolve(5), }) const queryClient = new QueryClient() // @ts-expect-error value should be a number - queryClient.setQueryData(queryKey, '5') + queryClient.setQueryData(tagged, '5') // @ts-expect-error value should be a number - queryClient.setQueryData(queryKey, () => '5') + queryClient.setQueryData(tagged, () => '5') - const data = queryClient.setQueryData(queryKey, 5) + const data = queryClient.setQueryData(tagged, 5) expectTypeOf(data).toEqualTypeOf() })