Reputation: 14969
I need to be able test my component (methods, computed properties, data, ...). However, when I import my vue component in my unit test:
import Pagination from 'src/components/shared/pagination.vue'
import { newComponent } from '../component-factory'
describe('pagination.vue', () => {
const propsData = {
metadata: {
page: 2,
records: 155,
total: 11,
},
perPage: 15,
}
it('should have correct number of records', () => {
const ctor = Vue.extend(Pagination)
const vm = new ctor({propsData}).$mount()
expect(vm.firstRecord).toBe(16)
expect(vm.lastRecord).toBe(30)
})
...
vm
is of type Vue
, and thus does not have the firstRecord
/lastRecord
properties. Running the test with karma shows a success, but the typescript compiler spits out Errors:
ERROR in ./tests/shared/pagination.spec.ts
(16,19): error TS2339: Property 'firstRecord' does not exist on type 'Vue'.
ERROR in ./tests/shared/pagination.spec.ts
(17,19): error TS2339: Property 'lastRecord' does not exist on type 'Vue'.
I tried casting:
...
const vm = new ctor({propsData}).$mount() as Pagination
...
But that results in a warning in VSCode:
[ts] Cannot find name 'Pagination'.
And has the effect of treating vm
as type any
which is totally counterproductive.
I think this all stems from the fact that when using .vue
files you have to add the declaration:
declare module '*.vue' {
import Vue from 'vue'
export default typeof Vue
}
Which clearly sets the type of all .vue
files to Vue
, which isn't exactly a lie, but isn't helpful either... Any suggestions? What am I doing wrong?
For future reference, I have attempted to use vuetype which generates .d.ts
files for each .vue
file, but ran into this issue. Also, there is a request to make .vue
a first class citizen in the typescript ecosystem, which would eliminate this problem. And, I just added a request for a vue language service extension
Upvotes: 1
Views: 2066
Reputation: 1067
Up until Vue 2.5, their TypeScript documentation page recommended exporting an interface that extends Vue
if you were not going to use vue-class-component. You can export this interface to use in your tests, to cast your component instance. The recommendation has been removed from the docs, but I have not been able to figure out how to change my tests to not need the interface.
It looks like vuetype could generate these interfaces for you, but I've just been creating them manually.
Here is a greatly simplified example, but you can define anything in your interface that you would reference on vm
, ie data, props, methods:
// NOTE: Make sure your interface extends `Vue`!
export interface PaginationComponent extends Vue {
firstRecord: number,
lastRecord: number
}
export default {
name: 'Pagination',
data: function() {
return {
firstRecord: 16,
lastRecord: 30,
}
}
}
For your test, you can cast the component instance to the type of your exported interface:
import Pagination, {PaginationComponent} from 'src/components/shared/pagination.vue'
describe('pagination', () => {
it('should know about component data fields', () => {
const ctor = Vue.extend(Pagination)
const vm : PaginationComponent = new ctor().$mount()
expect(vm.firstRecord).toBe(16)
expect(vm.lastRecord).toBe(30)
})
})
Upvotes: 1