Skip to content

Commit 924b13a

Browse files
committed
add ui tests
1 parent dafea86 commit 924b13a

File tree

11 files changed

+644
-43
lines changed

11 files changed

+644
-43
lines changed

gulpfile.js

Lines changed: 116 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,69 @@
11
/*eslint-disable no-var, one-var, func-names, indent, prefer-arrow-callback, object-shorthand, no-console, newline-per-chained-call, one-var-declaration-per-line, prefer-template, vars-on-top */
2+
var path = require('path');
3+
var exec = require('child_process').exec;
4+
var gulp = require('gulp'),
5+
$ = require('gulp-load-plugins')(),
6+
browserify = require('browserify'),
7+
buffer = require('vinyl-buffer'),
8+
del = require('del'),
9+
runSequence = require('run-sequence'),
10+
source = require('vinyl-source-stream'),
11+
watchify = require('watchify');
212

3-
var gulp = require('gulp'),
4-
$ = require('gulp-load-plugins')(),
5-
del = require('del'),
6-
runSequence = require('run-sequence');
13+
var shouldWatch = false;
14+
15+
function watchifyTask(options) {
16+
var bundler, rebundle, iteration = 0;
17+
bundler = browserify({
18+
entries: path.join(__dirname, '/test/demo/main.js'),
19+
basedir: __dirname,
20+
insertGlobals: false, // options.watch
21+
cache: {},
22+
// debug: options.watch,
23+
packageCache: {},
24+
fullPaths: false, // options.watch
25+
transform: [['babelify']],
26+
extensions: ['.jsx']
27+
});
28+
29+
if (options.watch) {
30+
bundler = watchify(bundler);
31+
}
32+
33+
rebundle = function() {
34+
var stream = bundler.bundle();
35+
36+
if (options.watch) {
37+
stream.on('error', function(err) {
38+
console.log(err);
39+
});
40+
}
41+
42+
stream
43+
.pipe(source('bundle.js'))
44+
.pipe(buffer())
45+
.pipe(gulp.dest('.tmp'))
46+
.pipe($.tap(function() {
47+
if (iteration === 0 && options.cb) {
48+
options.cb();
49+
}
50+
iteration++;
51+
}))
52+
.pipe($.connect.reload());
53+
};
54+
55+
bundler.on('update', rebundle);
56+
return rebundle();
57+
}
758

859
gulp.task('scripts', function() {
9-
return gulp.src('src/scripts/**/*')
60+
return gulp.src('demo/scripts/**/*')
1061
.pipe($.babel())
1162
.pipe(gulp.dest('lib/scripts'));
1263
});
1364

