vitest-dev / vitest-dev/vitest

[Browser] Inexplicable flakiness with spies and mocks in CI

Open
#8,339 12 comments 11 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

pending triage
Dominant language
TypeScript
Stars
17.1k
Forks
2k
Avg merge
1d 22h
Merged PRs (30d)
94

Description

Describe the bug

Could maybe be related to #7871 .

We are beginning to see a lot of flakiness in our test suite. Particularly with two types of issues and I am wondering if we are doing something fundamentally wrong. Here are the two cases.

First case

We sometimes get TypeError: [Function ...] is not a spy or a call to a spy! when they are properly set as spies.

This is one of the test file that failed with this :

  TypeError: [Function createBaseStore] is not a spy or a call to a spy!
  
  Failure screenshot:
    - src/components/commerce/atomic-commerce-recommendation-interface/__screenshots__/store.spec.ts/-createCommerceRecommendationStore-should-call--createBaseStore-with-the-correct-arguments-1.png
  
   ❯ src/components/commerce/atomic-commerce-recommendation-interface/store.spec.ts:23:28
       21|   it('should call #createBaseStore with the correct arguments', () => {
       22|     expect(store).toBeDefined();
       23|     expect(createBaseStore).toHaveBeenCalledExactlyOnceWith({
         |                            ^
       24|       loadingFlags: [],
       25|       iconAssetsPath: '',

This is the specific test file : https://github.com/coveo/ui-kit/blob/master/packages/atomic/src/components/commerce/atomic-commerce-recommendation-interface/store.spec.ts

Are we doing something wrong with this test or is there a problematic race condition somewhere ?

Second case

We sometimes get vi.mocked(...).mockReturnValue is not a function.

This error often gets triggered for the whole suite as if the test is ran before the global mocks.

× atomic-commerce-load-more-products > when interface element type is 'product-listing' > should call #buildProductListing with engine 264ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when interface element type is 'product-listing' > should initialize pagination controller from product listing 244ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when interface element type is 'search' > should call #buildSearch with engine 191ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when interface element type is 'search' > should initialize pagination controller from search 182ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > should render nothing when the app is not loaded 278ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > should render nothing when there are no products 117ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > should render the container 190ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > should render a localized summary with formatted numbers 168ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > should render a progress bar with the correct width 214ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > should not render a load more button when all products are loaded 182ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > should render a load more button with the correct localized label when more products are available 298ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > when the load more button is clicked > should call #fetchMoreProducts 165ms
       → vi.mocked(...).mockReturnValue is not a function
     × atomic-commerce-load-more-products > when the app is loaded and there are products > when the load more button is clicked > should call #focusOnNextNewResult 362ms
       → vi.mocked(...).mockReturnValue is not a function

This is an example of one test that failed

  TypeError: vi.mocked(...).mockReturnValue is not a function
  
  Failure screenshots:
    - src/components/commerce/atomic-commerce-load-more-products/__screenshots__/atomic-commerce-load-more-products.spec.ts/atomic-commerce-load-more-products-when-interface-element-type-is--product-listing--should-call--buildProductListing-with-engine-1.png
    - src/components/commerce/atomic-commerce-load-more-products/__screenshots__/atomic-commerce-load-more-products.spec.ts/atomic-commerce-load-more-products-when-interface-element-type-is--product-listing--should-initialize-pagination-controller-from-product-listing-1.png
  
   ❯ renderLoadMoreProducts src/components/commerce/atomic-commerce-load-more-products/atomic-commerce-load-more-products.spec.ts:53:37
       51| 
       52|     if (interfaceType === 'product-listing') {
       53|       vi.mocked(buildProductListing).mockReturnValue(
         |                                     ^
       54|         buildFakeProductListing({
       55|           state: {

Again this is the test file : https://github.com/coveo/ui-kit/blob/master/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/atomic-commerce-load-more-products.spec.ts

Are we doing something wrong here again ?

Thank you !

Reproduction

I don't have a proper reproduction case since this seem to be random and flaky but here is our config.

https://github.com/coveo/ui-kit/blob/master/packages/atomic/vitest.config.ts

System Info
System:
    OS: macOS 15.5
    CPU: (12) arm64 Apple M3 Pro
    Memory: 297.77 MB / 36.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.14.0 - ~/.nvm/versions/node/v22.14.0/bin/node
    npm: 11.4.2 - ~/.nvm/versions/node/v22.14.0/bin/npm
  Browsers:
    Chrome: 138.0.7204.159
    Chrome Canary: 140.0.7314.0
    Safari: 18.5
  npmPackages:
    @vitest/browser: 3.2.4 => 3.2.4
    playwright: 1.54.1 => 1.54.1
    vitest: 3.2.4 => 3.2.4
Used Package Manager

npm

Validations

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 packages/atomic/vitest.config.ts and the two named test files: store.spec.ts and atomic-commerce-load-more-products.spec.ts. Run the affected browser tests repeatedly, comparing the spy and mock setup with the reported failures. Done means the intermittent errors no longer occur and the affected assertions pass reliably in CI.

Written by the indexing model from the issue text.

Assessment

Tech stack
playwright, typescript
Domain
testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.