Compare commits
12 Commits
Author | SHA1 | Date |
---|---|---|
|
e1a5cbce2e | |
|
1f78a3b099 | |
|
ef1b46656d | |
|
e1931832eb | |
|
bc2f37532b | |
|
ff1e8fa30d | |
|
828f8117e8 | |
|
4320647061 | |
|
de6d6cadd7 | |
|
23d2043d39 | |
|
1ab649b982 | |
|
b14abd0a6f |
14
.babelrc
14
.babelrc
|
@ -8,5 +8,17 @@
|
||||||
}],
|
}],
|
||||||
"stage-2"
|
"stage-2"
|
||||||
],
|
],
|
||||||
"plugins":["transform-vue-jsx", "transform-runtime"]
|
"plugins": ["transform-vue-jsx", "transform-runtime"],
|
||||||
|
"env": {
|
||||||
|
"test": {
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"targets": {
|
||||||
|
"node": "current"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ module.exports = {
|
||||||
browser: true,
|
browser: true,
|
||||||
node: true,
|
node: true,
|
||||||
es6: true,
|
es6: true,
|
||||||
|
jest: true
|
||||||
},
|
},
|
||||||
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
test/coverage/
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: stable
|
node_js: stable
|
||||||
script: npm run test
|
install:
|
||||||
|
- npm install
|
||||||
|
- npm install -g codecov
|
||||||
|
script: npm run test:ci
|
||||||
|
after_success:
|
||||||
|
- codecov
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
module.exports = {
|
||||||
|
verbose: true,
|
||||||
|
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.vue$': 'vue-jest',
|
||||||
|
'^.+\\.jsx?$': 'babel-jest'
|
||||||
|
},
|
||||||
|
moduleNameMapper: {
|
||||||
|
'^@/(.*)$': '<rootDir>/src/$1'
|
||||||
|
},
|
||||||
|
snapshotSerializers: ['jest-serializer-vue'],
|
||||||
|
testMatch: [
|
||||||
|
'<rootDir>/(test/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': './test/coverage',
|
||||||
|
'collectCoverage': true,
|
||||||
|
'coverageReporters': [
|
||||||
|
'lcov',
|
||||||
|
'text-summary'
|
||||||
|
]
|
||||||
|
}
|
|
@ -10,7 +10,9 @@
|
||||||
"build": "node build/build.js",
|
"build": "node build/build.js",
|
||||||
"build:report": "npm_config_report=true node build/build.js",
|
"build:report": "npm_config_report=true node build/build.js",
|
||||||
"lint": "eslint --ext .js,.vue src",
|
"lint": "eslint --ext .js,.vue src",
|
||||||
"test": "npm run lint"
|
"test": "jest",
|
||||||
|
"test:watch": " jest --watch",
|
||||||
|
"test:ci": "npm run lint && npm run test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "0.18.0",
|
"axios": "0.18.0",
|
||||||
|
@ -23,10 +25,12 @@
|
||||||
"vuex": "3.0.1"
|
"vuex": "3.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vue/test-utils": "1.0.0-beta.20",
|
||||||
"autoprefixer": "8.5.0",
|
"autoprefixer": "8.5.0",
|
||||||
"babel-core": "6.26.0",
|
"babel-core": "6.26.0",
|
||||||
"babel-eslint": "8.2.6",
|
"babel-eslint": "8.2.6",
|
||||||
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||||
|
"babel-jest": "23.4.0",
|
||||||
"babel-loader": "7.1.5",
|
"babel-loader": "7.1.5",
|
||||||
"babel-plugin-syntax-jsx": "6.18.0",
|
"babel-plugin-syntax-jsx": "6.18.0",
|
||||||
"babel-plugin-transform-runtime": "6.23.0",
|
"babel-plugin-transform-runtime": "6.23.0",
|
||||||
|
@ -44,6 +48,8 @@
|
||||||
"file-loader": "1.1.11",
|
"file-loader": "1.1.11",
|
||||||
"friendly-errors-webpack-plugin": "1.7.0",
|
"friendly-errors-webpack-plugin": "1.7.0",
|
||||||
"html-webpack-plugin": "^4.0.0-alpha",
|
"html-webpack-plugin": "^4.0.0-alpha",
|
||||||
|
"jest": "23.4.0",
|
||||||
|
"jest-serializer-vue": "2.0.2",
|
||||||
"mini-css-extract-plugin": "0.4.1",
|
"mini-css-extract-plugin": "0.4.1",
|
||||||
"node-notifier": "5.2.1",
|
"node-notifier": "5.2.1",
|
||||||
"node-sass": "^4.7.2",
|
"node-sass": "^4.7.2",
|
||||||
|
@ -62,6 +68,7 @@
|
||||||
"uglifyjs-webpack-plugin": "1.2.7",
|
"uglifyjs-webpack-plugin": "1.2.7",
|
||||||
"url-loader": "1.0.1",
|
"url-loader": "1.0.1",
|
||||||
"vue-loader": "15.3.0",
|
"vue-loader": "15.3.0",
|
||||||
|
"vue-jest": "2.6.0",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-template-compiler": "2.5.17",
|
"vue-template-compiler": "2.5.17",
|
||||||
"webpack": "4.16.5",
|
"webpack": "4.16.5",
|
||||||
|
|
|
@ -33,10 +33,11 @@ export default {
|
||||||
isActive: {
|
isActive: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
}
|
||||||
toggleClick: {
|
},
|
||||||
type: Function,
|
methods: {
|
||||||
default: null
|
toggleClick() {
|
||||||
|
this.$emit('toggleClick')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,11 @@ export function parseTime(time, cFormat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatTime(time, option) {
|
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 d = new Date(time)
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<el-menu class="navbar" mode="horizontal">
|
<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 />
|
<breadcrumb />
|
||||||
<el-dropdown class="avatar-container" trigger="click">
|
<el-dropdown class="avatar-container" trigger="click">
|
||||||
<div class="avatar-wrapper">
|
<div class="avatar-wrapper">
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,24 @@
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,25 @@
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,35 @@
|
||||||
|
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 + 5)).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')
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,34 @@
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,33 @@
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue