Commit 2d1148eb authored by 偏右's avatar 偏右 Committed by GitHub

Add UI Test (#10)

* Add jest and enzyme

* Add test for connected component

* fix lint

* update travis

* Add e2e test

* fix ci

* Add e2e test

* update travis.yml

* Fix global jasmine timeout

* update test scripts

* fix jest glob patterns

* short timeout

* fix travis

* uitest => unit-test

* Add ls in travis.yml

* use electron on travis

https://github.com/segmentio/nightmare/issues/313#issuecomment-152274351

* clear travis.yml

* change setup file name

* ignore coverage

* unit-test => unit

* remove helpers/visit

* update test script

* clean up test scripts

* ignore test case
parent 3357ffbb
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
"env": { "env": {
"browser": true, "browser": true,
"node": true, "node": true,
"es6": true "es6": true,
"mocha": true,
"jasmine": true
}, },
"rules": { "rules": {
"generator-star-spacing": [0], "generator-star-spacing": [0],
......
...@@ -11,3 +11,5 @@ ...@@ -11,3 +11,5 @@
# misc # misc
.DS_Store .DS_Store
npm-debug.log* npm-debug.log*
/coverage
...@@ -2,3 +2,32 @@ language: node_js ...@@ -2,3 +2,32 @@ language: node_js
node_js: node_js:
- "8" - "8"
env:
matrix:
- TEST_TYPE=lint
- TEST_TYPE=test-all
- TEST_TYPE=test-dist
addons:
apt:
packages:
- xvfb
install:
- export DISPLAY=':99.0'
- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- npm install
script:
- |
if [ "$TEST_TYPE" = lint ]; then
npm run lint
elif [ "$TEST_TYPE" = test-all ]; then
npm run test:all
elif [ "$TEST_TYPE" = test-dist ]; then
npm run site
mv dist/* ./
php -S localhost:8000 &
npm test .e2e.js
fi
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
"scripts": { "scripts": {
"start": "roadhog server", "start": "roadhog server",
"build": "roadhog build", "build": "roadhog build",
"lint": "eslint --ext .js src test mock", "lint": "eslint --ext .js src mock tests",
"test": "npm run lint",
"precommit": "npm run lint", "precommit": "npm run lint",
"site": "roadhog-api-doc static" "site": "roadhog-api-doc static",
"test": "jest",
"test:all": "node ./tests/run-tests.js"
}, },
"dependencies": { "dependencies": {
"antd": "next", "antd": "next",
...@@ -25,11 +26,14 @@ ...@@ -25,11 +26,14 @@
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^7.1.1", "babel-eslint": "^7.1.1",
"babel-jest": "^21.0.0",
"babel-plugin-dva-hmr": "^0.3.2", "babel-plugin-dva-hmr": "^0.3.2",
"babel-plugin-import": "^1.2.1", "babel-plugin-import": "^1.2.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.9.0", "babel-plugin-transform-runtime": "^6.9.0",
"babel-runtime": "^6.9.2", "babel-runtime": "^6.9.2",
"cross-port-killer": "^1.0.1",
"enzyme": "^2.9.1",
"eslint": "^3.0.0", "eslint": "^3.0.0",
"eslint-config-airbnb": "latest", "eslint-config-airbnb": "latest",
"eslint-plugin-babel": "^4.0.0", "eslint-plugin-babel": "^4.0.0",
...@@ -39,9 +43,38 @@ ...@@ -39,9 +43,38 @@
"eslint-plugin-react": "^7.0.1", "eslint-plugin-react": "^7.0.1",
"gh-pages": "^1.0.0", "gh-pages": "^1.0.0",
"husky": "^0.13.4", "husky": "^0.13.4",
"jest": "^21.0.1",
"mockjs": "^1.0.1-beta3", "mockjs": "^1.0.1-beta3",
"nightmare": "^2.10.0",
"react-test-renderer": "^15.6.1",
"redbox-react": "^1.3.2", "redbox-react": "^1.3.2",
"roadhog": "^1.0.2", "roadhog": "^1.0.2",
"roadhog-api-doc": "^0.1.5" "roadhog-api-doc": "^0.1.5"
},
"babel": {
"presets": [
"es2015",
"stage-0",
"react"
],
"plugins": [
"transform-decorators-legacy"
]
},
"jest": {
"setupFiles": [
"<rootDir>/tests/setupTests.js"
],
"testMatch": [
"**/?(*.)(spec|test|e2e).js?(x)"
],
"setupTestFrameworkScriptFile": "<rootDir>/tests/jasmine.js",
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleNameMapper": {
"\\.(css|less)$": "<rootDir>/tests/styleMock.js"
}
} }
} }
...@@ -3,7 +3,9 @@ import classNames from 'classnames'; ...@@ -3,7 +3,9 @@ import classNames from 'classnames';
import { Icon } from 'antd'; import { Icon } from 'antd';
import styles from './index.less'; import styles from './index.less';
export default ({ className, type, title, description, extra, actions, ...restProps }) => { export default function Result({
className, type, title, description, extra, actions, ...restProps
}) {
const iconMap = { const iconMap = {
error: <Icon className={styles.error} type="close-circle" />, error: <Icon className={styles.error} type="close-circle" />,
success: <Icon className={styles.success} type="check-circle" />, success: <Icon className={styles.success} type="check-circle" />,
...@@ -18,4 +20,4 @@ export default ({ className, type, title, description, extra, actions, ...restPr ...@@ -18,4 +20,4 @@ export default ({ className, type, title, description, extra, actions, ...restPr
{actions && <div className={styles.actions}>{actions}</div>} {actions && <div className={styles.actions}>{actions}</div>}
</div> </div>
); );
}; }
import Nightmare from 'nightmare';
describe('Homepage', () => {
it('it should have logo text', async () => {
const page = Nightmare().goto('http://localhost:8000');
const text = await page.evaluate(() => document.body.innerHTML).end();
expect(text).toContain('<h1>Ant Design Pro</h1>');
});
});
import Nightmare from 'nightmare';
describe('Login', () => {
let page;
beforeEach(() => {
page = Nightmare();
page.goto('http://localhost:8000/#/user/login');
});
it('should login with failure', async () => {
await page.type('#userName', 'mockuser')
.type('#password', 'wrong_password')
.click('button[type="submit"]')
.wait('.ant-alert-error') // should display error
.end();
});
xit('should login successfully', async () => {
const text = await page.type('#userName', 'admin')
.type('#password', '888888')
.click('button[type="submit"]')
.wait('.ant-layout-sider h1') // should display error
.evaluate(() => document.body.innerHTML)
.end();
expect(text).toContain('<h1>Ant Design Pro</h1>');
});
});
import React from 'react';
import { shallow } from 'enzyme';
import Dashboard from './Dashboard';
it('renders Dashboard', () => {
const wrapper = shallow(
<Dashboard.WrappedComponent user={{ list: [] }} />
);
expect(wrapper.find('Table').props().dataSource).toEqual([]);
});
import React from 'react';
import { shallow } from 'enzyme';
import Success from './Success';
it('renders with Result', () => {
const wrapper = shallow(<Success />);
expect(wrapper.find('Result').length).toBe(1);
expect(wrapper.find('Result').prop('type')).toBe('success');
});
import moment from 'moment'; import moment from 'moment';
function fixedZero(val) { export function fixedZero(val) {
return val * 1 < 10 ? `0${val}` : val; return val * 1 < 10 ? `0${val}` : val;
} }
function getTimeDistance(type) { export function getTimeDistance(type) {
const now = new Date(); const now = new Date();
const oneDay = 1000 * 60 * 60 * 24; const oneDay = 1000 * 60 * 60 * 24;
...@@ -48,8 +48,3 @@ function getTimeDistance(type) { ...@@ -48,8 +48,3 @@ function getTimeDistance(type) {
return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)]; return [moment(`${year}-01-01 00:00:00`), moment(`${year}-12-31 23:59:59`)];
} }
} }
export default {
fixedZero,
getTimeDistance,
};
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
const { spawn } = require('child_process');
const { kill } = require('cross-port-killer');
const env = Object.create(process.env);
env.BROWSER = 'none';
const startServer = spawn('npm', ['start'], {
env,
});
startServer.stderr.on('data', (data) => {
// eslint-disable-next-line
console.log(data);
});
startServer.on('exit', () => {
kill(process.env.PORT || 8000);
});
// eslint-disable-next-line
console.log('Starting development server for e2e tests...');
startServer.stdout.on('data', (data) => {
if (data.toString().indexOf('The app is running at') >= 0) {
// eslint-disable-next-line
console.log('Development server is started, ready to run tests.');
const testCmd = spawn('npm', ['run', 'jest'], {
stdio: 'inherit',
});
testCmd.on('exit', () => {
startServer.kill();
});
}
});
import { jsdom } from 'jsdom';
// fixed jsdom miss
const documentHTML = '<!doctype html><html><body><div id="root"></div></body></html>';
global.document = jsdom(documentHTML);
global.window = document.defaultView;
global.navigator = global.window.navigator;
global.requestAnimationFrame = global.requestAnimationFrame || function requestAnimationFrame(cb) {
return setTimeout(cb, 0);
};
module.exports = {};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment