From 20fc6c290805c29957cc3fc91b93df8d30ab1249 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Sun, 26 Apr 2026 14:09:31 +0900 Subject: [PATCH 1/6] test(angular-query-experimental/injectInfiniteQuery): add test for error state when 'queryFn' rejects (#10585) --- .../__tests__/inject-infinite-query.test.ts | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) 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 e3c3744d56..f1f38acc7a 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 @@ -66,6 +66,44 @@ describe('injectInfiniteQuery', () => { ).toBeInTheDocument() }) + it('should reject and update signal', async () => { + const key = queryKey() + + @Component({ + template: ` +
status: {{ query.status() }}
+
pages: {{ query.data()?.pages?.join(', ') ?? 'none' }}
+
error: {{ query.error()?.message ?? 'none' }}
+
isError: {{ query.isError() }}
+
failureCount: {{ query.failureCount() }}
+ `, + }) + class Page { + readonly query = injectInfiniteQuery(() => ({ + retry: false, + queryKey: key, + queryFn: () => + sleep(10).then(() => Promise.reject(new Error('Some error'))), + initialPageParam: 0, + getNextPageParam: () => 12, + })) + } + + const rendered = await render(Page) + + expect(rendered.getByText('status: pending')).toBeInTheDocument() + expect(rendered.getByText('pages: none')).toBeInTheDocument() + + await vi.advanceTimersByTimeAsync(11) + rendered.fixture.detectChanges() + + expect(rendered.getByText('status: error')).toBeInTheDocument() + expect(rendered.getByText('pages: none')).toBeInTheDocument() + expect(rendered.getByText('error: Some error')).toBeInTheDocument() + expect(rendered.getByText('isError: true')).toBeInTheDocument() + expect(rendered.getByText('failureCount: 1')).toBeInTheDocument() + }) + describe('injection context', () => { it('should throw NG0203 with descriptive error outside injection context', () => { const key = queryKey() From 4f373699e05fd23c574a7dfe0b627b7652d3bc0c Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Sun, 26 Apr 2026 14:21:24 +0900 Subject: [PATCH 2/6] test(angular-query-experimental/injectQuery): add test for 'select' option transforming 'queryFn' data (#10586) --- .../src/__tests__/inject-query.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) 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 82eb8f0f34..1254564a8b 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts @@ -356,6 +356,30 @@ describe('injectQuery', () => { expect(rendered.getByText('failureReason: Some error')).toBeInTheDocument() }) + it('should be able to select a part of the data with select', async () => { + const key = queryKey() + + @Component({ + template: `
data: {{ query.data() ?? 'none' }}
`, + }) + class Page { + readonly query = injectQuery<{ name: string }, Error, string>(() => ({ + queryKey: key, + queryFn: () => sleep(10).then(() => ({ name: 'test' })), + select: (data) => data.name, + })) + } + + const rendered = await render(Page) + + expect(rendered.getByText('data: none')).toBeInTheDocument() + + await vi.advanceTimersByTimeAsync(11) + rendered.fixture.detectChanges() + + expect(rendered.getByText('data: test')).toBeInTheDocument() + }) + it('should update query on options contained signal change', async () => { const key1 = queryKey() const key2 = queryKey() From 76161b7a6b403dad448b75bc15f06b86effb2283 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Sun, 26 Apr 2026 14:42:26 +0900 Subject: [PATCH 3/6] test(angular-query-experimental/injectQuery): add test for 'placeholderData' lifecycle (#10587) --- .../src/__tests__/inject-query.test.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) 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 1254564a8b..4ff82e2250 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts @@ -380,6 +380,38 @@ describe('injectQuery', () => { expect(rendered.getByText('data: test')).toBeInTheDocument() }) + it('should show placeholderData until queryFn resolves and then expose real data', async () => { + const key = queryKey() + + @Component({ + template: ` +
data: {{ query.data() }}
+
isPlaceholderData: {{ query.isPlaceholderData() }}
+
isSuccess: {{ query.isSuccess() }}
+ `, + }) + class Page { + readonly query = injectQuery(() => ({ + queryKey: key, + queryFn: () => sleep(10).then(() => 'real-data'), + placeholderData: 'placeholder', + })) + } + + const rendered = await render(Page) + + expect(rendered.getByText('data: placeholder')).toBeInTheDocument() + expect(rendered.getByText('isPlaceholderData: true')).toBeInTheDocument() + expect(rendered.getByText('isSuccess: true')).toBeInTheDocument() + + await vi.advanceTimersByTimeAsync(11) + rendered.fixture.detectChanges() + + expect(rendered.getByText('data: real-data')).toBeInTheDocument() + expect(rendered.getByText('isPlaceholderData: false')).toBeInTheDocument() + expect(rendered.getByText('isSuccess: true')).toBeInTheDocument() + }) + it('should update query on options contained signal change', async () => { const key1 = queryKey() const key2 = queryKey() From d78883bff0a0b950fa1385588def01db99397aaa Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Sun, 26 Apr 2026 14:53:07 +0900 Subject: [PATCH 4/6] test(angular-query-experimental/injectQuery): remove duplicate error test already covered by 'should reject and update signal' (#10588) --- .../src/__tests__/inject-query.test.ts | 18 ------------------ 1 file changed, 18 deletions(-) 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 4ff82e2250..a8bff8527b 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-query.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-query.test.ts @@ -604,24 +604,6 @@ describe('injectQuery', () => { }) }) - it('should set state to error when queryFn returns reject promise', async () => { - const key = queryKey() - const query = TestBed.runInInjectionContext(() => { - return injectQuery(() => ({ - retry: false, - queryKey: key, - queryFn: () => - sleep(10).then(() => Promise.reject(new Error('Some error'))), - })) - }) - - expect(query.status()).toBe('pending') - - await vi.advanceTimersByTimeAsync(11) - - expect(query.status()).toBe('error') - }) - it('should render with required signal inputs', async () => { @Component({ selector: 'app-fake', From e69e5d2a07cc8ac661b1a2d926b8409b155a2e22 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Sun, 26 Apr 2026 15:03:29 +0900 Subject: [PATCH 5/6] test(angular-query-experimental/injectMutation): switch 'error' test to '@Component' + 'render' pattern (#10589) --- .../src/__tests__/inject-mutation.test.ts | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) 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 b9d3eea6e1..c1023a5391 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts @@ -72,25 +72,36 @@ describe('injectMutation', () => { }) it('should return error when request fails', async () => { - const mutation = TestBed.runInInjectionContext(() => { - return injectMutation(() => ({ + @Component({ + template: ` +
isIdle: {{ mutation.isIdle() }}
+
isPending: {{ mutation.isPending() }}
+
isError: {{ mutation.isError() }}
+
isSuccess: {{ mutation.isSuccess() }}
+
data: {{ mutation.data() ?? 'none' }}
+
error: {{ mutation.error()?.message ?? 'none' }}
+ `, + }) + class Page { + readonly mutation = injectMutation(() => ({ mutationFn: () => sleep(10).then(() => Promise.reject(new Error('Some error'))), })) - }) + } - mutation.mutate() + const rendered = await render(Page) + + rendered.fixture.componentInstance.mutation.mutate() await vi.advanceTimersByTimeAsync(11) + rendered.fixture.detectChanges() - expectSignals(mutation, { - isIdle: false, - isPending: false, - isError: true, - isSuccess: false, - data: undefined, - error: Error('Some error'), - }) + expect(rendered.getByText('isIdle: false')).toBeInTheDocument() + expect(rendered.getByText('isPending: false')).toBeInTheDocument() + expect(rendered.getByText('isError: true')).toBeInTheDocument() + expect(rendered.getByText('isSuccess: false')).toBeInTheDocument() + expect(rendered.getByText('data: none')).toBeInTheDocument() + expect(rendered.getByText('error: Some error')).toBeInTheDocument() }) it('should return data when request succeeds', async () => { From 72a15ae4d9f6fe262cb1bd72107f9862291c1e9d Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Sun, 26 Apr 2026 15:31:53 +0900 Subject: [PATCH 6/6] test(angular-query-experimental/injectMutation): switch 'pending' test to '@Component' + 'render' pattern (#10590) --- .../src/__tests__/inject-mutation.test.ts | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) 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 c1023a5391..fd32ee09b8 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts @@ -50,25 +50,34 @@ describe('injectMutation', () => { it('should change state after invoking mutate', async () => { const result = 'Mock data' - const mutation = TestBed.runInInjectionContext(() => { - return injectMutation(() => ({ + @Component({ + template: ` +
isIdle: {{ mutation.isIdle() }}
+
isPending: {{ mutation.isPending() }}
+
isError: {{ mutation.isError() }}
+
isSuccess: {{ mutation.isSuccess() }}
+
data: {{ mutation.data() ?? 'none' }}
+
error: {{ mutation.error()?.message ?? 'none' }}
+ `, + }) + class Page { + readonly mutation = injectMutation(() => ({ mutationFn: (params: string) => sleep(10).then(() => params), })) - }) + } - TestBed.tick() + const rendered = await render(Page) - mutation.mutate(result) + rendered.fixture.componentInstance.mutation.mutate(result) await vi.advanceTimersByTimeAsync(0) + rendered.fixture.detectChanges() - expectSignals(mutation, { - isIdle: false, - isPending: true, - isError: false, - isSuccess: false, - data: undefined, - error: null, - }) + expect(rendered.getByText('isIdle: false')).toBeInTheDocument() + expect(rendered.getByText('isPending: true')).toBeInTheDocument() + expect(rendered.getByText('isError: false')).toBeInTheDocument() + expect(rendered.getByText('isSuccess: false')).toBeInTheDocument() + expect(rendered.getByText('data: none')).toBeInTheDocument() + expect(rendered.getByText('error: none')).toBeInTheDocument() }) it('should return error when request fails', async () => {