TestWindow is not a constructor in Stenciljs Unit test - stenciljs

Getting errors when I run unit test for the component
1) TestWindow is not a constructor
2) Cannot read property 'textContent' of undefined
Not able to understand how to proceed further. When I try to console element and testWindow, both are coming as undefined.
**tsx file**
import { Component } from '#stencil/core';
#Component({
tag: 'my-header',
styleUrl: 'my-header.css'
})
export class MyHeader {
render() {
return (
<div>
<p>Hello MyHeader!</p>
</div>
);
}
}
**Spec file**
import { TestWindow } from '#stencil/core/testing';
import { MyHeader } from './my-header';
describe('my-header', () => {
it('should build', () => {
expect(new MyHeader()).toBeTruthy();
});
describe('rendering', () => {
let element: HTMLMyHeaderElement;
let testWindow: TestWindow;
beforeEach(async () => {
testWindow = new TestWindow();
element = await testWindow.load({
components: [MyHeader],
html: '<my-header></my-header>'
});
});
console.log("element ",element);
console.log("testWindow ",testWindow);
it('should show content', () => {
expect(element.textContent).toEqual('');
});
});
});
package.json
"devDependencies": {
"#stencil/core": "~0.16.4",
"#stencil/sass": "^0.1.1",
"#types/jest": "23.3.11",
"#types/puppeteer": "1.6.4",
"jest": "^23.6.0",
"jest-cli": "23.6.0",
"puppeteer": "1.8.0",
"workbox-build": "3.4.1"
}
how can I get rid of those errors or I'm missing something to include.

The entire Stencil unit testing changed in latest versions.
TestWindow is now deprecated in favor of the combination of Jest and Puppeteer.
You should consult the documentation for further explanations about how to test your code: end to end testing in Stencil

Related

How to make unit test "location.href" by jest Vue.js

What I want to do
I wanna make test that is redirect by click.
if possible, I wanna make test not only method called assertion but redirect "URL" assertion.
Test Target Code
<p class="target" v-on:click="redirect">Click!</p>
<script>
export default {
methods: {
redirect() {
window.location.href = '/home'
},
}
}
Test Code
import { shallowMount } from '#vue/test-utils'
import redirectComponent from '../components/RedirectComponent.vue'
describe('Redirect component', () => {
const wrapper = shallowMount(redirectComponent)
it('Redirect By Click Test', () => {
wrapper.find('.target').trigger('click');
expect(window.location.href).toEqual('/home');
})
})
result
Expected: "/home"
Received: "http://localhost/"
How can I make redirect test?
window.location.href gives you the URL of the current page;
window.location.pathname will give you the path name of the current page, which I believe, is what you are looking for.
This is my Solution!
import { shallowMount } from '#vue/test-utils'
import redirectComponent from '../components/RedirectComponent.vue'
describe('Redirect component', () => {
const wrapper = shallowMount(redirectComponent)
Object.defineProperty(window, 'location', {
value: {
href: 'http://localhost',
},
configurable: true,
});
it('Redirect By Click Test', () => {
wrapper.find('.target').trigger('click');
expect(window.location.href).toEqual('/home');
})
})

Jest Unit test cant determine Vuetify components visibility

I have a Vue2 project with Vuetify, and i am using Jest for unit testing my code. I am starting out testing some sample code and i simple cannot get Jest to determine if a Vuetify v-alert component is visible or not. I have tried the built in Jest methods as well as adding Jest-dom and using the toBeVisible() method and nothing is working so far.
If you look at the Test.vue component, the v-alert component is hidden by default.(Its style is set to display: none;)
The unit test says expect(alert).not.toBeVisible() which should pass, but it always fails regardless of what the v-alert model is set to. If i change the test to expect(alert).toBeVisible() it passes regardless of the v-alert model is set to true/false.
If i change the test to be expect(alert).toHaveStyle({ display: 'none' }); it fails regardless of if i have the model set to true/false.
So as far as i can tell the Jest unit test CANNOT determine the visibility of the v-alert component at all. These same test work fine on the v-btn component just fine so why does the v-alert break? This is just my first unit test sample that ive been trying to get working for 2 days now. I have an entire application to write tests for and so far Jest is not working very well with Vuetify...any suggestions?
// Test.vue component
<template>
<div>
<v-btn ref="btn" depressed tile #click="showAlert">Show Alert</v-btn>
<v-alert
v-model="showError"
ref="error-msg"
type="error"
transition="scale-transition"
width="410"
tile
dense
dismissible
#input="clearError"
>
{{ errorText }}
</v-alert>
</div>
</template>
<script>
export default {
data() {
return {
showError: false,
errorText: ''
};
},
methods: {
showAlert() {
this.errorText = 'Test Error message';
this.showError = true;
},
clearError() {
this.errorText = '';
}
}
};
</script>
// Jest Unit test
// Libraries
import Vue from 'vue';
import Vuetify from 'vuetify';
// Components
import Test from '#/components/Login/Test.vue';
// Utilities
import { createLocalVue, shallowMount } from '#vue/test-utils';
// Import Jest Dom test utils.
import '#testing-library/jest-dom';
const localVue = createLocalVue();
Vue.use(Vuetify);
describe('Test Page', () => {
let vuetify;
beforeEach(() => {
vuetify = new Vuetify();
});
it('Check visibility of button', () => {
const wrapper = shallowMount(Test, {
localVue,
vuetify
});
const btn = wrapper.findComponent({ ref: 'btn' }).element;
expect(btn).toBeVisible();
});
it('Error Message hidden on page load', () => {
const wrapper = shallowMount(Test, {
localVue,
vuetify
});
const alert = wrapper.findComponent({ ref: 'error-msg' }).element;
expect(alert).not.toBeVisible();
});
});
// Package.json
"dependencies": {
"vue": "^2.6.11",
"vue-click-outside": "^1.1.0",
"vue-debounce": "^2.5.7",
"vue-router": "^3.3.4",
"vuetify": "^2.2.11",
"vuex": "^3.4.0"
},
"devDependencies": {
"#babel/plugin-transform-runtime": "^7.10.3",
"#babel/polyfill": "^7.10.1",
"#fortawesome/fontawesome-free": "^5.13.1",
"#testing-library/jest-dom": "^5.10.1",
"#vue/cli-plugin-babel": "^4.4.5",
"#vue/cli-plugin-e2e-nightwatch": "^4.4.5",
"#vue/cli-plugin-eslint": "^4.4.5",
"#vue/cli-plugin-unit-jest": "^4.4.5",
"#vue/cli-service": "^4.4.5",
"#vue/eslint-config-prettier": "^4.0.1",
"#vue/test-utils": "^1.0.3",
"babel-eslint": "^10.0.3",
"babel-jest": "^26.1.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.14.1",
"sass": "^1.26.9",
"sass-loader": "^8.0.2",
"vue-cli-plugin-vuetify": "^2.0.6",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.5.0"
}
I ran into a similar issue, so I decided to use exists from #vue/test-utils instead.
Docs for exists: https://vue-test-utils.vuejs.org/api/wrapper/#exists
I also decided to use v-if (instead of v-model) on the v-alert element to hide / show the component.
It looks like if v-if receives a value of false, the component/element in the document is replaced with <!---->, which is great for checking if your component/element is hidden or displayed.
See v-if test spec: https://github.com/vuejs/vue/blob/52719ccab8fccffbdf497b96d3731dc86f04c1ce/test/unit/features/directives/if.spec.js
SFC
Template:
<template>
<v-container>
<v-btn
#click='showError()'
ref="showErrorButton">
Show Error
</v-btn>
<v-alert
v-if="errorEncountered"
ref="errorAlert"
colored-border
type="error"
elevation="2"
>
Oops! Something went wrong!
</v-alert>
<v-container>
<template>
Javascript:
export default {
methods: {
showError() {
this.errorEncountered = true;
}
}
data() {
return {
errorEncountered: false,
};
},
};
Whenever errorEncountered is updated, the v-alert component will show/hide depending on whether the value is true/false.
Tests
describe('Component', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(Component, {
localVue,
vuetify,
});
});
describe('When component is mounted', () => {
it('Then the default value for errorEncountered should be false', () => {
expect(wrapper.vm.errorEncountered).toBeFalse();
});
it('Then the default state for the error alert should be hidden', async () => {
const errorAlert = wrapper.find({ ref: 'errorAlert' });
expect(errorAlert.exists()).toBeFalse();
});
describe('When an error is encountered', () => {
it('Then errorEncountered should be set to true', async () => {
const showErrorButton = wrapper.find({ ref: 'showErrorButton' });
showErrorButton.trigger('click');
await Vue.nextTick();
expect(wrapper.vm.errorEncountered).toBeTrue();
});
it('Then error alert should be visible', async () => {
const showErrorButton = wrapper.find({ ref: 'showErrorButton' });
showErrorButton.trigger('click');
await Vue.nextTick();
const errorAlert = wrapper.find({ ref: 'errorAlert' });
expect(errorAlert.exists()).toBeTrue();
});
});
});

