TanStack / TanStack/query

`isSuccess()` not triggering `effect()` during testing

Open
#9,981 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

package: angular-query
Dominant language
TypeScript
Stars
50.3k
Forks
4.2k
Avg merge
18h 25m
Merged PRs (30d)
200

Description

Describe the bug

I have this AppComponent, with an effect() that's dependent on the isSuccess() of a query:

@Component({
	selector: 'app-root',
	templateUrl: './app.html',
	imports: [ReactiveFormsModule],
	styleUrl: './app.css',
	changeDetection: ChangeDetectionStrategy.OnPush,
})
export class App {
	dataService = inject(DataService);

	formField = new FormControl<number>(42);

	query = injectQuery(() => ({
		queryKey: ['query'],
		queryFn: () => {
			console.log('in query', this.dataService.give());
			return this.dataService.give();
		},
	}));

	constructor() {
		effect(() => {
			console.log('in effect:', this.query.isSuccess());
			if (!this.query.isSuccess()) return;

			console.log('setting form value');
			this.formField.setValue(9999);
		});
	}
}

And I'm trying to test this, either through the classic TestBed or new Vitest features combined with the Testing Library:

describe('App', () => {
	let dataServiceMock: Mocked<DataService>;

	beforeEach(() => {
		dataServiceMock = { give: vi.fn().mockReturnValue(Promise.resolve([30, 40, 50])) } as Mocked<DataService>;
	});

	it('should work using the testing library', async () => {
		let sut = await render(App, {
			providers: [provideQueryClient(new QueryClient()), { provide: DataService, useValue: dataServiceMock }],
		});

		await sut.rerender();
		sut.detectChanges();
		await sut.fixture.whenStable();
		await sut.rerender();
		sut.detectChanges();
		await sut.fixture.whenStable();
		await sut.rerender();
		sut.detectChanges();
		await sut.fixture.whenStable();
		await sut.rerender();
		sut.detectChanges();
		await sut.fixture.whenStable();
		await sut.rerender();
		TestBed.tick();
		TestBed.tick();
		TestBed.tick();
		sut.fixture.detectChanges();
		await sut.fixture.whenStable();
		sut.detectChanges();
		await sut.fixture.whenStable();
		await sut.rerender();
		await expect(page.getByRole('textbox')).toHaveValue(9999);
		expect(sut.fixture.componentInstance.formField.value).toBe(9999);
	});

	it('should work using TestBed', async () => {
		TestBed.configureTestingModule({
			imports: [App],
			providers: [provideQueryClient(new QueryClient()), { provide: DataService, useValue: dataServiceMock }],
		});
		let fixture = TestBed.createComponent(App);
		let sut = fixture.componentInstance;

		fixture.detectChanges();
		await fixture.whenStable();
		fixture.detectChanges();
		await fixture.whenStable();
		fixture.detectChanges();
		await fixture.whenStable();
		TestBed.tick();
		TestBed.tick();
		TestBed.tick();
		TestBed.tick();
		fixture.detectChanges();
		await fixture.whenStable();

		expect(sut.formField.value).toBe(9999);
	});
});

But isSuccess() in the effect() never becomes true even though I'm clearly returning data. I've logged the result of the DataService, it's returning a fulfilled promise as arranged.

The many tick()/detectChanges()/whenStable() are my desperate attempts at getting something to work btw.

This may have something to do with the issue of requiring Angular v19+ and relying on component effect schedule timing.

Your minimal, reproducible example

https://github.com/JPtenBerge/tanstack-query-query-effect-bug

Steps to reproduce
  1. Define a query using injectQuery() that on init calls some sort of a service for retrieving data
  2. In the constructor, creating an effect() that updates something like a component variable if isSuccess() of the above defined query.
  3. In a Vitest browser-based test, configure the testing module with a mock for the above mentioned data service.
  4. Assert whether the component variable or something similar has been updated.

Vitest config in angular.json:

"test": {
  "builder": "@angular/build:unit-test",
  "options": {
    "browsers": ["chromium"]
  }
}
Expected behavior

I expect the effect() to be called again and seeing isSuccess() of the query being true, but it's not called again.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform
  • OS: Windows 11
  • Browser: Chromium for testing
Tanstack Query adapter

angular-query

TanStack Query version

v5.90.16

TypeScript version

v5.9.2

Additional context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked minimal reproducible example, then inspect the App component's injectQuery() and effect() interaction under the TestBed and Vitest setups. Reproduce the failing assertion and trace Angular's effect scheduling around the fulfilled query; done means the effect observes isSuccess() as true and the form value becomes 9999 without repeated manual ticks.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
frontend, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.