├── .browserslistrc
├── test
└── unit
│ ├── globals
│ ├── index.js
│ ├── di.js
│ └── console.js
│ ├── utils
│ ├── tid.js
│ ├── di.js
│ ├── axios.js
│ └── store.js
│ ├── index.js
│ └── base.po.js
├── .postcssrc.js
├── .lintstagedrc
├── jsconfig.json
├── public
├── favicon.ico
└── index.html
├── src
├── assets
│ └── logo.png
├── store
│ ├── auth
│ │ ├── getters.js
│ │ ├── mutations.js
│ │ ├── index.js
│ │ ├── actions.js
│ │ ├── getters.spec.js
│ │ ├── mutations.spec.js
│ │ └── actions.spec.js
│ └── index.js
├── components
│ ├── MyCheckboxListContext.js
│ ├── MyCheckboxListStatus.vue.po.js
│ ├── MyButton.vue.po.js
│ ├── MyCheckboxList.vue.po.js
│ ├── MyCheckbox.vue.po.js
│ ├── MyButton.vue
│ ├── MyCheckboxListStatus.vue
│ ├── MyCheckboxList.vue
│ ├── Emails.vue.po.js
│ ├── MyButton.vue.spec.js
│ ├── MyCheckbox.vue
│ ├── MyCheckboxListStatus.vue.spec.js
│ ├── Emails.vue
│ ├── MyCheckbox.vue.spec.js
│ └── MyCheckboxList.vue.spec.js
├── services
│ ├── api.js
│ ├── profile.js
│ ├── auth-interceptor.js
│ ├── credentials.js
│ ├── email.js
│ ├── profile.stub.js
│ ├── auth.js
│ ├── credentials.spec.js
│ ├── profile.spec.js
│ ├── auth.stub.js
│ ├── auth-interceptor.spec.js
│ ├── email.spec.js
│ ├── auth.spec.js
│ └── email.stub.js
├── filters
│ ├── full-name.js
│ └── full-name.spec.js
├── bootstrap.js
├── directives
│ ├── focus.js
│ └── focus.spec.js
├── views
│ ├── About.vue.po.js
│ ├── Welcome.vue.po.js
│ ├── About.vue
│ ├── Login.vue.po.js
│ ├── Welcome.vue
│ ├── About.vue.spec.js
│ ├── Login.vue
│ ├── Welcome.vue.spec.js
│ └── Login.vue.spec.js
├── main.js
├── App.vue.po.js
├── di.js
├── router.js
├── App.vue.spec.js
├── App.vue
└── router.spec.js
├── .editorconfig
├── babel.config.js
├── .gitignore
├── .nycrc
├── vue.config.js
├── .eslintrc.js
├── TODO.md
├── LICENSE
├── package.json
└── README.md
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 8
4 |
--------------------------------------------------------------------------------
/test/unit/globals/index.js:
--------------------------------------------------------------------------------
1 | import '..';
2 | import './console';
3 | import './di';
4 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,vue}": [
3 | "npm run lint",
4 | "git add"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "experimentalDecorators": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcibique/vue-testing-examples/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mcibique/vue-testing-examples/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/src/store/auth/getters.js:
--------------------------------------------------------------------------------
1 | export function isAuthenticated (state) {
2 | return !!state.token;
3 | }
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 |
--------------------------------------------------------------------------------
/src/components/MyCheckboxListContext.js:
--------------------------------------------------------------------------------
1 | const MY_CHECKBOX_LIST_CONTEXT = Symbol('MY_CHECKBOX_LIST_CONTEXT');
2 |
3 | export default MY_CHECKBOX_LIST_CONTEXT;
4 |
--------------------------------------------------------------------------------
/src/services/api.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { authRequestInterceptor } from './auth-interceptor';
3 |
4 | axios.interceptors.request.use(authRequestInterceptor);
5 |
--------------------------------------------------------------------------------
/src/store/auth/mutations.js:
--------------------------------------------------------------------------------
1 | export function resetToken (state) {
2 | state.token = null;
3 | }
4 |
5 | export function setToken (state, token) {
6 | state.token = token;
7 | }
8 |
--------------------------------------------------------------------------------
/test/unit/globals/di.js:
--------------------------------------------------------------------------------
1 | import container from '@di';
2 |
3 | beforeEach(function () {
4 | container.snapshot();
5 | });
6 |
7 | afterEach(function () {
8 | container.restore();
9 | });
10 |
--------------------------------------------------------------------------------
/src/filters/full-name.js:
--------------------------------------------------------------------------------
1 | export function fullName (profile) {
2 | if (!profile) {
3 | return '';
4 | }
5 |
6 | return `${profile.firstName || ''} ${profile.lastName || ''}`.trim() || profile.username || '';
7 | }
8 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ['@vue/app', { jsx: false, loose: true, useBuiltIns: 'entry' }]
4 | ],
5 | 'env': {
6 | 'test': {
7 | 'plugins': [
8 | 'istanbul'
9 | ]
10 | }
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/src/components/MyCheckboxListStatus.vue.po.js:
--------------------------------------------------------------------------------
1 | import BasePageObj from '@unit/base.po';
2 |
3 | export default class MyCheckboxListStatusPageObj extends BasePageObj {
4 | get defaultMessage () {
5 | return this.tid('c-checkbox-list-status__default-message');
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/components/MyButton.vue.po.js:
--------------------------------------------------------------------------------
1 | import BasePageObj from '@unit/base.po';
2 |
3 | export default class MyButtonPageObj extends BasePageObj {
4 | click () {
5 | return this.wrapper.trigger('click');
6 | }
7 |
8 | isPrimary () {
9 | return this.wrapper.classes().includes('c-button--primary');
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/unit/utils/tid.js:
--------------------------------------------------------------------------------
1 | import { Wrapper, WrapperArray } from '@vue/test-utils';
2 |
3 | Wrapper.prototype.tid = function (selector) {
4 | return this.find(`[tid~="${selector}"]`);
5 | };
6 |
7 | Wrapper.prototype.tids = WrapperArray.prototype = function (selector) {
8 | return this.findAll(`[tid~="${selector}"]`);
9 | };
10 |
--------------------------------------------------------------------------------
/test/unit/utils/di.js:
--------------------------------------------------------------------------------
1 | import sinon from 'sinon';
2 | import container, { overrideWithConstantValue } from '@di';
3 |
4 | export function mockService (identifier) {
5 | let service = container.get(identifier);
6 | let serviceMock = sinon.mock(service);
7 | overrideWithConstantValue(identifier, service);
8 | return serviceMock;
9 | }
10 |
--------------------------------------------------------------------------------
/src/services/profile.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { Register } from '@di';
3 |
4 | export const PROFILE_SERVICE_ID = Symbol('profileService');
5 |
6 | @Register(PROFILE_SERVICE_ID)
7 | export default class ProfileService {
8 | getProfile () {
9 | return axios.get('/api/profile').then(response => response.data);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw*
22 |
23 | .nyc_output
24 | test/reports
25 |
--------------------------------------------------------------------------------
/src/services/auth-interceptor.js:
--------------------------------------------------------------------------------
1 | import container from '@di';
2 | import { STORE_ID } from '@/store';
3 |
4 | export function authRequestInterceptor (config) {
5 | let store = container.get(STORE_ID);
6 | if (store.state.auth.token) {
7 | config.headers.Authorization = `Bearer ${store.state.auth.token}`;
8 | }
9 |
10 | return config;
11 | }
12 |
--------------------------------------------------------------------------------
/src/bootstrap.js:
--------------------------------------------------------------------------------
1 | import 'core-js/stable';
2 | import 'regenerator-runtime/runtime';
3 | import 'reflect-metadata';
4 | import { Component } from 'vue-property-decorator';
5 |
6 | // do this before any VUE component is loaded, otherwise @Component() would ignore navigation guards
7 | Component.registerHooks(['beforeRouteEnter', 'beforeRouteLeave', 'beforeRouteUpdate']);
8 |
--------------------------------------------------------------------------------
/src/store/auth/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions';
2 | import * as getters from './getters';
3 | import * as mutations from './mutations';
4 |
5 | export default function createModule () {
6 | return {
7 | namespaced: true,
8 | state: {
9 | token: null
10 | },
11 | actions,
12 | mutations,
13 | getters
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/src/services/credentials.js:
--------------------------------------------------------------------------------
1 | import { Register } from '@di';
2 |
3 | export const CREDENTIALS_SERVICE_ID = Symbol('credentialsService');
4 |
5 | @Register(CREDENTIALS_SERVICE_ID)
6 | export default class CredentialsService {
7 | sanitize (input) {
8 | if (input && input.trim) {
9 | return input.trim();
10 | } else {
11 | return input;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.nycrc:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "src/**/*.(js|vue)"
4 | ],
5 | "exclude": [
6 | "src/**/*.spec.js",
7 | "src/**/*.po.js",
8 | "src/**/*.stub.js"
9 | ],
10 | "instrument": false,
11 | "sourceMap": false,
12 | "reporter": [
13 | "html",
14 | "text"
15 | ],
16 | "report-dir": "./test/reports",
17 | "tempDirectory": "./test/reports/.nyc_output"
18 | }
19 |
--------------------------------------------------------------------------------
/src/directives/focus.js:
--------------------------------------------------------------------------------
1 | export default {
2 | inserted (el, binding) {
3 | if (typeof binding.value === 'undefined' || !!binding.value) {
4 | el.focus();
5 | }
6 | },
7 | componentUpdated (el, binding) {
8 | if (binding.value !== binding.oldValue) {
9 | if (typeof binding.value === 'undefined' || !!binding.value) {
10 | el.focus();
11 | } else {
12 | el.blur();
13 | }
14 | }
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/src/services/email.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { Register } from '@di';
3 |
4 | export const EMAIL_SERVICE_ID = Symbol('emailService');
5 |
6 | @Register(EMAIL_SERVICE_ID)
7 | export default class EmailService {
8 | getEmails () {
9 | return axios.get('/api/emails').then(response => response.data);
10 | }
11 | markEmailAsRead (id) {
12 | return axios.put(`/api/emails/${id}`, { unread: false }).then(response => response.data);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/views/About.vue.po.js:
--------------------------------------------------------------------------------
1 | import BasePageObj from '@unit/base.po';
2 |
3 | export default class AboutViewPageObj extends BasePageObj {
4 | get heading () {
5 | return this.tid('c-about__heading');
6 | }
7 |
8 | get githubLink () {
9 | return this.tid('c-about__github-link');
10 | }
11 |
12 | get backLink () {
13 | return this.tid('c-about__back-link');
14 | }
15 |
16 | goBack () {
17 | return this.backLink.trigger('click');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | let path = require('path');
2 | let useServiceStub = !!process.env.npm_config_stub;
3 |
4 | module.exports = {
5 | productionSourceMap: false,
6 |
7 | chainWebpack (config) {
8 | config.resolve.alias.set('@unit', path.resolve(__dirname, 'test', 'unit'));
9 | config.resolve.alias.set('@di', path.resolve(__dirname, 'src', 'di.js'));
10 |
11 | if (useServiceStub) {
12 | config.resolve.extensions.prepend('.stub.js');
13 | }
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | VUE testing examples
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/unit/index.js:
--------------------------------------------------------------------------------
1 | import chai from 'chai';
2 | import chaiAsPromised from 'chai-as-promised';
3 | import sinon from 'sinon';
4 | import sinonChai from 'sinon-chai';
5 | import sinonStubPromise from 'sinon-stub-promise';
6 | import { config } from '@vue/test-utils';
7 |
8 | import './utils/axios';
9 | import './utils/store';
10 | import './utils/tid';
11 |
12 | config.logModifiedComponents = false;
13 |
14 | chai.use(sinonChai);
15 | chai.use(chaiAsPromised);
16 | sinonStubPromise(sinon);
17 |
--------------------------------------------------------------------------------
/test/unit/utils/axios.js:
--------------------------------------------------------------------------------
1 | import AxiosMockAdapter from 'axios-mock-adapter';
2 | import { expect } from 'chai';
3 |
4 | AxiosMockAdapter.prototype.verifyNoOutstandingExpectation = function () {
5 | for (let verb in this.handlers) {
6 | let expectations = this.handlers[verb];
7 | if (expectations.length > 0) {
8 | for (let expectation of expectations) {
9 | expect.fail(1, 0, `Expected URL ${expectation[0]} to have been requested but it wasn't.`);
10 | }
11 | }
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/test/unit/globals/console.js:
--------------------------------------------------------------------------------
1 | import sinon from 'sinon';
2 | import { expect } from 'chai';
3 |
4 | beforeEach(function () {
5 | if (console.error.restore) {
6 | console.error.restore();
7 | }
8 | if (console.error.reset) {
9 | console.error.reset();
10 | }
11 | sinon.spy(console, 'error');
12 | });
13 |
14 | afterEach(function () {
15 | expect(console.error, `console.error() has been called ${console.error.callCount} times.`).not.to.have.been.called;
16 | console.error.restore();
17 | });
18 |
--------------------------------------------------------------------------------
/src/views/Welcome.vue.po.js:
--------------------------------------------------------------------------------
1 | import BasePageObj from '@unit/base.po';
2 | import EmailsPageObj from '@/components/Emails.vue.po';
3 |
4 | export default class WelcomeViewPageObj extends BasePageObj {
5 | get header () {
6 | return this.tid('welcome__header');
7 | }
8 |
9 | get loading () {
10 | return this.tid('welcome__loading');
11 | }
12 |
13 | get loadingError () {
14 | return this.tid('welcome_loading-error');
15 | }
16 |
17 | get emails () {
18 | return new EmailsPageObj(this.tid('welcome__emails'));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import './bootstrap';
2 | import { registerConstantValue } from './di';
3 | import Vue from 'vue';
4 | import App from './App.vue';
5 | import { createRouter, ROUTER_ID } from './router';
6 | import { createStore, STORE_ID } from './store';
7 | import './services/api';
8 |
9 | Vue.config.productionTip = false;
10 |
11 | let store = createStore(Vue);
12 | registerConstantValue(STORE_ID, store);
13 |
14 | let router = createRouter(Vue);
15 | registerConstantValue(ROUTER_ID, router);
16 |
17 | new Vue({
18 | router,
19 | store,
20 | render: h => h(App)
21 | }).$mount('#app');
22 |
--------------------------------------------------------------------------------
/src/store/auth/actions.js:
--------------------------------------------------------------------------------
1 | import container from '@di';
2 | import { AUTH_SERVICE_ID } from '@/services/auth';
3 |
4 | export async function login ({ commit }, { username, password, rememberMe }) {
5 | let authService = container.get(AUTH_SERVICE_ID);
6 | let token = await authService.login(username, password, rememberMe);
7 | commit('setToken', token);
8 | return token;
9 | }
10 |
11 | export async function logout ({ commit }) {
12 | let authService = container.get(AUTH_SERVICE_ID);
13 | await authService.logout().finally(function () {
14 | commit('resetToken');
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/src/App.vue.po.js:
--------------------------------------------------------------------------------
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 | }
28 |
--------------------------------------------------------------------------------
/src/store/auth/getters.spec.js:
--------------------------------------------------------------------------------
1 | import '@unit/globals';
2 | import { expect } from 'chai';
3 |
4 | import { isAuthenticated } from './getters';
5 |
6 | describe('Store - Auth module getters', function () {
7 | describe('isAuthenticated', function () {
8 | it('should return true if authentication token exists', function () {
9 | expect(isAuthenticated({ token: 'random_token' })).to.be.true;
10 | });
11 |
12 | it('should return false if authentication token doesn\'t exists', function () {
13 | expect(isAuthenticated({ token: null })).to.be.false;
14 | });
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | mocha: true
6 | },
7 | extends: [
8 | 'plugin:vue/essential',
9 | '@vue/standard'
10 | ],
11 | rules: {
12 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
14 | 'semi': ['error', 'always'],
15 | 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': true }],
16 | 'no-unused-expressions': 'off'
17 | },
18 | parserOptions: {
19 | parser: 'babel-eslint',
20 | ecmaFeatures: {
21 | legacyDecorators: true
22 | }
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/src/components/MyCheckboxList.vue.po.js:
--------------------------------------------------------------------------------
1 | import BasePageObj from '@unit/base.po';
2 | import MyCheckboxListStatusPageObj from './MyCheckboxListStatus.vue.po';
3 | import MyCheckboxPageObj from './MyCheckbox.vue.po';
4 |
5 | export default class MyCheckboxListPageObj extends BasePageObj {
6 | get statusElement () {
7 | return this.tid('c-checkbox-list-status');
8 | }
9 |
10 | get status () {
11 | return new MyCheckboxListStatusPageObj(this.statusElement);
12 | }
13 |
14 | get checkboxElements () {
15 | return this.tids('c-checkbox');
16 | }
17 |
18 | get checkboxes () {
19 | return this.checkboxElements.wrappers.map(checkboxElement => new MyCheckboxPageObj(checkboxElement));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/services/profile.stub.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import AxiosMockAdapter from 'axios-mock-adapter';
3 | import { Override } from '@di';
4 |
5 | import ProfileService, { PROFILE_SERVICE_ID } from './profile.js'; // always use '.js' extension otherwise this module will be required.
6 |
7 | export { PROFILE_SERVICE_ID };
8 |
9 | @Override(PROFILE_SERVICE_ID)
10 | export default class ProfileStubService extends ProfileService {
11 | getProfile () {
12 | let axiosMock = new AxiosMockAdapter(axios);
13 | axiosMock.onGet('/api/profile').replyOnce(200, {
14 | firstName: 'John',
15 | lastName: 'Doe',
16 | username: 'john.doe',
17 | id: '123'
18 | });
19 |
20 | return super.getProfile().finally(() => axiosMock.restore());
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/MyCheckbox.vue.po.js:
--------------------------------------------------------------------------------
1 | import BasePageObj from '@unit/base.po';
2 |
3 | export default class MyCheckboxPageObj extends BasePageObj {
4 | get icon () {
5 | return this.wrapper.tid('c-checkbox__icon');
6 | }
7 |
8 | get label () {
9 | return this.wrapper.tid('c-checkbox__label');
10 | }
11 |
12 | text () {
13 | return this.label.text();
14 | }
15 |
16 | check () {
17 | return this.icon.trigger('click');
18 | }
19 |
20 | get isChecked () {
21 | return this.icon.classes().includes('c-checkbox__icon--checked');
22 | }
23 |
24 | get isFocused () {
25 | return this.icon.classes().includes('c-checkbox__icon--focused');
26 | }
27 |
28 | setChecked (newValue) {
29 | if (this.isChecked !== newValue) {
30 | this.check();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import { namespace } from 'vuex-class';
4 |
5 | import createAuthModule from './auth';
6 |
7 | export const AUTH_MODULE_ID = 'auth';
8 |
9 | export function createStore (/* istanbul ignore next */ vueInstance = Vue) {
10 | vueInstance.use(Vuex);
11 |
12 | return new Vuex.Store({
13 | namespaced: true,
14 | strict: process.env.NODE_ENV !== 'production',
15 | modules: {
16 | [AUTH_MODULE_ID]: createAuthModule()
17 | }
18 | });
19 | }
20 |
21 | export const STORE_ID = Symbol('store');
22 |
23 | let { Getter: AuthGetter, State: AuthState, Action: AuthAction, Mutation: AuthMutation } = namespace(AUTH_MODULE_ID);
24 |
25 | export {
26 | AuthGetter,
27 | AuthState,
28 | AuthAction,
29 | AuthMutation
30 | };
31 |
--------------------------------------------------------------------------------
/src/services/auth.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { Register } from '@di';
3 |
4 | import { CREDENTIALS_SERVICE_ID } from './credentials';
5 |
6 | export const AUTH_SERVICE_ID = Symbol('authService');
7 |
8 | @Register(AUTH_SERVICE_ID, [CREDENTIALS_SERVICE_ID])
9 | export default class AuthService {
10 | constructor (credentialsService) {
11 | this.credentialsService = credentialsService;
12 | }
13 |
14 | login (username, password, rememberMe) {
15 | username = this.credentialsService.sanitize(username);
16 | password = this.credentialsService.sanitize(password);
17 | return axios.post('/api/login', { username, password, rememberMe }).then(response => response.data);
18 | }
19 |
20 | logout () {
21 | return axios.post('/api/logout').then(response => response.data);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/MyButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
35 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # To document:
2 |
3 | 1. Testing navigation guards
4 | 1. Testing filter
5 | 1. Testing directive
6 | 1. Writing complex integration test for a component
7 | 1. Mocking router
8 | 1. Scoped slots
9 | 1. Inversify and mocking router/store in tests
10 | 1. Test coverage
11 |
12 | Introduce the dev stack:
13 |
14 | * vue, vuex, vue-router, vue-property-decorator, vuex-class, axios, lodash, inversify (vanilla js solution), sinon, mocha, sinon-chai, sinon-stub-promise flush-promises, lolex
15 |
16 | Provide examples for
17 |
18 | * ??? testing mutations, actions ???
19 | * ??? testing `router.push()` to the route with async component using `import()` ???
20 | * ??? broken test coverage (100% coverage but still not taking all paths: https://twitter.com/getify/status/955939257755021312) ???
21 | * ??? 100% test coverage without need to test everything (https://labs.ig.com/code-coverage-100-percent-tragedy) ???
22 |
23 | Issues:
24 |
25 | * !!! `trigger("click")` on `