Unable to test a lodash debounced vue method

I've been trying to test a confirmation button using jest and vue-test-utils. I'm using a debounced method to handle accidental double-clicking.
I've tried using jest.useFakeTimers() and jest.runOnlyPendingTimers(), but I'm still not seeing my button text changing in my tests. I've created an isolated test file below - any advice on what I'm doing wrong here would be greatly appreciated!
import { shallowMount, createLocalVue } from '#vue/test-utils'
import _ from 'lodash'
jest.useFakeTimers()
const myComponent = {
data(){
return {
confirming: false
}
},
computed: {
state(){
return this.confirming ? 'are you sure?' : 'default'
}
},
template: `<div #click="changeState">{{ state }}</div>`,
methods: {
changeState(){
this.doConfirm()
},
doConfirm: _.debounce(function(){
if(!this.confirming){
this.confirming = true
}else{
this.confirming = false
}
}, 500)
}
}
describe('Testing debounce methods', () => {
let $wrapper
beforeEach(() => {
$wrapper = shallowMount(myComponent)
})
test('Check default state', () => {
expect($wrapper.text()).toContain('default')
})
test('Check state changes with click', () => {
$wrapper.trigger('click')
jest.runOnlyPendingTimers()
expect($wrapper.text()).toContain('are you sure?')
})
})

Jest Unit Test: wrapper.vm.$refs.editForm.validate is not a function

