Skip to content

Commit b148acb

Browse files
andyfry01appleboy
authored andcommitted
Expanding unit test suite (#223)
* updated documentation to include available and default props for component * added testing libraries to dev dependencies * added unit tests, added window mocking via JSDOM * added test:watch script to package.json * replaced tabs with spaces * yarn.lock update * deleting package-lock.json, created in error * readme update, added info on supported node version * dropping node v4 and v5 support and CI tests
1 parent 8388d6a commit b148acb

File tree

5 files changed

+1036
-107
lines changed

5 files changed

+1036
-107
lines changed

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ sudo: false
33
language: node_js
44

55
node_js:
6-
- '4'
7-
- '5'
86
- '6'
97
- '7'
108
- '8'

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ $ npm start
4242

4343
open the `http://localhost:3000` in your browser.
4444

45+
# Node support
46+
47+
Node >= v6 is required for this package. Run `node -v` in your command prompt if you're unsure which Node version you have installed.
48+
4549
### Automatically render the reCAPTCHA widget
4650

4751
Html example code:

__tests__/recaptcha-test.js

Lines changed: 176 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,182 @@
1-
jest.dontMock('../src/index');
1+
// Mock grecaptcha, see below
2+
const grecaptchaMock = {
3+
reset: function() {
4+
return true
5+
},
6+
render: function() {
7+
return true
8+
}
9+
}
210

11+
// JSDOM configuration (should be done before requiring anything else, see: http://airbnb.io/enzyme/docs/guides/jsdom.html)
12+
const {JSDOM} = require('jsdom');
13+
const jsdom = new JSDOM('<!doctype html><html><body></body></html>');
14+
const {window} = jsdom;
15+
// set grecaptchaMock as a property on JSDOM window, will now be accessable by component when rendered in tests
16+
window.grecaptcha = grecaptchaMock
17+
18+
function copyProps(src, target) {
19+
const props = Object.getOwnPropertyNames(src).filter(prop => typeof target[prop] === 'undefined').reduce((result, prop) => ({
20+
...result,
21+
[prop]: Object.getOwnPropertyDescriptor(src, prop)
22+
}), {});
23+
Object.defineProperties(target, props);
24+
}
25+
26+
global.window = window;
27+
global.document = window.document;
28+
global.navigator = {
29+
userAgent: 'node.js'
30+
};
31+
copyProps(window, global);
32+
33+
// Import React, test utils, component
334
import React from 'react';
435
import ReactTestUtils from 'react-dom/test-utils';
536
import Recaptcha from '../src/index';
37+
import sinon from 'sinon';
38+
39+
// Lodash for deep equality testing
40+
import _ from 'lodash'
41+
42+
// Import enzyme and configure for React 15
43+
import Adapter from 'enzyme-adapter-react-15';
44+
import {configure, render, mount} from 'enzyme';
45+
configure({adapter: new Adapter()});
46+
47+
// Test method for test props
48+
function testFunction() {
49+
return true
50+
}
51+
52+
// Test props with all props specified
53+
const testProps = {
54+
className: 'testClass',
55+
onloadCallbackName: 'testCallBackName',
56+
elementID: 'testElementID',
57+
onloadCallback: testFunction,
58+
verifyCallback: testFunction,
59+
expiredCallback: testFunction,
60+
render: 'testRender',
61+
sitekey: 'testSitekey',
62+
theme: 'testTheme',
63+
type: 'testType',
64+
verifyCallbackName: 'testVerifyCallbackName',
65+
expiredCallbackName: 'testExpiredCallbackName',
66+
size: 'testSize',
67+
tabindex: 'testTabindex',
68+
hl: 'testHl',
69+
badge: 'testBadge'
70+
};
71+
72+
73+
/* ----------
74+
Test cases!
75+
---------- */
676

777
describe('Recaptcha Test', () => {
8-
it('should exists', () => {
9-
// Render into document
10-
let recaptcha = ReactTestUtils.renderIntoDocument(<Recaptcha sitekey="123456789" />);
11-
expect(ReactTestUtils.isCompositeComponent(recaptcha)).toBeTruthy();
12-
});
13-
});
78+
describe('Recaptcha component', () => {
79+
it('should exist', () => {
80+
// Render into document
81+
let recaptcha = ReactTestUtils.renderIntoDocument(<Recaptcha sitekey="123456789"/>);
82+
expect(ReactTestUtils.isCompositeComponent(recaptcha)).toBeTruthy();
83+
});
84+
it('should mount successfully', () => {
85+
const component = mount(<Recaptcha />);
86+
let actual = component.length
87+
let expected = 1
88+
expect(actual).toEqual(expected)
89+
})
90+
})
91+
92+
describe('Component props', () => {
93+
it('should render props correctly', () => {
94+
const component = mount(<Recaptcha {...testProps} />)
95+
let componentProps = component.props()
96+
let actual = _.isEqual(componentProps, testProps)
97+
let expected = true
98+
expect(actual).toEqual(expected)
99+
})
100+
it('should render default props for the component\'s specified default props', () => {
101+
const component = mount(<Recaptcha />)
102+
let componentProps = component.props()
103+
let actual = _.isEqual(Recaptcha.defaultProps, componentProps)
104+
let expected = true
105+
expect(actual).toEqual(expected)
106+
})
107+
})
108+
109+
describe('Component methods', () => {
110+
describe('component#constructor', () => {
111+
it('should exist', () => {
112+
const component = mount(<Recaptcha />)
113+
let actual = typeof component.instance().constructor
114+
let expected = 'function'
115+
expect(actual).toEqual(expected)
116+
})
117+
it('should bind \'this\' to the appropriate component methods when called', () => {
118+
const component = mount(<Recaptcha />)
119+
const boundComponentMethods = ['_renderGrecaptcha', 'reset']
120+
let actual = undefined
121+
let expected = undefined
122+
boundComponentMethods.forEach(method => {
123+
actual = component.instance()[method].hasOwnProperty('prototype')
124+
expected = false
125+
expect(actual).toEqual(expected)
126+
actual = undefined
127+
expected = undefined
128+
})
129+
})
130+
})
131+
132+
describe('component#reset', () => {
133+
it('should exist', () => {
134+
const component = mount(<Recaptcha />)
135+
let actual = typeof component.instance().reset
136+
let expected = 'function'
137+
expect(actual).toEqual(expected)
138+
})
139+
it('should call reset on window.grecaptcha when called', () => {
140+
let resetSpy = sinon.spy(window.grecaptcha, 'reset');
141+
const component = mount(<Recaptcha />, {context: window})
142+
component.instance().reset()
143+
let actual = resetSpy.callCount
144+
let expected = 1
145+
expect(actual).toEqual(expected)
146+
resetSpy.restore()
147+
})
148+
})
149+
150+
describe('component#_updateReadyState', () => {
151+
it('should exist', () => {
152+
const component = mount(<Recaptcha />)
153+
let actual = typeof component.instance()._updateReadyState
154+
let expected = 'function'
155+
expect(actual).toEqual(expected)
156+
})
157+
it('should set the component\'s state to ready when isReady returns true', () => {
158+
const component = mount(<Recaptcha />, {context: window})
159+
let actual = component.instance().state.ready
160+
let expected = true
161+
expect(actual).toEqual(expected)
162+
})
163+
})
164+
165+
describe('component#_renderGrecaptcha', () => {
166+
it('should exist', () => {
167+
const component = mount(<Recaptcha />)
168+
let actual = typeof component.instance()._renderGrecaptcha
169+
let expected = 'function'
170+
expect(actual).toEqual(expected)
171+
})
172+
it('should be called when the captcha is ready to render', () => {
173+
let componentSpy = sinon.spy(Recaptcha.prototype, '_renderGrecaptcha');
174+
const component = mount(<Recaptcha />, {context: window})
175+
let actual = componentSpy.callCount
176+
let expected = 1
177+
expect(actual).toEqual(expected)
178+
componentSpy.restore()
179+
})
180+
})
181+
})
182+
})

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"compile": "webpack -p --config webpack.production.config.js",
99
"lint": "eslint src example",
1010
"test": "BABEL_ENV=production jest",
11+
"test:watch": "BABEL_ENV=production jest --watch",
1112
"prepublish": "NODE_ENV=production npm run compile"
1213
},
1314
"repository": {
@@ -43,19 +44,26 @@
4344
"babel-preset-react": "^6.3.13",
4445
"babel-preset-stage-0": "^6.3.13",
4546
"babel-runtime": "^6.3.19",
47+
"enzyme": "^3.3.0",
48+
"enzyme-adapter-react-15": "^1.0.5",
4649
"eslint": "^1.10.3",
4750
"eslint-config-airbnb": "^5.0.0",
4851
"eslint-plugin-react": "^3.14.0",
4952
"jest": "^20.0.4",
5053
"jest-cli": "^20.0.4",
54+
"jsdom": "^11.6.1",
55+
"lodash": "^4.17.4",
5156
"pre-commit": "^1.1.2",
5257
"prop-types": "^15.5.10",
5358
"react": "^15.5.4",
59+
"react-addons-test-utils": "^15.6.2",
5460
"react-dom": "^15.5.4",
5561
"react-hot-loader": "^1.3.0",
62+
"react-test-renderer": "^15.6.2",
5663
"react-transform-catch-errors": "^1.0.1",
5764
"react-transform-hmr": "^1.0.1",
5865
"redbox-react": "^1.2.0",
66+
"sinon": "^4.2.2",
5967
"webpack": "^1.12.9",
6068
"webpack-dev-server": "^1.14.0"
6169
},

0 commit comments

Comments
 (0)