1465
gulp.task('lint', function() {
15-
return gulp.src('src/scripts/**/*')
66+
return gulp.src('demo/scripts/**/*')
1667
.pipe($.eslint({
1768
useEslintrc: true,
1869
rules: {
@@ -24,7 +75,7 @@ gulp.task('lint', function() {
2475
});
2576

2677
gulp.task('styles', function() {
27-
return gulp.src('src/styles/*.scss')
78+
return gulp.src('demo/styles/*.scss')
2879
.pipe(gulp.dest('lib/styles'))
2980
.pipe($.plumber())
3081
.pipe($.sass.sync({
@@ -41,7 +92,7 @@ gulp.task('clean', function(cb) {
4192
});
4293

4394
gulp.task('watch', ['build'], function() {
44-
gulp.watch('src/**/*', function() {
95+
gulp.watch('demo/**/*', function() {
4596
gulp.start('scripts');
4697
});
4798
});
@@ -51,4 +102,61 @@ gulp.task('build', ['clean'], function(cb) {
51102
runSequence('lint', 'scripts', 'styles', cb);
52103
});
53104

105+
gulp.task('localserver', function(cb) {
106+
shouldWatch = true;
107+
108+
gulp.watch(['demo/styles/*', 'test/demo/*.scss'], function() {
109+
gulp.start('styles:test');
110+
});
111+
112+
return runSequence('setup:test', cb);
113+
});
114+
115+
gulp.task('setup:test', ['scripts:test', 'styles:test'], function() {
116+
gulp.src('test/demo/index.html')
117+
.pipe(gulp.dest('.tmp'));
118+
119+
return $.connect.server({
120+
root: [path.join(__dirname, '.tmp/')],
121+
livereload: true,
122+
port: 8888
123+
});
124+
});
125+
126+
gulp.task('scripts:test', function(cb) {
127+
return watchifyTask({
128+
watch: shouldWatch,
129+
cb: cb
130+
});
131+
});
132+
133+
gulp.task('styles:test', function() {
134+
return gulp.src('test/demo/main.scss')
135+
.pipe($.plumber())
136+
.pipe($.sass.sync({
137+
precision: 4
138+
}).on('error', $.sass.logError))
139+
.pipe($.plumber.stop())
140+
.pipe($.autoprefixer())
141+
.pipe($.rename({ basename: 'bundle' }))
142+
.pipe(gulp.dest('.tmp'))
143+
.pipe($.connect.reload());
144+
});
145+
146+
gulp.task('test:ui', ['setup:test'], function(cb) {
147+
exec('./node_modules/.bin/nightwatch -c test/nightwatch.conf.js', function(error, stdout) {
148+
$.connect.serverClose();
149+
console.log(stdout);
150+
151+
if (error) {
152+
console.error(`exec error: ${error}`);
153+
process.exit(1);
154+
return;
155+
}
156+
157+
process.exit(0);
158+
cb();
159+
});
160+
});
161+
54162
gulp.task('default', ['build']);

package.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"tour"
2323
],
2424
"dependencies": {
25+
"nested-property": "^0.0.6",
2526
"react-autobind": "^1.0",
2627
"scroll": "^2.0"
2728
},
@@ -41,7 +42,12 @@
4142
"babel-preset-react": "^6.5",
4243
"babel-preset-stage-1": "^6.5",
4344
"babel-register": "^6.9",
45+
"babelify": "^7.3",
46+
"bootstrap": "^4.0.0-alpha",
47+
"browserify": "^13.0",
48+
"chromedriver": "^2.21",
4449
"del": "^2.2",
50+
"enzyme": "^2.4",
4551
"eslint": "^2.13",
4652
"eslint-config-airbnb": "^9.0",
4753
"eslint-plugin-import": "^1.9",
@@ -51,26 +57,34 @@
5157
"gulp": "^3.9",
5258
"gulp-autoprefixer": "^3.1",
5359
"gulp-babel": "^6.1",
60+
"gulp-connect": "^4.1",
5461
"gulp-eslint": "^2.0",
5562
"gulp-load-plugins": "^1.2",
5663
"gulp-plumber": "^1.1",
5764
"gulp-rename": "^1.2",
5865
"gulp-sass": "^2.3",
66+
"gulp-tap": "^0.1",
5967
"jsdom": "^9.2",
6068
"mocha": "^2.5",
69+
"nightwatch": "^0.9",
6170
"react": "^15.1",
6271
"react-addons-test-utils": "^15.1",
6372
"react-dom": "^15.1",
64-
"run-sequence": "^1.2"
73+
"run-sequence": "^1.2",
74+
"selenium-server-standalone-jar": "^2.53",
75+
"vinyl-buffer": "^1.0",
76+
"vinyl-source-stream": "^1.1",
77+
"watchify": "^3.7"
6578
},
6679
"scripts": {
6780
"lint": "eslint src test",
6881
"build": "gulp build",
6982
"prepublish": "npm run build",
70-
"test": "./node_modules/.bin/_mocha --compilers js:babel-register --recursive --require ./test/setup.js"
83+
"test": "npm run test:ui",
84+
"test:ui": "gulp localserver & nightwatch -c test/nightwatch.js; kill %1"
7185
},
7286
"engines": {
73-
"node": ">=5.0.0",
87+
"node": ">=6.0.0",
7488
"npm": ">=3.0.0"
7589
}
7690
}

test/component.spec.js

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,13 @@
11
import expect from 'expect';
22
import React from 'react';
3-
import TestUtils from 'react-addons-test-utils';
3+
import { render } from 'enzyme';
44

5-
import Joyride from '../src/scripts/Joyride';
6-
7-
function setup() {
8-
const props = {
9-
steps: [
10-
{
11-
title: 'Auto Scroll',
12-
text: 'Scroll to correct position if required. <i>It can be turned off</i>',
13-
selector: '#area-chart',
14-
position: 'top'
15-
},
16-
{
17-
title: 'Hide Elements',
18-
text: 'You can really customize the UI',
19-
textAlign: 'center',
20-
selector: '#donut-chart',
21-
position: 'left'
22-
}
23-
]
24-
};
25-
26-
return TestUtils.renderIntoDocument(
27-
<Joyride {...props} />
28-
);
29-
}
5+
import Demo from './demo/App';
306

317
describe('Joyride', () => {
32-
const render = setup();
8+
const demo = render(<Demo />);
339

34-
it('should be a Component', () => {
35-
expect(TestUtils.isCompositeComponent(render)).toBe(true);
10+
it('should be able to start', () => {
11+
expect(demo.find('.joyride').length).toEqual(1);
3612
});
3713
});

test/demo/App.jsx

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import React from 'react';
2+
import Joyride from '../../src/scripts/Joyride';
3+
4+
export default class Demo extends React.Component {
5+
constructor(props) {
6+
super(props);
7+
8+
this.state = {
9+
running: false,
10+
steps: [
11+
{
12+
title: 'Our Projects',
13+
text: 'Ooops. I forgot to add images!',
14+
textAlign: 'center',
15+
selector: '.projects h2 span',
16+
position: 'right',
17+
style: {
18+
beacon: {
19+
offsetX: 30
20+
}
21+
}
22+
},
23+
{
24+
title: 'Our Mission',
25+
text: 'Or some other marketing bullshit terms',
26+
selector: '.mission h2 span',
27+
position: 'bottom',
28+
style: {
29+
beacon: {
30+
offsetY: 20
31+
}
32+
}
33+
},
34+
{
35+
title: 'About Us',
36+
text: 'We are the people',
37+
selector: '.about h2 span',
38+
position: 'left',
39+
style: {
40+
beacon: {
41+
offsetX: 15
42+
}
43+
}
44+
}
45+
]
46+
};
47+
48+
this.onClickStart = this.onClickStart.bind(this);
49+
}
50+
51+
componentDidMount() {
52+
this.refs.joyride.addTooltip({
53+
title: 'The classic joyride',
54+
text: "Let's go on a magical tour",
55+
selector: '.hero h3 span',
56+
position: 'bottom',
57+
event: 'hover',
58+
style: {
59+
backgroundColor: 'rgba(0, 0, 0, 0.8)',
60+
borderRadius: 0,
61+
color: '#fff',
62+
mainColor: '#ff67b4',
63+
textAlign: 'center',
64+
width: '20rem'
65+
}
66+
});
67+
}
68+
69+
onClickStart(e) {
70+
const state = this.state;
71+
e.preventDefault();
72+
73+
if (!state.running && state.steps.length) {
74+
this.setState({
75+
running: true
76+
});
77+
78+
this.refs.joyride.start();
79+
return;
80+
}
81+
82+
this.refs.joyride.reset(true);
83+
}
84+
85+
render() {
86+
return (
87+
<div className="demo">
88+
<Joyride
89+
ref="joyride"
90+
steps={this.state.steps}
91+
scrollToFirstStep={true}
92+
debug={false} />
93+
<div className="hero">
94+
<div className="container">
95+
<h1>My super awesome catchy title</h1>
96+
<h3><span>Let's Talk?</span><a href="#" onClick={this.onClickStart}>&raquo;</a></h3>
97+
</div>
98+
</div>
99+
<div className="site__section projects">
100+
<div className="container">
101+
<h2><span>Projects</span></h2>
102+
</div>
103+
</div>
104+
105+
<div className="site__section mission">
106+
<div className="container">
107+
<h2><span>Mission</span></h2>
108+
</div>
109+
</div>
110+
<div className="site__section about">
111+
<div className="container">
112+
<h2><span>About</span></h2>
113+
</div>
114+
</div>
115+
</div>
116+
);
117+
}
118+
}

test/demo/index.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>React Joyride</title>
6+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"/>
7+
<meta name="description" content="Create tooltips, walkthroughs and guided tours for your ReactJS apps. Now with standalone tooltips!"/>
8+
<link rel="stylesheet" href="bundle.css">
9+
</head>
10+
<body>
11+
<div id="react"></div>
12+
<script src="bundle.js"></script>
13+
</body>
14+
</html>

test/demo/main.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import App from './App';
4+
5+
document.addEventListener('DOMContentLoaded', () => {
6+
ReactDOM.render(<App />, document.getElementById('react'));
7+
});

0 commit comments

Comments
 (0)