Skip to content

Instantly share code, notes, and snippets.

@kleinjm
Created January 18, 2018 20:16
Show Gist options
  • Save kleinjm/47d83f5de4ff39d779b26c96f3d004f6 to your computer and use it in GitHub Desktop.
Save kleinjm/47d83f5de4ff39d779b26c96f3d004f6 to your computer and use it in GitHub Desktop.
Test components and examples for VueJS L&L
import { mount, shallow, createLocalVue } from 'vue-test-utils';
import VueRouter from 'vue-router';
import { BASE_TRANSLATE } from '~src/store/constants';
import Vuelidate from 'vuelidate';
import createStore from '~src/store';
const VUE_UTIL_METHODS = { shallow, mount };
// Setup an isolated component wrapper with all our Vue bells and whistles
function buildDoxVue({ method, component, options = {} }) {
const store = createStore();
const localVue = createLocalVue();
component.apollo = undefined;
localVue.use(Vuelidate);
if (options.router) {
localVue.use(VueRouter);
}
localVue.prototype.$translate = store.getters[BASE_TRANSLATE];
return VUE_UTIL_METHODS[method](component, {
localVue,
store,
...options,
});
}
export function mountDoxVue(component, options) {
return buildDoxVue({ method: 'mount', component, options });
}
export function shallowDoxVue(component, options) {
return buildDoxVue({ method: 'shallow', component, options });
}
import { shallow } from 'vue-test-utils';
import MyComponent from '~src/packages/profiles/components/MyComponent1.vue';
describe('MyComponent', () => {
describe('rendering items', () => {
it('renders all items in the list', () => {
const wrapper = shallow(MyComponent, {
propsData: {
users: [
{ id: 1, name: 'First' },
{ id: 2, name: 'Second' },
{ id: 3, name: 'Third' },
],
},
});
expect(wrapper.text()).to.include('First');
expect(wrapper.text()).to.include('Second');
expect(wrapper.text()).to.include('Third');
});
});
});
<template>
<ul>
<li v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
</template>
<script>
export default {
name: 'MyComponent',
props: {
users: Array,
},
}
</script>
import { shallow } from 'vue-test-utils';
import MyComponent from '~src/packages/profiles/components/MyComponent2.vue';
describe('MyComponent', () => {
const users = Object.freeze([
{ id: 1, name: 'First' },
{ id: 2, name: 'Second' },
{ id: 3, name: 'Third' },
]);
describe('rendering items', () => {
it('renders all items in the list', () => {
const wrapper = shallow(MyComponent, {
propsData: {
users,
profile: { admin: true },
},
});
expect(wrapper.findAll('[data-test-user-item]').length).to.eq(3);
});
it('does not render for non-admins', () => {
const wrapper = shallow(MyComponent, { propsData: { users } });
// Empty wrappers render an empty comment <!---->
// The isEmpty method comes from vue-test-utils
expect(wrapper.isEmpty()).to.be.true;
});
});
});
<template>
<ul v-if="isAdmin">
<li v-for="user in users"
:key="user.id"
data-test-user-item
>
{{ user.name }}
</li>
</ul>
</template>
<script>
import _get from 'lodash/get';
export default {
name: 'MyComponent',
props: {
users: Array,
profile: Object,
},
computed: {
isAdmin() {
return _get(this.profile, 'admin', false);
},
},
}
</script>
import { mount } from 'vue-test-utils';
import MyComponent from '~src/packages/profiles/components/MyComponent3.vue';
describe('MyComponent', () => {
const users = Object.freeze([
{ id: 1, name: 'First' },
{ id: 2, name: 'Second' },
{ id: 3, name: 'Third' },
]);
describe('rendering items', () => {
it('renders all items in the list', () => {
const wrapper = mount(MyComponent, {
propsData: {
users,
profile: { admin: true },
},
});
expect(wrapper.findAll('[data-test-user-item]').length).to.eq(3);
});
});
});
<template>
<ul v-if="isAdmin">
<MyListItem v-for="user in users"
:key="user.id"
:user="user"
>
</MyListItem>
</ul>
</template>
<script>
import _get from 'lodash/get';
import MyListItem from './MyListItem.vue';
export default {
name: 'MyComponent',
components: { MyListItem },
props: {
users: Array,
profile: Object,
},
computed: {
isAdmin() {
return _get(this.profile, 'admin', false);
},
},
}
</script>
import { mountDoxVue } from '~test/util/doxVue';
import MyComponent from '~src/packages/profiles/components/MyComponent4.vue';
describe('MyComponent', () => {
const users = Object.freeze([
{ id: 1, name: 'First' },
{ id: 2, name: 'Second' },
{ id: 3, name: 'Third' },
]);
describe('rendering items', () => {
it('renders all items in the list', () => {
const wrapper = mountDoxVue(MyComponent, {
data: {
users,
},
});
expect(wrapper.findAll('[data-test-user-item]').length).to.eq(3);
});
});
describe('toggleVueProfiles', () => {
it('displays the flash on success', async () => {
const performToggleFeatureMutation = sinon
.stub()
.resolves({ success: true });
const wrapper = mountDoxVue(MyComponent, {
methods: { performToggleFeatureMutation },
});
wrapper.find('[data-test-vue-profiles-btn]').trigger('click');
await wrapper.vm.$nextTick();
expect(performToggleFeatureMutation.called).to.be.true;
expect(wrapper.html()).to.include('data-test-flash-message');
});
});
});
<template>
<div>
<div class="flash"
v-if="updatedSuccessfully"
data-test-flash-message
>
Vue profiles have been successfully turned on for all users
</div>
<ul>
<MyListItem v-for="user in users"
:key="user.id"
:user="user"
>
</MyListItem>
</ul>
<button @click="toggleVueProfiles"
data-test-vue-profiles-btn
>
Toggle Vue Profiles
</button>
</div>
</template>
<script>
import MyListItem from './MyListItem.vue';
import gql from 'graphql-tag';
import toggleFeatureMutation from './toggleFeatureMutation';
import invariant from '~src/lib/invariant';
export default {
name: 'MyComponent',
components: { MyListItem },
data() {
return {
users: [],
updatedSuccessfully: false,
};
},
computed: {
userIds() {
return _map(this.users, 'id');
},
},
methods: {
performToggleFeatureMutation() {
return toggleFeatureMutation({
apollo: this.$apollo,
featureName: 'vue-profile',
userIds: this.userIds,
refetchQueries: this.refetchQueries,
});
},
toggleVueProfiles() {
return this.performToggleFeatureMutation().then(response => {
if(response.success) this.updatedSuccessfully = true;
}).catch(error => {
this.updatedSuccessfully = false;
invariant(false, error);
});
},
},
apollo: {
users: {
query: gql`query users {
users {
id
name
}
}`,
},
},
}
</script>
import { mount } from 'vue-test-utils';
import MyComponent from '~src/packages/profiles/components/MyComponent5.vue';
describe('MyComponent', () => {
const users = [{ id: 1, name: 'First' }];
describe('flash message', () => {
it('shows the flash when clicking delete all button', () => {
const wrapper = mount(MyComponent, {
propsData: { users, profile: { admin: true } },
});
wrapper.find('[data-test-delete-all-btn]').trigger('click');
expect(wrapper.find('[data-test-flash-message]')).to.exist;
// OR test the whole DOM
expect(wrapper.html()).to.contain('data-test-flash-message');
});
});
});
<template>
<div v-if="isAdmin">
<div class="flash"
v-if="showFlashMessage"
data-test-flash-message
>
Are you sure you want to delete all users? You may get fired.
<button class="why-do-we-have-this-button">
Yes, I'm outta here
</button>
<button class="they-better-click-this-one">
No, I want to keep the users and my job
</button>
</div>
<ul>
<MyListItem v-for="user in users"
:key="user.id"
:user="user"
>
</MyListItem>
</ul>
<button class="super-danger-btn"
@click="deleteAllUsers"
data-test-delete-all-btn
>
Delete all users
</button>
</div>
</template>
<script>
import _get from 'lodash/get';
import MyListItem from './MyListItem.vue';
export default {
name: 'MyComponent',
components: { MyListItem },
props: {
users: Array,
profile: Object,
},
data() {
return { showFlashMessage: false };
},
computed: {
isAdmin() {
return _get(this.profile, 'admin', false);
},
},
methods: {
deleteAllUsers() {
this.showFlashMessage = true;
},
},
}
</script>
import { mount } from 'vue-test-utils';
import MyComponent from '~src/packages/profiles/components/MyComponent6.vue';
describe('MyComponent', () => {
const users = Object.freeze([
{ id: 1, name: 'First' },
{ id: 2, name: 'Second' },
{ id: 3, name: 'Third' },
]);
let $router = [];
afterEach(() => {
$router = [];
});
describe('navigation', () => {
it('goes to the profile page', () => {
const profileUUID = 'abc123';
const wrapper = mount(MyComponent, {
propsData: {
users,
profile: { uuid: profileUUID, admin: true },
},
mocks: { $router },
});
wrapper.find('[data-test-profile-btn]').trigger('click');
expect($router[0].name).to.eq('profiles-index');
expect($router[0].params.profileUUID).to.eq(profileUUID);
});
});
});
<template>
<div v-if="isAdmin">
<ul>
<MyListItem v-for="user in users"
:key="user.id"
:user="user"
>
</MyListItem>
</ul>
<button @click="goToProfile"
data-test-profile-btn
>
Profile
</button>
</div>
</template>
<script>
import _get from 'lodash/get';
import MyListItem from './MyListItem.vue';
export default {
name: 'MyComponent',
components: { MyListItem },
props: {
users: Array,
profile: Object,
},
computed: {
isAdmin() {
return _get(this.profile, 'admin', false);
},
profileUUID() {
return _get(this.profile, 'uuid', '');
},
},
methods: {
goToProfile() {
this.$router.push({
name: 'profiles-index',
params: { profileUUID: this.profileUUID },
});
},
},
}
</script>
import { mountDoxVue } from '~test/util/doxVue';
import MyComponent from '~src/packages/profiles/components/MyComponent7.vue';
describe('MyComponent', () => {
const users = Object.freeze([{ id: 1, name: 'First' }]);
it('triggers a flash message', async () => {
const wrapper = mountDoxVue(MyComponent, { propsData: { users } });
wrapper.find('[data-test-flash-btn]').trigger('click');
await wrapper.vm.$nextTick();
const message = wrapper.vm.$translate('MyComponent7.flashMessage');
expect(wrapper.vm.$store.state.BASE.flashMessages[0].message).to.eq(
message
);
});
});
<template>
<div>
<ul>
<MyListItem v-for="user in users"
:key="user.id"
:user="user"
>
</MyListItem>
</ul>
<button @click="showFlash"
data-test-flash-btn
>
Do something flash message worthy
</button>
</div>
</template>
<script>
import MyListItem from './MyListItem.vue';
import { mapMutations } from 'vuex';
import { BASE_ADD_FLASH_MESSAGE } from '~src/packages/base/store.js';
export default {
name: 'MyComponent',
components: { MyListItem },
props: {
users: Array,
},
methods: {
...mapMutations({ addFlashMessage: BASE_ADD_FLASH_MESSAGE }),
showFlash() {
this.performFlashDataQuery().then(response => {
if(response.success) {
this.addFlashMessage({
message: this.$translate('MyComponent7.flashMessage'),
});
}
});
},
performFlashDataQuery() {
return new Promise(resolve => { resolve({ success: true }) });
},
},
}
</script>
<template>
<p data-test-user-item>
{{ user.name }}
</p>
</template>
<script>
export default {
name: 'MyListItem',
props: {
user: {
type: Object,
required: true,
},
},
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment