Description
Just highlighing a funny side effect of this library.
Context
I'm currently trying to make Vue + TypeScript + Jest work nice together in order to integrate it into Quasar framework (happy if you want to check the "upgrade guide" I put together and help with TODO stuff).
Funny discovery
While doing so, I came to the conclusion that currently the only way of getting component types into tests was to extract TS file into a separate file with the same name as the Vue one, then import both the .vue
(shimmed) and the .ts
(for typings) into the test file.
import QBtnDemo from './demo/QBtn-demo';
import QBtnDemoSfc from './demo/QBtn-demo.vue';
const wrapper = mount(QBtnDemoSfc as typeof QBtnDemo);
const vm = wrapper.vm;
This work pretty well, but it's kinda verbose.
At some point I had the random idea of directly mount the TS import just for fun and... It worked?! Structure-related tests passed, a couple of console.log
assured me that template was being rendered, even if the TS file actually didn't have any info about it.
To make it more explicit, this works with correct component typings.
import QBtnDemo from './demo/QBtn-demo';
const wrapper = mount(QBtnDemo);
const vm = wrapper.vm;
If someone else can try this and give feedback, both positive and negative, it would be a good idea.
Possible explanation
If you are like me, you probably are wondering where does this black magic come from.
Actually I'm not really sure myself, but this is the best I could come up, helped by Quasar staff who knows TS and Jest, if someone can confirm or correct the hypotesis, I'd be happy to update.
ts-jest
transpile at runtime .ts
files into .js
files (I can guess, with the same name of the TS ones).
At the same time, vue-jest
transpile at runtime .vue
files into .js
files with all info attached (TS, template, style), always with the same name.
Because they write a file with the same name, I guess vue-jest
is actually overwriting the TS-only transpilation with a full SFC implementation transpilation.
The import is done without the file extension, so we have import QBtnDemo from './demo/qbtn-demo';
for the TS file.
At compile/development time it will point to the TS file and give us correct typings for Jest to use upon mounting (and it extends Vue, so it won't complain), which is also compatible with ESLint and Vetur support.
At test time, instead, it will resolve to the Vue-transpiled JS file, which also contains info about the template and style of the component.
This comment can be useful to understand what's going on.
Requirements
- SFC should be transformed into a "Double File Component" (DFC?) composed of a
.vue
and.ts
file - Both files should be in the same folder
- You should use
vue-jest
to process Vue files - You should use
ts-jest
to process TS files
Pros
- You get full component typings with a neat syntax
- It works seamlessly with Vetur
Cons
- You must separate SFC in a DFC
- There is a problem with test coverage, especially when using Jest in watch mode: Jest requires
--no-cache
for proper coverage #56
Other attempts
Previous to this discovery, I was experimenting with wildcard ambient module declarations to obtain typings directly when importing .vue
files, but got some "domain collision" problems with the general Vue shim. If anyone can help on that issue, it's much appreciated.
Mostly because making that one work, although it needs some kind of automatic shim generation, is more future proof for when someone will find a way to make .vue
files work semlessly and the DFC hack can be dropped.