I want to migrate jest unit tests from vue 2 to vue 3. But I'm stuck with mocking up computed props.
I got a lot of vue-2 unit tests written like this:
const wrapper = shallowMount(FooComponent, {
computed: {
myComputedProp: () => false // The intention is to return "false" during unit tests no matter what
}
});
That was working in vue 2 world, but seems has no effect after the migration to vue 3 and the compatible vue-test utils.
Some of the components atm on composition api, while the others yet on options api.
I'd prefer to not re-write all these unit tests, cause it's a migration, but find a way to mock computed props once again if that's possible.
Thanks
Related
I'm trying to write SSR-friendly code, keeping in mind a potential migration of my app from SPA to SSR. One of the principles of such code is to avoid statefull singletons which can cause cross request state pollution
The problem comes when I need to use an instance of Vuex, Vue-router, Vue-i18n etc. outside of Vue component. Because the solution in all the respective SO answers is... You guessed it. To create and export a statefull singleton in a separate js file and then import it all over the app:
Vue-router: https://stackoverflow.com/a/43562210/11208064
Vuex: https://stackoverflow.com/a/47575742/11208064
Vue-i18n: https://stackoverflow.com/a/66695008/11208064
A simple example
// store.js
export default new Vuex.Store() {} // this is a singleton
// someOtherModule.js
import { store } from './store.js'
Pinia has covered the issue in the docs. They recommend to access the pinia instance via app.$pinia. However they don't specify how do I access the app instance itself.
Also the problem is not limited to these libraries. We write our own modules which work in a similar manner.
Researching the issue I came across this article. It suggests to wipe module cache, so each time you require it all the code is executed again, making it fresh and stateless. Sounds pretty sophisticated, but maybe this is the way? And if not, what is the recommended solution?
I'm writing a new Vue project and want to test my components with vue-test-utils.
So far I've been writing unit-tests with a test case for each component method, testing its expected behavior while mocking other methods that it might call.
Recently I've read on the Vue docs that the unit tests for components should test general behavior and not rely on implemenation details:
https://vuejs.org/guide/scaling-up/testing.html#component-testing
which makes sense, but I still want to test the logic of my component's methods.
I don't want to extract it to different files / composables because they heavily rely on the component's data and other methods, and I don't wanna pass everything as parameters.
What do you recommend regarding this?
I can't mock methods anymore since setMethods is now deprecated in vue-test-utils, which is making it harder to test each method separately.
do you think I should give up on testing each method?
I find it helpful to test methods because usually small changes make those tests fail which help me notice errors in the code, but also makes it harder because every small legitimate change requires unit-test changes as well.
We have done unit test using vue-jest. Here are the steps.
Use the following code to set up the crypto property globally. This will allow Jest to access window.crypto and won't cause any issue.Create a crypto.mock file and paste following code.
const crypto = require('crypto')
Object.defineProperty(global.self, 'crypto', {
value: {
getRandomValues: arr => crypto.randomBytes(arr.length)
}
})
Now import this file in your test file component. Now You can use jasmine.Spy to spy on the elements.
let spyFor: jasmine.Spy; spyFor = spyOn(function.hello, 'hello'); expect(spyFor).toHaveBeenCalledTimes(1);
In this way you can mock on the methods. Pls free to ask if you have anything more.
I'm working on unit testing all of my components, and I've hit a bit of a snag (or maybe a misunderstanding of how to properly test).
I have a component that receives some parameters from the store, and then calls a series of functions that mostly return an input string with some transformations applied.
This looks something like the following:
<script setup lang="ts">
import { someTextTransform } from '../utilities/someTextTransform';
...
let parsedText = store.input;
if (store.applySomeTextTransform) {
parsedText = someTextTransform(parsedText);
}
I have already tested these functions themselves, so to me it seems like testing the actual output of the calls is unnecessary and I instead could just test to see if the functions have been called.
Here is a snippet on spying from the Vitest docs
Mocking functions can be split up into two different categories; spying & mocking.
Sometimes all you need is to validate whether or not a specific function has been called (and possibly which arguments were passed). In these cases a spy would be all we need which you can use directly with vi.spyOn().
This is exactly what I want. I want only to know whether or not the function has been called. The functions themselves are simple enough that they do not require additional setup (i.e., mocking is not required).
However looking through the docs of Vue Test Utils I don't see a way to do this. It looks like a more common way to do this is to mock the functions first and then you can spy on them more easily, but then I would have to create mocks that don't actually mock the functions which seems like I'm adding code to my codebase for no benefit other than a weird workaround.
I may just be missing something on how to do this, but I might also be approaching the testing in a suboptimal way so any advice is appreciated.
The Vue class component library uses the #Component decorator, and must thus be transpiled to work. Is there a way to use Vue class components without this decorator? Like, either a work-around or another similar library?
Use-case: Lower commitment for a legacy project, but still possible to analyze with tsc.
Transpiled environment is the expected scenario of use for Vue. It relies on custom .vue format and may lack some features without it, as well as the support of some third-party libraries because they rely on it.
The use of classes never was a good idea in Vue because it doesn't follow OOP paradigm. A class isn't instantiated directly but used as syntactic structure that is translated to Vue.component definition. Vue class components have inherent problems, one of which is poor support for TypeScript types. If Vue classes aren't already used in the project, there are reasons for them to not be the first choice.
In case there's a necessity to use Vue class components, this can be done in vanilla ES6 because decorators proposal is syntactic sugar, decorators are functions with specific signatures that are applied to classes and members and decorate them.
#foo
#bar()
class Baz {}
is the same as
let Baz = foo(bar()(class Baz {}))
Different decorator types are applied in different ways, also there are some differences between TypeScript and Babel legacy decorators.
#Component
class Foo extends Vue {
#Provide('bar') baz = 'bar'
}
is translated to
let Foo = class Foo extends Vue {
constructor() {
this.baz = 'bar'
}
}
Provide('bar')(Foo.prototype, 'baz')
Foo = Component(Foo);
With Vue 3 typescript is well supported, you could create your component as follows :
import { defineComponent } from 'vue'
export default defineComponent({
//the component options like data,props,computed...
})
For more details check the official docs
A running example to get started
As far as i understand there are two main ways to reuse options in different components.
Global registration of plugin or mixin making the desired options to be available all over application.
Vue.use(VuePlugin)
Or register them locally in every component where needed.
var Component = Vue.extend({ mixins: [VueMixin] })
Obviously the first method makes your code cleaner and easier to maintain. But which one is more efficient in terms of bundle size and overall application efficiency?