From f34b8118bdc250026bd460dece4c1e1406cc2649 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Wed, 1 May 2024 15:28:49 -0400 Subject: [PATCH 1/3] fix(angular-query-experimental): run mutation callback in injection context Previously, the injectMutation callback was run in injection context only if accessed in the same task as the component initialization (i.e. before the `effect` callback run). By running the effect run in injection context, it is ensured that the callback will always run in injection context, and any `inject` calls will not fail. Note there is a separate issue here, and it's that the callback is always run twice - once synchronously when initialization the mutation, and secondly as the first callback of the `effect`. This is something that can potentially be improved. No breaking changes, any code that worked before should still work. --- .../src/__tests__/inject-mutation.test.ts | 36 ++++++++++++++++++- .../src/inject-mutation.ts | 4 ++- 2 files changed, 38 insertions(+), 2 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 133197deed..a8157eb56c 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts @@ -1,4 +1,4 @@ -import { Component, input, signal } from '@angular/core' +import { Component, Injectable, inject, input, signal } from '@angular/core' import { QueryClient } from '@tanstack/query-core' import { TestBed } from '@angular/core/testing' import { describe, expect, vi } from 'vitest' @@ -455,4 +455,38 @@ describe('injectMutation', () => { await expect(() => mutateAsync()).rejects.toThrowError(err) }) + + test('should execute callback in injection context', async () => { + @Injectable() + class FakeService { + updateData(name: string) { + return Promise.resolve(name) + } + } + + @Component({ + selector: 'app-fake', + template: ``, + standalone: true, + providers: [FakeService], + }) + class FakeComponent { + mutation = injectMutation(() => { + const service = inject(FakeService) + return { + mutationFn: (name: string) => service.updateData(name), + } + }) + } + + const fixture = TestBed.createComponent(FakeComponent) + fixture.detectChanges() + + // check if injection contexts persist in a different task + await new Promise((resolve) => queueMicrotask(() => resolve())) + + expect( + await fixture.componentInstance.mutation.mutateAsync('test'), + ).toEqual('test') + }) }) diff --git a/packages/angular-query-experimental/src/inject-mutation.ts b/packages/angular-query-experimental/src/inject-mutation.ts index f7948df617..e7a63225ec 100644 --- a/packages/angular-query-experimental/src/inject-mutation.ts +++ b/packages/angular-query-experimental/src/inject-mutation.ts @@ -70,7 +70,9 @@ export function injectMutation< } effect(() => { - observer.setOptions(optionsFn(queryClient)) + observer.setOptions( + runInInjectionContext(currentInjector, () => optionsFn(queryClient)), + ) }) const result = signal(observer.getCurrentResult()) From 107e50b0f61f26b5fa764f774af37ddd67eefc7b Mon Sep 17 00:00:00 2001 From: Arnoud de Vries <6420061+arnoud-dv@users.noreply.github.com> Date: Sat, 1 Jun 2024 19:36:30 +0200 Subject: [PATCH 2/3] run prettier --- packages/angular-query-experimental/src/inject-mutation.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/angular-query-experimental/src/inject-mutation.ts b/packages/angular-query-experimental/src/inject-mutation.ts index e7a63225ec..4ec2c304b9 100644 --- a/packages/angular-query-experimental/src/inject-mutation.ts +++ b/packages/angular-query-experimental/src/inject-mutation.ts @@ -71,7 +71,9 @@ export function injectMutation< effect(() => { observer.setOptions( - runInInjectionContext(currentInjector, () => optionsFn(queryClient)), + runInInjectionContext(currentInjector, () => + optionsFn(queryClient), + ), ) }) From 2eeb6b45021484bc463a8d8238f68c1d6ee25db4 Mon Sep 17 00:00:00 2001 From: ShacharHarshuv Date: Fri, 21 Jun 2024 09:41:16 -0400 Subject: [PATCH 3/3] Catch error in test --- .../src/__tests__/inject-mutation.test.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 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 a8157eb56c..af86800221 100644 --- a/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts +++ b/packages/angular-query-experimental/src/__tests__/inject-mutation.test.ts @@ -457,6 +457,7 @@ describe('injectMutation', () => { }) test('should execute callback in injection context', async () => { + const errorSpy = vi.fn() @Injectable() class FakeService { updateData(name: string) { @@ -472,9 +473,14 @@ describe('injectMutation', () => { }) class FakeComponent { mutation = injectMutation(() => { - const service = inject(FakeService) - return { - mutationFn: (name: string) => service.updateData(name), + try { + const service = inject(FakeService) + return { + mutationFn: (name: string) => service.updateData(name), + } + } catch (e) { + errorSpy(e) + throw e } }) } @@ -488,5 +494,6 @@ describe('injectMutation', () => { expect( await fixture.componentInstance.mutation.mutateAsync('test'), ).toEqual('test') + expect(errorSpy).not.toHaveBeenCalled() }) })