Skip to content
This repository was archived by the owner on Jul 14, 2020. It is now read-only.

Commit 853bfd9

Browse files
authored
Add Karma example (& fix date mocking bug) (#3)
* Add Karma example * Remove testing check in webpack config for Karma example * Update to latest `@bigtest/convergence` to fix date mocking issue This also updates `@bigtest/interactor` & `@bigtest/mocha` since they both rely on `@bigtest/convergence`.
1 parent e667a30 commit 853bfd9

35 files changed

+10788
-16
lines changed

react/countdown-karma/.babelrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"presets": [
3+
["@babel/env", {
4+
"modules": false
5+
}],
6+
"@babel/react",
7+
["@babel/stage-2", {
8+
"decoratorsLegacy": true
9+
}]
10+
]
11+
}

react/countdown-karma/.postcssrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"plugins": {
3+
"autoprefixer": true,
4+
"precss": true
5+
}
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import '@babel/polyfill';
2+
3+
// other setup could be done here too, such as registering chai helpers
4+
5+
// we import our tests using webpack's require.context
6+
const requireTest = require.context('.', true, /-test/);
7+
requireTest.keys().forEach(requireTest);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { interactor, text } from '@bigtest/interactor';
2+
3+
export default @interactor class CountdownInteractor {
4+
static defaultScope = '[data-test-countdown]';
5+
years = text('[data-test-countdown-unit="years"]');
6+
months = text('[data-test-countdown-unit="months"]');
7+
days = text('[data-test-countdown-unit="days"]');
8+
hours = text('[data-test-countdown-unit="hours"]');
9+
minutes = text('[data-test-countdown-unit="minutes"]');
10+
seconds = text('[data-test-countdown-unit="seconds"]');
11+
milliseconds = text('[data-test-countdown-unit="milliseconds"]');
12+
direction = text('[data-test-countdown-direction]');
13+
target = text('[data-test-countdown-target]');
14+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { interactor, scoped } from '@bigtest/interactor';
2+
import SpinnerInteractor from './spinner';
3+
4+
export default @interactor class DateFormInteractor {
5+
// the default scope allows us to omit the selector when calling `new`
6+
static defaultScope = '[data-test-date-form]';
7+
8+
// interactors are composable and nested methods return an instance
9+
// of the top-most interactor for chaining
10+
year = scoped('[data-test-year-field]', SpinnerInteractor);
11+
month = scoped('[data-test-month-field]', SpinnerInteractor);
12+
day = scoped('[data-test-day-field]', SpinnerInteractor);
13+
hour = scoped('[data-test-hour-field]', SpinnerInteractor);
14+
minute = scoped('[data-test-minute-field]', SpinnerInteractor);
15+
submit = scoped('button[type="submit"]');
16+
17+
// getters can also be used for computed properties
18+
get value() {
19+
let year = this.year.value;
20+
let month = parseInt(this.month.value, 10) + 1;
21+
let day = this.day.value;
22+
let hour = this.hour.value.padStart(2, '0');
23+
let minute = this.minute.value.padStart(2, '0');
24+
25+
return `${year}/${month}/${day} @ ${hour}:${minute}`;
26+
}
27+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { interactor, clickable, value } from '@bigtest/interactor';
2+
3+
export default @interactor class SpinnerInteractor {
4+
// common helpers provide easy to define interactions
5+
prev = clickable('[data-test-spinner-option="prev"]');
6+
next = clickable('[data-test-spinner-option="next"]');
7+
value = value('input');
8+
9+
// complex interactions can be expressed as methods
10+
select(option) {
11+
let self = this;
12+
13+
// for each letter in `option`, send a keypress event
14+
// that will trigger the spinner's typeahead feature
15+
for (let key of option) {
16+
self = self.trigger('keypress', {
17+
charCode: key.charCodeAt()
18+
});
19+
}
20+
21+
// methods that return a new instance of itself are chainable
22+
return self;
23+
}
24+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { describe, beforeEach, it } from '@bigtest/mocha';
2+
import { travel } from 'timekeeper';
3+
import { expect } from 'chai';
4+
5+
import { setupApplicationForTesting, visit, location } from './helpers';
6+
import CountdownInteractor from '../interactors/countdown';
7+
8+
describe('Countdown', () => {
9+
const countdown = new CountdownInteractor();
10+
11+
setupApplicationForTesting();
12+
13+
describe('with a date in the future', () => {
14+
beforeEach(() => visit('/2019/1/2'));
15+
16+
it('displays the difference of time', () => {
17+
expect(countdown.years).to.equal('1');
18+
});
19+
20+
it('displays "until" and the target date', () => {
21+
expect(countdown.direction).to.equal('Until');
22+
expect(countdown.target).to.equal('January 2, 2019');
23+
});
24+
});
25+
26+
describe('with a date in the past', () => {
27+
beforeEach(() => {
28+
travel(new Date([2018, 1, 2]));
29+
visit('/2017/1/1');
30+
});
31+
32+
it('displays the difference of time', () => {
33+
expect(countdown.years).to.equal('1');
34+
});
35+
36+
it('displays "since" and the target date', () => {
37+
expect(countdown.direction).to.equal('Since');
38+
expect(countdown.target).to.equal('January 1, 2017');
39+
});
40+
});
41+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { before, beforeEach } from '@bigtest/mocha';
2+
import { setupAppForTesting } from '@bigtest/react';
3+
import { freeze } from 'timekeeper';
4+
import App from '../../src/app';
5+
6+
export { visit, location } from '@bigtest/react';
7+
8+
export function setupApplicationForTesting() {
9+
before(() => freeze(new Date([2018, 1, 1])));
10+
11+
beforeEach(async function() {
12+
this.app = await setupAppForTesting(App, {
13+
mountId: 'root'
14+
});
15+
});
16+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { describe, beforeEach, it } from '@bigtest/mocha';
2+
import { expect } from 'chai';
3+
4+
import { setupApplicationForTesting, location } from './helpers';
5+
import DateFormInteractor from '../interactors/form';
6+
7+
describe('Date Picker', () => {
8+
const form = new DateFormInteractor();
9+
setupApplicationForTesting();
10+
11+
it('has fields for year, month, day, hour, and minute', () => {
12+
expect(form.year.isPresent).to.be.true;
13+
expect(form.month.isPresent).to.be.true;
14+
expect(form.day.isPresent).to.be.true;
15+
expect(form.hour.isPresent).to.be.true;
16+
expect(form.minute.isPresent).to.be.true;
17+
});
18+
19+
it('defaults to today\'s date', () => {
20+
expect(form.value).to.equal('2018/1/1 @ 00:00');
21+
});
22+
23+
it('has a submit button', () => {
24+
expect(form.submit.isPresent).to.be.true;
25+
});
26+
27+
describe('selecting a date in the future', () => {
28+
beforeEach(async () => {
29+
await form.year.next();
30+
});
31+
32+
it('displays a "get countdown" submit button', () => {
33+
expect(form.submit.text).to.equal('Get Countdown');
34+
});
35+
});
36+
37+
describe('selecting a date in the past', () => {
38+
beforeEach(async () => {
39+
await form.year.prev();
40+
});
41+
42+
it('displays a "get elapsed" submit button', () => {
43+
expect(form.submit.text).to.equal('Get Elapsed');
44+
});
45+
});
46+
47+
describe('submitting a date', () => {
48+
beforeEach(async () => {
49+
await form.submit.click();
50+
});
51+
52+
it('goes to the date countdown', () => {
53+
expect(location().pathname).to.equal('/2018/01/01');
54+
});
55+
});
56+
57+
describe('submitting a date and time', () => {
58+
beforeEach(async () => {
59+
await form
60+
.year.select('2019')
61+
.hour.select('12')
62+
.minute.select('30')
63+
.submit.click();
64+
});
65+
66+
it('includes the time in the URL', () => {
67+
expect(location().pathname).to.equal('/2019/01/01/12:30');
68+
});
69+
});
70+
});

react/countdown-karma/karma.conf.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module.exports = config => {
2+
config.set({
3+
frameworks: ["mocha"], // sets up the Mocha framework automatically
4+
reporters: ["mocha"], // reports back to the CLI formatted like Mocha
5+
browsers: ["Chrome"], // automatically launches chrome to run our tests
6+
7+
files: [
8+
// karma-webpack will watch our files
9+
{ pattern: "bigtest/index.js", watched: false }
10+
],
11+
12+
preprocessors: {
13+
// tells Karma that we'll be using Webpack to process this file
14+
"bigtest/index.js": ["webpack"]
15+
},
16+
17+
// Mocha reporter options
18+
mochaReporter: {
19+
showDiff: true
20+
},
21+
22+
// our webpack config exports a function
23+
webpack: require("./webpack.config")(),
24+
25+
// webpack dev middleware options
26+
webpackMiddleware: {
27+
stats: "minimal"
28+
}
29+
30+
// for more Karma config options, check out the documentation
31+
// http://karma-runner.github.io/2.0/config/configuration-file.html
32+
});
33+
};

0 commit comments

Comments
 (0)