Skip to content

Commit 22066bf

Browse files
author
mcibique
committed
Added missing tests for App component.
1 parent a97e07e commit 22066bf

File tree

7 files changed

+136
-14
lines changed

7 files changed

+136
-14
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"serve": "vue-cli-service serve",
77
"build": "vue-cli-service build",
88
"precommit": "npm run lint -- --no-fix",
9-
"test": "nyc vue-cli-service test src/**/*.spec.js src/router.spec.js src/store/**/*.spec.js --include ./src/bootstrap.js ./test/unit/index.js",
9+
"test": "nyc vue-cli-service test src/**/*.spec.js src/router.spec.js src/store/**/*.spec.js src/App.vue.spec.js --include ./src/bootstrap.js ./test/unit/index.js",
1010
"test:watch": "npm run test -- --watch",
1111
"lint": "vue-cli-service lint"
1212
},

src/App.vue

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
<template>
2-
<div id="app" class="c-app">
3-
<header class="c-app__header">
4-
<router-link to="/logout" v-if="isAuthenticated">Logout</router-link>
2+
<div id="app" class="c-app" tid="c-app">
3+
<header class="c-app__header" tid="c-app__header">
4+
<router-link to="/logout" v-if="isAuthenticated" tid="c-app__logout-link">Logout</router-link>
55
</header>
6-
<main class="c-app__main">
6+
<main class="c-app__main" tid="c-app__main">
77
<router-view></router-view>
88
</main>
9-
<footer class="c-app__footer">
10-
<router-link to="/about">About</router-link>
9+
<footer class="c-app__footer" tid="c-app__footer">
10+
<router-link to="/about" tid="c-app__about-link">About</router-link>
1111
</footer>
1212
</div>
1313
</template>
1414

1515
<script>
16+
import Vue from 'vue';
1617
import { Component } from 'vue-property-decorator';
17-
import { Getter } from 'vuex-class';
18+
19+
import { AuthGetter } from './store/auth';
1820
1921
@Component
20-
export default class App {
21-
@Getter('auth/isAuthenticated') isAuthenticated;
22+
export default class App extends Vue {
23+
@AuthGetter('isAuthenticated') isAuthenticated;
2224
}
2325
</script>
2426

src/App.vue.po.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import BasePageObj from '@unit/base.po';
2+
3+
export default class AppPageObj extends BasePageObj {
4+
get header () {
5+
return this.tid('c-app__header');
6+
}
7+
8+
get main () {
9+
return this.tid('c-app__main');
10+
}
11+
12+
get footer () {
13+
return this.tid('c-app__footer');
14+
}
15+
16+
get logoutLink () {
17+
return this.tid('c-app__logout-link');
18+
}
19+
20+
get aboutLink () {
21+
return this.tid('c-app__about-link');
22+
}
23+
24+
logout () {
25+
this.logoutLink.trigger('click');
26+
}
27+
}

src/App.vue.spec.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import '@unit/globals';
2+
import { mount, createLocalVue } from '@vue/test-utils';
3+
import { expect } from 'chai';
4+
import sinon from 'sinon';
5+
6+
import container from '@di';
7+
import { createStore, STORE_ID } from '@/store';
8+
import { createRouter, ROUTER_ID } from '@/router';
9+
import App from './App';
10+
import AppPageObj from './App.vue.po';
11+
12+
describe('App', function () {
13+
beforeEach(function () {
14+
this.localVue = createLocalVue();
15+
16+
this.store = createStore(this.localVue);
17+
container.bind(STORE_ID).toConstantValue(this.store);
18+
19+
this.router = createRouter(this.localVue);
20+
container.bind(ROUTER_ID).toConstantValue(this.router);
21+
22+
this.mountApp = function (options) {
23+
let wrapper = mount(App, {
24+
localVue: this.localVue,
25+
store: this.store,
26+
router: this.router,
27+
...options
28+
});
29+
return new AppPageObj(wrapper);
30+
};
31+
});
32+
33+
afterEach(function () {
34+
this.store.restore();
35+
});
36+
37+
it('should mount without any errors', function () {
38+
this.mountApp();
39+
expect(console.error).not.to.have.been.called;
40+
});
41+
42+
it('should render properly', function () {
43+
let app = this.mountApp();
44+
expect(app.header.exists(), 'Should render app header').to.be.true;
45+
expect(app.main.exists(), 'Should render app main content').to.be.true;
46+
expect(app.footer.exists(), 'Should render app footer').to.be.true;
47+
});
48+
49+
it('should always display the About link', function () {
50+
let app = this.mountApp();
51+
expect(app.aboutLink.exists(), 'Should render the about link').to.be.true;
52+
});
53+
54+
describe('when user is not authenticated', function () {
55+
beforeEach(function () {
56+
let isAuthenticatedStub = sinon.stub().returns(false);
57+
this.store.mockGetter('auth/isAuthenticated', isAuthenticatedStub);
58+
this.app = this.mountApp();
59+
});
60+
61+
it('should not display logout link', function () {
62+
expect(this.app.logoutLink.exists(), 'Should not display logout link to non-authenticated user').to.be.false;
63+
});
64+
});
65+
66+
describe('when user is authenticated', function () {
67+
beforeEach(function () {
68+
let isAuthenticatedStub = sinon.stub().returns(true);
69+
this.store.mockGetter('auth/isAuthenticated', isAuthenticatedStub);
70+
this.app = this.mountApp();
71+
});
72+
73+
it('should display logout link', function () {
74+
expect(this.app.logoutLink.exists(), 'Should display logout link to authenticated user').to.be.true;
75+
});
76+
});
77+
});

src/store/auth/index.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import cloneDeep from 'lodash/cloneDeep';
1+
import { Getter, State, Action, Mutation, namespace } from 'vuex-class';
22

33
import * as actions from './actions';
44
import * as getters from './getters';
@@ -7,11 +7,23 @@ import * as mutations from './mutations';
77
export default function createModule () {
88
return {
99
namespaced: true,
10-
state: cloneDeep({
10+
state: {
1111
token: null
12-
}),
12+
},
1313
actions,
1414
mutations,
1515
getters
1616
};
1717
}
18+
19+
let AuthGetter = namespace('auth', Getter);
20+
let AuthState = namespace('auth', State);
21+
let AuthAction = namespace('auth', Action);
22+
let AuthMutation = namespace('auth', Mutation);
23+
24+
export {
25+
AuthGetter,
26+
AuthState,
27+
AuthAction,
28+
AuthMutation
29+
};

src/views/About.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<template>
1+
<template functional>
22
<section class="c-about">
33
<h1 class="c-about__heading" tid="c-about__heading">Vue testing examples</h1>
44
<p>Check out <a rel="noreferrer noopener" href="https://github.com/mcibique/vue-testing-examples" target="_blank" tid="c-about__github-link">github</a> page. Go <router-link :to="{ name: 'root' }" tid="c-about__back-link">back</router-link>.</p>

test/unit/base.po.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export default class BasePageObj {
2727
return this.wrapper.exists();
2828
}
2929

30+
html () {
31+
return this.wrapper.html();
32+
}
33+
3034
text () {
3135
return this.wrapper.text();
3236
}

0 commit comments

Comments
 (0)