vitest-dev / vitest

Next generation testing framework powered by Vite.
https://vitest.dev
MIT License
13.05k stars 1.17k forks source link

@vue/compat does not work with vitest #1886

Closed Weetbix closed 2 years ago

Weetbix commented 2 years ago

Describe the bug

Reactivity does not seem to work when using the vue compat build.

For example all these tests will work with vue 3, but all will fail with @vue/compat:

import {ref, onMounted, defineComponent} from 'vue';
import {it, expect} from 'vitest';
import {mount} from '@vue/test-utils';

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

const TestAsync = defineComponent({
    template: '<div><div>{{ mountText }}</div><div>{{ asyncText }}</div></div>',

    props: {
        done: Function,
    },
    setup({ done }) {
        const mountText = ref();
        const asyncText = ref();

        onMounted(() => {
            mountText.value = 'mounted';
        });

        sleep(0).then(() => {
            asyncText.value = 'async';
            done?.();
        });

        return {
            mountText,
            asyncText,
        };
    },
});

it('should show onMount text', () => new Promise(done => {
    const wrapper = mount(TestAsync);
    wrapper.vm.$nextTick(() => {
        expect(wrapper.html()).toMatch('mounted')
        done();
    });
}));

it('should show async text', async () => {
    let renderedAsyncResolve;
    const renderedAsync = new Promise(resolve => renderedAsyncResolve = resolve);

    const wrapper = mount(TestAsync, {
        propsData: { done: renderedAsyncResolve }
    });

    await renderedAsync;
    expect(wrapper.html()).toMatch('async');
});

it('should show async text with nextTick', () => new Promise(async (done) => {
    let renderedAsyncResolve;
    const renderedAsync = new Promise(resolve => renderedAsyncResolve = resolve);

    const wrapper = mount(TestAsync, {
        propsData: { done: renderedAsyncResolve }
    });

    await renderedAsync;
    wrapper.vm.$nextTick(() => {
        expect(wrapper.html()).toMatch('async');
        done();
    });
}));

Expected behavior All tests should pass when running in compat mode. The templates/output should update to reflect the new values.

Other

I raised this is @vue/test-utils here: https://github.com/vuejs/test-utils/issues/1665

But these tests can be made to work in jest with the module name mapper: https://github.com/vuejs/test-utils/issues/1665#issuecomment-1211576808

I think this might be related to the dual package hazard issue raised here: https://github.com/vuejs/vue-test-utils/issues/1982#issuecomment-1201131222

Reproduction

Check out this repo on the jh/vue-utils-version branch: https://github.com/Weetbix/vue-compat-composition-api-bug-repo/tree/jh/vue-utils-version

Run yarn test:vue3 to run in vue 3 and notice all tests pass.

Run yarn test:vue-compat to run with the vue compat alias, notice all tests fail.

System Info

System:
    OS: macOS 12.5.1
    CPU: (8) arm64 Apple M1
    Memory: 81.72 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.13.2 - ~/.nvm/versions/node/v16.13.2/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v16.13.2/bin/yarn
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.2/bin/npm
  Browsers:
    Firefox: 97.0.1
    Safari: 15.6.1
  npmPackages:
    vitest: ^0.22.1 => 0.22.1 

**Related information:**
- `@vue/test-utils` version: `2.0.2`
- `Vue` version: `3.2.37`

Used Package Manager

yarn

Validations

Weetbix commented 2 years ago

I've tried to work work out if this is a dual package hazard / alias issue but I am not having much luck.

For example if I manually change the imports inside the node modules folder to the compat build, I get weird errors about import names and claims the module is CommonJS. I changed the import in my test file and in /node_modules/@vue/test-utils/dist/vue-test-utils.esm-bundler.mjs to @vue/compat/dist/vue.runtime.esm-bundler.js and I get:

SyntaxError: Named export 'BaseTransition' not found. The requested module '@vue/compat/dist/vue.runtime.esm-bundler.js' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@vue/compat/dist/vue.runtime.esm-bundler.js';
const { transformVNodeArgs, Transition, BaseTransition, defineComponent, h, TransitionGroup, Teleport, nextTick, setDevtoolsHook, shallowReactive, reactive, isRef, createApp, computed } = pkg;

Which is weird, because it should be an ES Module and it does export those names..

sheremet-va commented 2 years ago

@Weetbix testing-library should import vue from the same source you import it. Try adding vue test utils to deps.inline or enable deps.registerNodeLoader, otherwise test utils will import Vue using Node resolution algorithm without looking at alias.

Weetbix commented 2 years ago

Hi @sheremet-va

Indeed it works when inlined! Thank you!