add unit test

v4.0
Pan 2018-10-26 11:29:14 +08:00
parent 5c29ebfa2b
commit 065c5e9635
13 changed files with 270 additions and 15 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
tests/**/coverage/
# Editor directories and files
.idea

24
jest.config.js 100644
View File

@ -0,0 +1,24 @@
module.exports = {
verbose: true,
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

View File

@ -1,17 +1,17 @@
{
"name": "vue-admin-template",
"version": "3.8.0",
"license": "MIT",
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
"author": "Pan <panfree23@gmail.com>",
"scripts": {
"dev": "vue-cli-service serve",
"build": "node build/index.js",
"build:report": "node build/index.js --report",
"build:preview": "node build/index.js --preview",
"build:report": "node build/index.js --report",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"lint": "vue-cli-service lint",
"test": "npm run lint",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
"test:unit": "vue-cli-service test:unit",
"test": "npm run lint && npm run test:unit"
},
"dependencies": {
"axios": "0.18.0",
@ -27,7 +27,11 @@
"devDependencies": {
"@vue/cli-plugin-babel": "3.0.5",
"@vue/cli-plugin-eslint": "3.0.5",
"@vue/cli-plugin-unit-jest": "3.0.5",
"@vue/cli-service": "3.0.5",
"@vue/test-utils": "1.0.0-beta.20",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "23.6.0",
"chalk": "2.4.1",
"connect": "3.6.6",
"node-sass": "^4.9.3",
@ -40,13 +44,14 @@
"svgo": "1.0.5",
"vue-template-compiler": "2.5.17"
},
"engines": {
"node": ">= 8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
],
"engines": {
"node": ">= 8.9",
"npm": ">= 3.0.0"
},
"license": "MIT"
}

View File

@ -33,10 +33,11 @@ export default {
isActive: {
type: Boolean,
default: false
},
toggleClick: {
type: Function,
default: null
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}

View File

@ -36,7 +36,11 @@ export function parseTime(time, cFormat) {
}
export function formatTime(time, option) {
time = +time * 1000
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()

View File

@ -1,6 +1,6 @@
<template>
<el-menu class="navbar" mode="horizontal">
<hamburger :toggle-click="toggleSideBar" :is-active="sidebar.opened" class="hamburger-container"/>
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar"/>
<breadcrumb />
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">

View File

@ -0,0 +1,5 @@
module.exports = {
env: {
jest: true
}
}

View File

@ -0,0 +1,93 @@
import { mount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
import ElementUI from 'element-ui'
import Breadcrumb from '@/components/Breadcrumb/index.vue'
const localVue = createLocalVue()
localVue.use(VueRouter)
localVue.use(ElementUI)
const routes = [
{
path: '/',
name: 'home',
children: [{
path: 'dashboard',
name: 'dashboard'
}]
},
{
path: '/menu',
name: 'menu',
children: [{
path: 'menu1',
name: 'menu1',
meta: { title: 'menu1' },
children: [{
path: 'menu1-1',
name: 'menu1-1',
meta: { title: 'menu1-1' }
},
{
path: 'menu1-2',
name: 'menu1-2',
redirect: 'noredirect',
meta: { title: 'menu1-2' },
children: [{
path: 'menu1-2-1',
name: 'menu1-2-1',
meta: { title: 'menu1-2-1' }
},
{
path: 'menu1-2-2',
name: 'menu1-2-2'
}]
}]
}]
}]
const router = new VueRouter({
routes
})
describe('Breadcrumb.vue', () => {
const wrapper = mount(Breadcrumb, {
localVue,
router
})
it('dashboard', () => {
router.push('/dashboard')
const len = wrapper.findAll('.el-breadcrumb__inner').length
expect(len).toBe(1)
})
it('normal route', () => {
router.push('/menu/menu1')
const len = wrapper.findAll('.el-breadcrumb__inner').length
expect(len).toBe(2)
})
it('nested route', () => {
router.push('/menu/menu1/menu1-2/menu1-2-1')
const len = wrapper.findAll('.el-breadcrumb__inner').length
expect(len).toBe(4)
})
it('no meta.title', () => {
router.push('/menu/menu1/menu1-2/menu1-2-2')
const len = wrapper.findAll('.el-breadcrumb__inner').length
expect(len).toBe(3)
})
it('click link', () => {
router.push('/menu/menu1/menu1-2/menu1-2-2')
const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
const second = breadcrumbArray.at(1)
const href = second.find('a').attributes().href
expect(href).toBe('#/menu/menu1')
})
it('noredirect', () => {
router.push('/menu/menu1/menu1-2/menu1-2-1')
const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
const redirectBreadcrumb = breadcrumbArray.at(2)
expect(redirectBreadcrumb.contains('a')).toBe(false)
})
it('last breadcrumb', () => {
router.push('/menu/menu1/menu1-2/menu1-2-1')
const breadcrumbArray = wrapper.findAll('.el-breadcrumb__inner')
const redirectBreadcrumb = breadcrumbArray.at(3)
expect(redirectBreadcrumb.contains('a')).toBe(false)
})
})

View File

@ -0,0 +1,18 @@
import { shallowMount } from '@vue/test-utils'
import Hamburger from '@/components/Hamburger/index.vue'
describe('Hamburger.vue', () => {
it('toggle click', () => {
const wrapper = shallowMount(Hamburger)
const mockFn = jest.fn()
wrapper.vm.$on('toggleClick', mockFn)
wrapper.find('.hamburger').trigger('click')
expect(mockFn).toBeCalled()
})
it('prop isActive', () => {
const wrapper = shallowMount(Hamburger)
wrapper.setProps({ isActive: true })
expect(wrapper.contains('.is-active')).toBe(true)
wrapper.setProps({ isActive: false })
expect(wrapper.contains('.is-active')).toBe(false)
})
})

View File

@ -0,0 +1,22 @@
import { shallowMount } from '@vue/test-utils'
import SvgIcon from '@/components/SvgIcon/index.vue'
describe('SvgIcon.vue', () => {
it('iconClass', () => {
const wrapper = shallowMount(SvgIcon, {
propsData: {
iconClass: 'test'
}
})
expect(wrapper.find('use').attributes().href).toBe('#icon-test')
})
it('className', () => {
const wrapper = shallowMount(SvgIcon, {
propsData: {
iconClass: 'test'
}
})
expect(wrapper.classes().length).toBe(1)
wrapper.setProps({ className: 'test' })
expect(wrapper.classes().includes('test')).toBe(true)
})
})

View File

@ -0,0 +1,27 @@
import { formatTime } from '@/utils/index.js'
describe('Utils:formatTime', () => {
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
it('ten digits timestamp', () => {
expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
})
it('test now', () => {
expect(formatTime(+new Date() - 1)).toBe('刚刚')
})
it('less two minute', () => {
expect(formatTime(+new Date() - 60 * 2 * 1000)).toBe('2分钟前')
})
it('less two hour', () => {
expect(formatTime(+new Date() - 60 * 60 * 2 * 1000)).toBe('2小时前')
})
it('less one day', () => {
expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
})
it('more than one day', () => {
expect(formatTime(d)).toBe('7月13日17时54分')
})
it('format', () => {
expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
})
})

View File

@ -0,0 +1,27 @@
import { parseTime } from '@/utils/index.js'
describe('Utils:parseTime', () => {
const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
it('timestamp', () => {
expect(parseTime(d)).toBe('2018-07-13 17:54:01')
})
it('ten digits timestamp', () => {
expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
})
it('new Date', () => {
expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
})
it('format', () => {
expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
})
it('get the day of the week', () => {
expect(parseTime(d, '{a}')).toBe('五') // 星期五
})
it('get the day of the week', () => {
expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
})
it('empty argument', () => {
expect(parseTime()).toBeNull()
})
})

View File

@ -0,0 +1,28 @@
import { isvalidUsername, validateURL, validateLowerCase, validateUpperCase, validatAlphabets } from '@/utils/validate.js'
describe('Utils:validate', () => {
it('isvalidUsername', () => {
expect(isvalidUsername('admin')).toBe(true)
expect(isvalidUsername('editor')).toBe(true)
expect(isvalidUsername('xxxx')).toBe(false)
})
it('validateURL', () => {
expect(validateURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
expect(validateURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
expect(validateURL('github.com/PanJiaChen/vue-element-admin')).toBe(false)
})
it('validateLowerCase', () => {
expect(validateLowerCase('abc')).toBe(true)
expect(validateLowerCase('Abc')).toBe(false)
expect(validateLowerCase('123abc')).toBe(false)
})
it('validateUpperCase', () => {
expect(validateUpperCase('ABC')).toBe(true)
expect(validateUpperCase('Abc')).toBe(false)
expect(validateUpperCase('123ABC')).toBe(false)
})
it(' validatAlphabets', () => {
expect(validatAlphabets('ABC')).toBe(true)
expect(validatAlphabets('Abc')).toBe(true)
expect(validatAlphabets('123aBC')).toBe(false)
})
})