When I write test case for form submit, i m getting issue with 1wrapper.vm.$refs.editForm.validate is not a function
I am unable to figure out the problem.. please Help me.
"#vue/cli-plugin-babel": "^3.11.0", "#vue/cli-plugin-eslint": "^3.11.0", "#vue/cli-plugin-pwa": "^3.11.0", "#vue/cli-plugin-unit-jest": "^3.11.0", "#vue/cli-service": "^3.11.0", "#vue/eslint-config-prettier": "^5.0.0", "#vue/test-utils": "^1.0.0-beta.29", "babel-core": "^7.0.0-bridge.0", "babel-eslint": "^10.0.1", "babel-jest": "^23.6.0"
==== EditProperty.vue======
<v-form ref="editForm" lazy-validation>
<v-flex>
<v-text-field label="Label Text" v-model="labelName" :rules="[v => !!v || 'Label Text is required']"
/>
</v-flex>
</v-form>
<script>
export default {
data() {
return {
labelName: ''
}
},
methods: {
save() {
if (this.$refs.editForm.validate()) {
this.$emit('updateLable', this.labelName)
}
}
}
}
</script>
======EditProperty.spec.js =====
import { shallowMount, createLocalVue } from '#vue/test-utils'
import EditProperty from '#/components/EditProperty.vue'
import Vuetify from 'vuetify'
const localVue = createLocalVue()
localVue.use(Vuetify)
let wrapper
describe('EditProperty.vue', () => {
beforeEach(() => {
wrapper = shallowMount(EditProperty, {
localVue,
data() {
return {
labelName: 'Username'
}
}
})
})
it('should save called correctly', () => {
wrapper.vm.save()
})
})
expected => test should be pass
getting => wrapper.vm.$refs.editForm.validate is not a function
When I write test case for form submit, i m getting issue with 1wrapper.vm.$refs.editForm.validate is not a function
I am unable to figure out the problem.. please Help me.
shallowMount does not render the child components. I.E. in your case, v-form won't be rendered in the test. In fact if you call html from your wrapper, you will see a HTML comment in place of the <edit-form>.
The rationale behind that vue test utils feature is that, when you're unit testing a component, you test only the logic of such component in isolation, and don't rely on code from other modules.
Now you could manually pass an object as stub and provide any test double to allow the validate() call, via the stubs option:
import { shallowMount, createLocalVue } from '#vue/test-utils'
import EditProperty from '#/components/EditProperty.vue'
import Vuetify from 'vuetify'
const localVue = createLocalVue()
localVue.use(Vuetify)
let wrapper
describe('EditProperty.vue', () => {
beforeEach(() => {
const EditFormStub = {
render: () => {},
methods: {
validate: () => true,
}
};
wrapper = shallowMount(EditProperty, {
localVue,
stubs: {
'edit-form': EditFormStub,
}
data() {
return {
labelName: 'Username'
}
}
})
})
it('should save called correctly', () => {
wrapper.vm.save()
})
})
So we are passing a fake editForm as a stub, with a fake validate() method which always returns true.
Then you can test your component code. For instance, you could test that your label is emitted as updateLabel (in your original snippet it was 'updateLable', be wary):
it('should save called correctly', () => {
wrapper.vm.save();
expect(wrapper.emitted('updateLabel')[0][0]).toBe(whatever the label should be)
})
if you got in a situation where you don't need to stub. You could easily do this:
import { nextTick } from 'vue'
it('test', async () => {
wrapper.vm.$refs.editForm.validate = jest.fn()
await nextTick()
})

Quasar Unknown custom element error in unit test

I have a simple Vue component that uses Quasar button
<template>
<div>
<span class="count">{{ count }}</span>
<q-btn #click="increment">Increment</q-btn>
</div>
</template>
<script>
export default {
name: 'TestComponent',
data() {
return {
count: 0,
};
},
methods: {
increment() {
this.count += 1;
},
},
};
</script>
I create a unit test for it
import { mount, createLocalVue } from '#vue/test-utils';
import { Quasar, QBtn } from 'quasar';
import TestComponent from '../TestComponent';
describe('TestComponent', () => {
let wrapper;
beforeEach(() => {
const localVue = createLocalVue();
localVue.use(Quasar, { components: { QBtn } });
wrapper = mount(TestComponent, { localVue });
});
it('renders the correct markup', () => {
expect(wrapper.html()).toContain('<span class="count">0</span>');
});
// it's also easy to check for the existence of elements
it('has a button', () => {
expect(wrapper.contains('button')).toBe(true);
});
});
My problem:
If I run the test cases (it function) one by one at a time the test will pass. For example, remove the second it('has a button'...) then run the test. It'll pass. It's the same when removing the first it('renders the correct markup'...)
However, If I keep all test cases then run the test. The second test case will fail with an error
console.error node_modules/vue/dist/vue.common.dev.js:630
[Vue warn]: Unknown custom element: <q-btn> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <TestComponent>
<Root>
What am I doing wrong?
Try removing the before-each. I saw this problem too. Can't remember what exactly fixed it but this is how I have my describe block.
describe('Mount Quasar', () => {
const localVue = createLocalVue()
localVue.use(Quasar, { components })
const wrapper = shallowMount(Register, {
localVue,
stubs: ['router-link', 'router-view']
})
const vm = wrapper.vm
it('passes the sanity check and creates a wrapper', () => {
expect(wrapper.isVueInstance()).toBe(true)
})
})
You will need to import quasar into either webpack, babel, or jest.
In the jest.config.js file
Add
moduleNameMapper: {
quasar: "quasar-framework/dist/umd/quasar.mat.umd.min.js"
},