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

Computed Properties Not Updating in Tests When Using mountSuspended #1115

Open
OziOcb opened this issue Feb 5, 2025 · 5 comments
Open

Computed Properties Not Updating in Tests When Using mountSuspended #1115

OziOcb opened this issue Feb 5, 2025 · 5 comments

Comments

@OziOcb
Copy link

OziOcb commented Feb 5, 2025

Environment


  • Operating System: Linux
  • Node Version: v18.20.3
  • Nuxt Version: 3.15.4
  • CLI Version: 3.21.1
  • Nitro Version: 2.10.4
  • Package Manager: [email protected]
  • Builder: -
  • User Config: compatibilityDate, devtools
  • Runtime Modules: -
  • Build Modules: -

Reproduction

Minimal Reproduction - https://stackblitz.com/edit/github-remjha3q?file=app.vue

  • Open app.vue and app.spec.ts files
  • Open a new Terminal and run npm run rest

Describe the bug

When testing a Vue component using mountSuspended from @nuxt/test-utils/runtime, computed properties fail to update reactively when their dependencies change. The same test cases pass when using @vue/test-utils' mount or shallowMount methods.

Current Behavior:

  • Data property foo updates correctly
  • Computed property bar remains stale with its initial value
  • Computed property baz remains stale with its initial value

Expected Behavior:

  • When foo changes to true:
    • foo property should update
    • bar should update to "(bar = true)"
    • baz should update to "baz => (bar = true)"

Workaround:

Using standard @vue/test-utils mounting methods works as expected:

// These alternatives work correctly
return shallowMount(App, {});
// or
return mount(App, {});

Files

package.json

{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare",
    "test": "vitest"
  },
  "dependencies": {
    "nuxt": "^3.15.4",
    "vue": "latest",
    "vue-router": "latest"
  },
  "devDependencies": {
    "@nuxt/test-utils": "^3.15.4",
    "@vue/test-utils": "^2.4.6",
    "happy-dom": "^16.6.0",
    "jsdom": "^26.0.0",
    "vitest": "^3.0.5"
  }
}

vitest.config.ts

import { defineVitestConfig } from '@nuxt/test-utils/config';

export default defineVitestConfig({
  test: {
    environment: 'nuxt',
    environmentOptions: {
      nuxt: {
        domEnvironment: 'jsdom', // 'happy-dom' (default) or 'jsdom'
      },
    },
    globals: true,
  },
});

app.vue

<template>
  <div>{{ baz }}</div>
</template>

<script lang="ts">
export default defineNuxtComponent({
  name: 'UnitTestsMountSuspendedComputedValuesBug',

  data() {
    return {
      foo: false,
    };
  },

  computed: {
    bar() {
      return this.foo ? '(bar = true)' : '(bar = false)';
    },

    baz() {
      return 'baz => ' + this.bar;
    },
  },
});
</script>

app.spec.ts

import { describe, beforeEach, it, expect } from 'vitest';
import { mountSuspended } from '@nuxt/test-utils/runtime';
import { shallowMount, mount } from '@vue/test-utils';
import App from './app.vue';
import { VueWrapper } from '@vue/test-utils';

let wrapper: VueWrapper<InstanceType<typeof App>>;
const mountComponent = async () => {
  // return shallowMount(App, { // this works as expected
  // return mount(App, { // this works as expected
  return await mountSuspended(App, { // this doesn't work as expected!
    // data() { // pre-setting data while using moutSuspended doesn't work as well! (it works fine with other methods though)
    //   return {
    //     foo: true,
    //   };
    // },
  });
};

