Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(angular-query): consistent injector parameter #7201

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,6 +1,8 @@
import { Injector } from '@angular/core'
import { TestBed } from '@angular/core/testing'
import { QueryClient } from '@tanstack/query-core'
import { afterEach } from 'vitest'
// NOTE: do not import test from 'vitest' here - only global test function is patched for Angular zone
import { afterEach, describe, expect } from 'vitest'
import { injectInfiniteQuery } from '../inject-infinite-query'
import { provideAngularQuery } from '../providers'
import { expectSignals, infiniteFetcher } from './test-utils'
Expand Down Expand Up @@ -61,4 +63,33 @@ describe('injectInfiniteQuery', () => {
status: 'success',
})
})

describe('injection context', () => {
test('throws NG0203 outside injection context', () => {
expect(() => {
injectInfiniteQuery(() => ({
queryKey: ['injectionContextError'],
queryFn: infiniteFetcher,
initialPageParam: 0,
getNextPageParam: () => 12,
}))
}).toThrowError(
'NG0203: injectInfiniteQuery() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203',
)
})

test('can be used outside injection context when passing an injector', () => {
const query = injectInfiniteQuery(
() => ({
queryKey: ['manualInjector'],
queryFn: infiniteFetcher,
initialPageParam: 0,
getNextPageParam: () => 12,
}),
TestBed.inject(Injector),
)

expect(query.status()).toBe('pending')
})
})
})
@@ -1,5 +1,7 @@
import { Injector } from '@angular/core'
import { TestBed, fakeAsync, flush, tick } from '@angular/core/testing'
import { QueryClient } from '@tanstack/query-core'
// NOTE: do not import test from 'vitest' here - only global test function is patched for Angular zone
import { beforeEach, describe, expect } from 'vitest'
import { injectIsFetching } from '../inject-is-fetching'
import { injectQuery } from '../inject-query'
Expand Down Expand Up @@ -32,4 +34,20 @@ describe('injectIsFetching', () => {
flush()
expect(isFetching()).toStrictEqual(0)
}))

describe('injection context', () => {
test('throws NG0203 outside injection context', () => {
expect(() => {
injectIsFetching()
}).toThrowError(
'NG0203: injectIsFetching() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203',
)
})

test('can be used outside injection context when passing an injector', () => {
expect(
injectIsFetching(undefined, TestBed.inject(Injector)),
).not.toThrow()
})
})
})
@@ -1,5 +1,7 @@
import { Injector } from '@angular/core'
import { QueryClient } from '@tanstack/query-core'
import { beforeEach, describe } from 'vitest'
// NOTE: do not import test from 'vitest' here - only global test function is patched for Angular zone
import { beforeEach, describe, expect } from 'vitest'
import { TestBed, fakeAsync, tick } from '@angular/core/testing'
import { injectIsMutating } from '../inject-is-mutating'
import { injectMutation } from '../inject-mutation'
Expand Down Expand Up @@ -36,4 +38,20 @@ describe('injectIsMutating', () => {
expect(isMutating()).toBe(1)
})
}))

describe('injection context', () => {
test('throws NG0203 outside injection context', () => {
expect(() => {
injectIsMutating()
}).toThrowError(
'NG0203: injectIsMutating() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203',
)
})

test('can be used outside injection context when passing an injector', () => {
expect(
injectIsMutating(undefined, TestBed.inject(Injector)),
).not.toThrow()
})
})
})
@@ -1,7 +1,8 @@
import { Component, input, signal } from '@angular/core'
import { Component, Injector, input, signal } from '@angular/core'
import { QueryClient } from '@tanstack/query-core'
import { TestBed } from '@angular/core/testing'
import { describe, expect, test, vi } from 'vitest'
// NOTE: do not import test from 'vitest' here - only global test function is patched for Angular zone
import { describe, expect, vi } from 'vitest'
import { By } from '@angular/platform-browser'
import { JsonPipe } from '@angular/common'
import { injectMutation } from '../inject-mutation'
Expand Down Expand Up @@ -173,5 +174,21 @@ describe('injectMutationState', () => {

expect(spans).toEqual(['success', 'error'])
})

describe('injection context', () => {
test('throws NG0203 outside injection context', () => {
expect(() => {
injectMutationState()
}).toThrowError(
'NG0203: injectMutationState() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203',
)
})

test('can be used outside injection context when passing an injector', () => {
expect(
injectMutationState(undefined, TestBed.inject(Injector)),
).not.toThrow()
})
})
})
})
@@ -1,6 +1,7 @@
import { Component, input, signal } from '@angular/core'
import { Component, Injector, input, signal } from '@angular/core'
import { QueryClient } from '@tanstack/query-core'
import { TestBed } from '@angular/core/testing'
// NOTE: do not import test from 'vitest' here - only global test function is patched for Angular zone
import { describe, expect, vi } from 'vitest'
import { By } from '@angular/platform-browser'
import { injectMutation } from '../inject-mutation'
Expand Down Expand Up @@ -455,4 +456,29 @@ describe('injectMutation', () => {

await expect(() => mutateAsync()).rejects.toThrowError(err)
})

describe('injection context', () => {
test('throws NG0203 outside injection context', () => {
expect(() => {
injectMutation(() => ({
mutationKey: ['injectionContextError'],
mutationFn: () => Promise.resolve(),
}))
}).toThrowError(
'NG0203: injectMutation() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203',
)
})

test('can be used outside injection context when passing an injector', () => {
expect(() => {
injectMutation(
() => ({
mutationKey: ['injectionContextError'],
mutationFn: () => Promise.resolve(),
}),
TestBed.inject(Injector),
)
}).not.toThrow()
})
})
})
@@ -1,6 +1,7 @@
import { Component, computed, input, signal } from '@angular/core'
import { Component, Injector, computed, input, signal } from '@angular/core'
import { TestBed, fakeAsync, flush, tick } from '@angular/core/testing'
import { QueryClient } from '@tanstack/query-core'
// NOTE: do not import test from 'vitest' here - only global test function is patched for Angular zone
import { describe, expect, vi } from 'vitest'
import { injectQuery } from '../inject-query'
import { provideAngularQuery } from '../providers'
Expand Down Expand Up @@ -254,6 +255,31 @@ describe('injectQuery', () => {
}))
})

describe('injection context', () => {
test('throws NG0203 outside injection context', () => {
expect(() => {
injectQuery(() => ({
queryKey: ['injectionContextError'],
queryFn: simpleFetcher,
}))
}).toThrowError(
'NG0203: injectQuery() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`. Find more at https://angular.io/errors/NG0203',
)
})

test('can be used outside injection context when passing an injector', () => {
const query = injectQuery(
() => ({
queryKey: ['manualInjector'],
queryFn: simpleFetcher,
}),
TestBed.inject(Injector),
)

expect(query.status()).toBe('pending')
})
})

test('should set state to error when queryFn returns reject promise', fakeAsync(() => {
const query = TestBed.runInInjectionContext(() => {
return injectQuery(() => ({
Expand Down
12 changes: 4 additions & 8 deletions packages/angular-query-experimental/src/inject-mutation-state.ts
Expand Up @@ -43,22 +43,18 @@ function getResult<TResult = MutationState>(
)
}

export interface InjectMutationStateOptions {
injector?: Injector
}

export function injectMutationState<TResult = MutationState>(
mutationStateOptionsFn: () => MutationStateOptions<TResult> = () => ({}),
options?: InjectMutationStateOptions,
injector?: Injector,
): Signal<Array<TResult>> {
return assertInjector(injectMutationState, options?.injector, () => {
return assertInjector(injectMutationState, injector, () => {
const destroyRef = inject(DestroyRef)
const queryClient = injectQueryClient()
const ngZone = inject(NgZone)

const mutationCache = queryClient.getMutationCache()

return lazySignalInitializer((injector) => {
return lazySignalInitializer((lazyInitializerInjector) => {
const result = signal<Array<TResult>>(
getResult(mutationCache, mutationStateOptionsFn()),
)
Expand All @@ -72,7 +68,7 @@ export function injectMutationState<TResult = MutationState>(
result.set(getResult(mutationCache, mutationStateOptions))
})
},
{ injector },
{ injector: lazyInitializerInjector },
)

const unsubscribe = mutationCache.subscribe(
Expand Down