Description
Hi, thank you for the great work!
I have some functions (wrappers for Jest mount()
helper) which expect a Vue
parameter to provide autocomplete for the vm
.
Until ac3581b, autocomplete didn't worked but at least it didn't fire off any error because the component inerithed from VueConstructor<never>
and was recognized as a Vue
instance.
Now I get an error because a lot of Vue
properties are missing from VueProxy
(rightfully).
I tryed to find a way to make the function work both with Vue
and VueProxy
(because as a matter of fact I don't really need all the stuff on Vue
type, VueProxy
should be enough), but it seems there is no VueClass
equivalent which manages VueProxy
.
Also, VueProxy
itself is not exported and, even if it was, I would have to manually specify PropsOptions
and RawBindings
instead of having them inferred from the component.
Any hint on how to proceed?
For the time being I just reverted VueConstructorProxy
typings in my local setup, but I'd like to solve the problem and make everything work properly.
This issue is related to my previous comment here and have the same root cause.
Official mount()
and shallowMount()
testing helpers don't have autocomplete because of the VueProxy
usage.
Maybe an helper can be provided which converts back from VueProxy
to a Vue
instance?
Bonus: if there is some way to extract props typings from VueProxy
, I'm interested in that as well.
My factory generator functions
import VueCompositionApi from '@vue/composition-api';
import { createLocalVue, shallowMount, VueClass } from '@vue/test-utils';
import { Cookies, Quasar, QuasarPluginOptionsExt } from 'quasar';
import Vue from 'vue';
const mockSsrContext = () => {
return {
req: {
headers: {},
},
res: {
setHeader: () => undefined,
},
};
};
export const mountQuasar = <V extends Vue>(
component: VueClass<V>,
options: {
quasar?: Partial<QuasarPluginOptionsExt>;
ssr?: boolean;
cookies?: any;
plugins?: any;
propsData?: any;
} = {},
) => {
const localVue = createLocalVue();
const app = {};
localVue.use(Quasar, options.quasar);
localVue.use(VueCompositionApi);
if (options) {
const ssrContext = options.ssr ? mockSsrContext() : null;
if (options.cookies) {
const cookieStorage = ssrContext ? Cookies.parseSSR(ssrContext) : Cookies;
const cookies = options.cookies;
Object.keys(cookies).forEach(key => {
cookieStorage.set(key, cookies[key]);
});
}
if (options.plugins) {
options.plugins.forEach((plugin: any) => {
plugin({
app,
Vue: localVue,
ssrContext,
});
});
}
}
// mock vue-i18n
const $t = () => {};
const $tc = () => {};
const $n = () => {};
const $d = () => {};
// Works both with Vue file and TS file because of some underlying black magic
// See https://github.com/vuejs/vue-jest/issues/188
return shallowMount(component, {
propsData: options.propsData,
localVue,
mocks: { $t, $tc, $n, $d },
// Injections for Components with a QPage root Element
provide: {
pageContainer: true,
layout: {
header: {},
right: {},
footer: {},
left: {},
},
},
});
};
export function mountFactory<V extends Vue>(
component: VueClass<V>,
options: {
quasar?: Partial<QuasarPluginOptionsExt>;
ssr?: boolean;
cookies?: any;
plugins?: any;
} = {},
) {
// TODO: add prop typings based on component
return (propsData?: any) => mountQuasar(component, { ...options, propsData });
}
Usage
import { QBtn, QIcon, QItem, QItemSection, QList } from 'quasar';
import { mountFactory } from 'test/jest/utils';
import MyComponent from './my-component';
const factory = mountFactory(MyComponent, { // Throws error because MyComponent is not of type Vue
quasar: {
components: {
QBtn,
QItemSection,
QItem,
QIcon,
QList,
},
},
});
describe('MyComponent', () => {
it('is a Vue instance', () => {
const wrapper = factory({ propName: 'propValue' });
console.log(wrapper.vm.propName); // Even with previous typings, autocomplete for this wouldn't have worked
expect(wrapper.isVueInstance()).toBeTruthy();
});
});