describe('AppMountSuspendedComputedValuesBug', () => {
  beforeEach(async () => {
    wrapper = await mountComponent();
  });

  // Toggling foo (data property) works as expected
  describe('foo', () => {
    it('should equal false by default', () => {
      expect(wrapper.vm.foo).toBe(false);
    });

    it('should equal true if changed using wrapper.vm.foo = true', async () => {
      wrapper.vm.foo = true;
      await wrapper.vm.$nextTick();
      expect(wrapper.vm.foo).toBe(true);
    });
  });

  // bar (coumputed value) doesn't update when foo (data property) changes
  describe('bar', () => {
    it('should return "(bar = false)" by default', () => {
      expect(wrapper.vm.bar).toBe('(bar = false)');
    });

    it('should return "(bar = true)" if this.foo === true', async () => {
      wrapper.vm.foo = true;
      await wrapper.vm.$nextTick();
      expect(wrapper.vm.bar).toBe('(bar = true)');
    });
  });

  // Obviously, baz (computed value) won't update becasue bar (computed value) doesn't update
  describe('baz', () => {
    it('should return "baz => (bar = false)" by default', () => {
      expect(wrapper.vm.baz).toBe('baz => (bar = false)');
    });

    it('should return "baz => (bar = true)" if this.foo === true', async () => {
      wrapper.vm.foo = true;
      await wrapper.vm.$nextTick();
      expect(wrapper.vm.baz).toBe('baz => (bar = true)');
    });
  });
});

Additional context

Pre-setting initial data values through the mount options also doesn't work with mountSuspended, while it works fine with other mounting methods.

Logs

RERUN  app.spec.ts x1 

 ❯ app.spec.ts (6 tests | 2 failed) 234ms
   ✓ AppMountSuspendedComputedValuesBug > foo > should equal false by default
   ✓ AppMountSuspendedComputedValuesBug > foo > should equal true if changed using wrapper.vm.foo = true
   ✓ AppMountSuspendedComputedValuesBug > bar > should return "(bar = false)" by default
   × AppMountSuspendedComputedValuesBug > bar > should return "(bar = true)" if this.foo === true 44ms
     → expected '(bar = false)' to be '(bar = true)' // Object.is equality
   ✓ AppMountSuspendedComputedValuesBug > baz > should return "baz => (bar = false)" by default
   × AppMountSuspendedComputedValuesBug > baz > should return "baz => (bar = true)" if this.foo === true 36ms
     → expected 'baz => (bar = false)' to be 'baz => (bar = true)' // Object.is equality

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  app.spec.ts > AppMountSuspendedComputedValuesBug > bar > should return "(bar = true)" if this.foo === true
AssertionError: expected '(bar = false)' to be '(bar = true)' // Object.is equality

Expected: "(bar = true)"
Received: "(bar = false)"eval app.spec.ts:48:30
     46|       wrapper.vm.foo = true;
     47|       await wrapper.vm.$nextTick();
     48|       expect(wrapper.vm.bar).toBe('(bar = true)');
       |                              ^
     49|     });
     50|   });

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯

 FAIL  app.spec.ts > AppMountSuspendedComputedValuesBug > baz > should return "baz => (bar = true)" if this.foo === true
AssertionError: expected 'baz => (bar = false)' to be 'baz => (bar = true)' // Object.is equality

Expected: "baz => (bar = true)"
Received: "baz => (bar = false)"eval app.spec.ts:61:30
     59|       wrapper.vm.foo = true;
     60|       await wrapper.vm.$nextTick();
     61|       expect(wrapper.vm.baz).toBe('baz => (bar = true)');
       |                              ^
     62|     });
     63|   });

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/2]⎯


 Test Files  1 failed (1)
      Tests  2 failed | 4 passed (6)
   Start at  16:28:03
   Duration  730ms

 FAIL  Tests failed. Watching for file changes...
       press h to show help, press q to quit
Copy link

stackblitz bot commented Feb 5, 2025

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

@OziOcb
Copy link
Author

OziOcb commented Feb 5, 2025

Apologies, but after reflecting on it, I think it's best to report this here - https://github.com/nuxt/test-utils/issues.

Right?

@huang-julien huang-julien transferred this issue from nuxt/nuxt Feb 5, 2025
@Reiss-Cashmore
Copy link

+1

@LukaszLuminski
Copy link

I have the same problem.

@timhere
Copy link

timhere commented Feb 7, 2025

I have the same problem too, I can't test the behaviour of computed properties using mountSuspended, plus also passing any initial data properties aren't respected in tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants