Skip to content

Commit e66488e

Browse files
committed
chore: unit test
1 parent 92f55dd commit e66488e

12 files changed

+299
-4
lines changed

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"env": {
99
"browser": true,
1010
"node": true,
11-
"es6": true
11+
"es6": true,
12+
"jest": true
1213
},
1314
"parserOptions": {
1415
"ecmaFeatures": {

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ package-lock.json
99

1010
dev/config.js
1111
yarn.lock
12+
13+
coverage

__mocks__/setup.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import moxios from 'moxios'
2+
3+
// mock window.*
4+
global.localStorage = {
5+
getItem () { return '{}' },
6+
setItem () {},
7+
removeItem () {}
8+
}
9+
global.document = {
10+
title: ''
11+
}
12+
global.location = {
13+
search: '',
14+
href: ''
15+
}
16+
17+
// mock axios request
18+
moxios.stubRequest(/\/repos\/.*\/comments/, {
19+
status: 200,
20+
response: [{
21+
id: 1,
22+
html_url: 'https://github.com/xxx/xxx/issues/1#issuecomment-xxx',
23+
body_html: '<p>111</p>',
24+
created_at: '2017-06-30T09:00:19Z',
25+
user: {
26+
login: 'booxood',
27+
avatar_url: 'https://avatars0.githubusercontent.com/u/2151410?v=3',
28+
html_url: 'https://github.com/booxood'
29+
}
30+
}, {
31+
id: 2,
32+
html_url: 'https://github.com/xxx/xxx/issues/1#issuecomment-xxx',
33+
body_html: '<p>222</p>',
34+
created_at: '2017-06-30T09:01:19Z',
35+
user: {
36+
login: 'booxood',
37+
avatar_url: 'https://avatars0.githubusercontent.com/u/2151410?v=3',
38+
html_url: 'https://github.com/booxood'
39+
}
40+
}]
41+
})
42+
moxios.stubRequest(/\/repos\/.*\/issues/, {
43+
status: 200,
44+
response: [{
45+
html_url: 'https://github.com/xxx/xxx/issues/1',
46+
comments_url: 'https://api.github.com/repos/xxx/xxx/issues/1/comments',
47+
comments: 2
48+
}]
49+
})
50+
moxios.stubRequest(/.*/, {
51+
status: 404,
52+
})

__mocks__/style.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = {}

package.json

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,36 @@
1212
"scripts": {
1313
"dev": "cross-env NODE_ENV=development webpack-dev-server --inline --hot --no-info --progress",
1414
"build": "rimraf ./dist && cross-env NODE_ENV=production webpack --hide-modules && cross-env NODE_ENV=production webpack --config webpack.config.min.js",
15-
"lint": "eslint src"
15+
"lint": "eslint src",
16+
"coverage": "jest --coverage",
17+
"test": "jest"
1618
},
1719
"author": "Liucw",
1820
"license": "MIT",
1921
"devDependencies": {
2022
"autoprefixer": "7.1.2",
2123
"babel-core": "6.25.0",
2224
"babel-eslint": "7.2.3",
25+
"babel-jest": "20.0.3",
2326
"babel-loader": "7.1.1",
2427
"babel-preset-es2015": "6.24.1",
2528
"babel-preset-react": "6.24.1",
2629
"babel-preset-stage-2": "6.24.1",
2730
"cross-env": "5.0.1",
2831
"css-loader": "0.28.4",
32+
"enzyme": "2.9.1",
2933
"eslint": "4.1.1",
3034
"eslint-config-o2team": "0.1.6",
3135
"eslint-plugin-react": "7.1.0",
3236
"extract-text-webpack-plugin": "2.1.2",
37+
"jest": "20.0.4",
38+
"moxios": "0.4.0",
3339
"postcss-loader": "2.0.6",
40+
"react": "15.6.1",
41+
"react-dom": "15.6.1",
42+
"react-test-renderer": "15.6.1",
3443
"rimraf": "2.6.1",
44+
"sinon": "2.3.7",
3545
"style-loader": "0.18.2",
3646
"url-loader": "0.5.9",
3747
"webpack": "3.1.0",
@@ -46,5 +56,20 @@
4656
"preact": "8.1.0",
4757
"preact-compat": "3.16.0",
4858
"react-flip-move": "2.9.14"
59+
},
60+
"jest": {
61+
"transform": {
62+
"^.+\\.jsx?$": "babel-jest"
63+
},
64+
"moduleNameMapper": {
65+
"\\.(css|less|scss)$": "<rootDir>/__mocks__/style.js"
66+
},
67+
"moduleFileExtensions": [
68+
"js",
69+
"jsx"
70+
],
71+
"coveragePathIgnorePatterns": [
72+
"src/gitalk.jsx"
73+
]
4974
}
5075
}

src/__tests__/gitalk.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react'
2+
import { shallow } from 'enzyme'
3+
import moxios from 'moxios'
4+
5+
import '../../__mocks__/setup'
6+
import Gitalk from '../gitalk'
7+
import Comment from '../component/comment'
8+
import { axiosGithub } from '../util'
9+
10+
describe('Gitalk', function () {
11+
beforeEach(function () {
12+
moxios.install(axiosGithub)
13+
})
14+
afterEach(function () {
15+
moxios.uninstall(axiosGithub)
16+
})
17+
it('render', function (done) {
18+
const props = {}
19+
const wrapper = shallow(<Gitalk {...props} />)
20+
expect(wrapper.find('.gt-container')).toHaveLength(1)
21+
22+
moxios.wait(function () {
23+
wrapper.update()
24+
expect(wrapper.find(Comment)).toHaveLength(2)
25+
done()
26+
})
27+
})
28+
})

src/__tests__/util.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { queryParse, queryStringify, formatErrorMsg } from '../util'
2+
3+
describe('util', function () {
4+
const search = 'a=b&c=1'
5+
const searchObject = {
6+
a: 'b',
7+
c: '1'
8+
}
9+
10+
describe('queryParse', function () {
11+
it(search, function () {
12+
expect(queryParse(search)).toEqual(searchObject)
13+
})
14+
it(`?${search}`, function () {
15+
expect(queryParse(`?${search}`)).toEqual(searchObject)
16+
})
17+
})
18+
19+
describe('queryStringify', function () {
20+
it('object', function () {
21+
expect(queryStringify(searchObject)).toEqual(search)
22+
})
23+
})
24+
25+
describe('formatErrorMsg', function () {
26+
it('err.response', function () {
27+
expect(formatErrorMsg({
28+
response: {
29+
data: {
30+
message: 'm1',
31+
errors: [{
32+
message: 'm21'
33+
}, {
34+
message: 'm22'
35+
}]
36+
}
37+
}
38+
})).toEqual('Error: m1. m21, m22')
39+
})
40+
it('err.msg', function () {
41+
expect(formatErrorMsg({
42+
message: 'm1'
43+
})).toEqual('Error: m1')
44+
})
45+
})
46+
})

src/component/avatar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from 'react'
33
export default function Avatar (props) {
44
const src = props.src
55
let className = 'gt-avatar '
6-
props.className && (className+=props.className)
6+
props.className && (className += props.className)
77
return (
88
<div className={className}>
99
<img src={src} alt="头像"/>

src/component/avatar.spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react'
2+
import { shallow } from 'enzyme'
3+
4+
import Avatar from './avatar'
5+
6+
describe('Avatar', function () {
7+
it('set props className', function () {
8+
const className = 'class'
9+
expect(shallow(<Avatar className={className} />)
10+
.hasClass(`gt-avatar ${className}`)
11+
).toBe(true)
12+
})
13+
it('set props src', function () {
14+
const src = 'src'
15+
expect(shallow(<Avatar src={src} />)
16+
.find('img').prop('src')
17+
).toEqual(src)
18+
})
19+
})
20+

src/component/button.spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react'
2+
import { shallow } from 'enzyme'
3+
import sinon from 'sinon'
4+
5+
import Button from './button'
6+
7+
describe('Button', function () {
8+
it('set props className', function () {
9+
const className = 'class'
10+
expect(shallow(<Button className={className} />)
11+
.hasClass(className)
12+
).toBe(true)
13+
})
14+
it('set props text', function () {
15+
const text = 'text'
16+
expect(shallow(<Button text={text} />)
17+
.find('.gt-btn-text').text()
18+
).toEqual(text)
19+
})
20+
it('set props isLoading', function () {
21+
expect(shallow(<Button isLoading={true} />)
22+
.find('.gt-btn-loading').exists()
23+
).toBe(true)
24+
})
25+
it('set props onClick', function () {
26+
const onButtonClick = sinon.spy()
27+
const wrapper = shallow(<Button onClick={onButtonClick} />)
28+
wrapper.find('button').simulate('click')
29+
expect(onButtonClick.calledOnce).toBe(true)
30+
})
31+
})

src/component/comment.spec.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import React from 'react'
2+
import { shallow } from 'enzyme'
3+
4+
import Comment from './comment'
5+
import Avatar from './avatar'
6+
7+
const comment = {
8+
html_url: 'https://github.com/xxxx/xxxxx/issues/1#issuecomment-xxxxx',
9+
body_html: '<p>123</p>',
10+
created_at: '2017-06-30T09:01:19Z',
11+
user: {
12+
login: 'booxood',
13+
avatar_url: 'https://avatars0.githubusercontent.com/u/2151410?v=3',
14+
html_url: 'https://github.com/booxood'
15+
}
16+
}
17+
18+
describe('Comment', function () {
19+
it('render with no user', function () {
20+
const props = {
21+
comment
22+
}
23+
const wrapper = shallow(<Comment {...props} />)
24+
expect(wrapper.hasClass('gt-comment')).toBe(true)
25+
expect(wrapper.find(Avatar)).toHaveLength(1)
26+
expect(wrapper.find('.gt-comment-header')).toHaveLength(1)
27+
expect(wrapper.find('.gt-comment-username').prop('href')).toEqual(comment.user.html_url)
28+
expect(wrapper.find('.gt-comment-username').text()).toEqual(comment.user.login)
29+
expect(wrapper.find('.gt-comment-date').text()).toEqual(expect.stringMatching(/ago$/))
30+
expect(wrapper.find('.gt-comment-body').render().html()).toEqual(expect.stringContaining(comment.body_html))
31+
})
32+
33+
it('render with user but isn\'t creator', function () {
34+
const props = {
35+
comment,
36+
user: { login: 'hello' }
37+
}
38+
const wrapper = shallow(<Comment {...props} />)
39+
expect(wrapper.find('.gt-comment-edit')).toHaveLength(0)
40+
})
41+
42+
it('render with user is creator', function () {
43+
const props = {
44+
comment,
45+
user: { login: 'booxood' }
46+
}
47+
const wrapper = shallow(<Comment {...props} />)
48+
expect(wrapper.find('.gt-comment-edit')).toHaveLength(1)
49+
})
50+
51+
it('render with creator isn\'t admin', function () {
52+
const props = {
53+
comment,
54+
admin: ['hello']
55+
}
56+
const wrapper = shallow(<Comment {...props} />)
57+
expect(wrapper.hasClass('gt-comment-admin')).toBe(false)
58+
})
59+
60+
it('render with creator is admin', function () {
61+
const props = {
62+
comment,
63+
admin: ['booxood', 'hello']
64+
}
65+
const wrapper = shallow(<Comment {...props} />)
66+
expect(wrapper.hasClass('gt-comment-admin')).toBe(true)
67+
})
68+
69+
it('set props commentedText', function () {
70+
const commentedText = 'commentedText'
71+
const props = {
72+
comment,
73+
commentedText
74+
}
75+
const wrapper = shallow(<Comment {...props} />)
76+
expect(wrapper.find('.gt-comment-text').text()).toEqual(commentedText)
77+
})
78+
79+
it('set props language=zh-TW', function () {
80+
const props = {
81+
comment,
82+
language: 'zh-TW'
83+
}
84+
const wrapper = shallow(<Comment {...props} />)
85+
expect(wrapper.find('.gt-comment-date').text()).toEqual(expect.stringContaining('前'))
86+
})
87+
})

src/util.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const queryParse = (search = window.location.search) => {
88
.split('&')
99
.forEach(queryStr => {
1010
const [key, value] = queryStr.split('=')
11+
/* istanbul ignore else */
1112
if (key) query[decodeURIComponent(key)] = decodeURIComponent(value)
1213
})
1314

@@ -17,7 +18,7 @@ export const queryParse = (search = window.location.search) => {
1718
export const queryStringify = query => {
1819
const queryString = Object.keys(query)
1920
.map(key => `${key}=${encodeURIComponent(query[key] || '')}`)
20-
.join('&') || ''
21+
.join('&')
2122
return queryString
2223
}
2324

@@ -36,6 +37,7 @@ export const axiosGithub = axios.create({
3637

3738
export const getMetaContent = (name, content = 'content') => {
3839
const el = document.querySelector(`meta[name='${name}']`)
40+
/* istanbul ignore next */
3941
return el && el.getAttribute(content)
4042
}
4143

0 commit comments

Comments
 (0)