diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9df53e0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +[*.js] +charset = utf-8 +indent_style = space +indent_size = 2 + +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/.eslintrc b/.eslintrc index 77ffa2d..73f0d5d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -15,6 +15,7 @@ "comma-dangle": [2, "always-multiline"], "comma-spacing": 1, "key-spacing": 0, + "indent": ["error", 2], "no-mixed-spaces-and-tabs": 2, "no-multiple-empty-lines": [1, { "max": 1}], "no-underscore-dangle": 0, @@ -31,7 +32,8 @@ "react/prop-types": 1, "react/react-in-jsx-scope": 1, "react/self-closing-comp": 1, - "react/wrap-multilines": 1, + "react/jsx-wrap-multilines": 1, + "semi": ["error", "always"], "strict": [1, "never"] } } diff --git a/karma.conf.js b/karma.conf.js index 072e5f3..63ac584 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -42,7 +42,7 @@ module.exports = function (config) { autoWatch: true, - browsers: [ isCI ? "PhantomJS" : "Chrome" ], + browsers: [isCI ? "PhantomJS" : "Chrome"], captureTimeout: 60000, browserNoActivityTimeout: 30000, diff --git a/package.json b/package.json index b1b960f..de24813 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "build": "rm -rf lib && babel src --out-dir lib", "lint": "eslint ./", + "lint:fix": "eslint ./ --fix", "test": "karma start --single-run", "test-watch": "karma start", "patch": "release patch --run", @@ -49,9 +50,9 @@ "babel-runtime": "^6.0.0", "chai": "^3.5.0", "es5-shim": "^4.5.0", - "eslint": "~1.6.0", - "eslint-config-defaults": "~7.0.1", - "eslint-plugin-react": "~3.5.1", + "eslint": "^3.17.1", + "eslint-config-defaults": "^9.0.0", + "eslint-plugin-react": "^6.10.0", "karma": "~0.13.9", "karma-chai": "~0.1.0", "karma-chrome-launcher": "~0.2.0", diff --git a/src/recaptcha-wrapper.js b/src/recaptcha-wrapper.js index 5bedb2f..ce1561d 100644 --- a/src/recaptcha-wrapper.js +++ b/src/recaptcha-wrapper.js @@ -3,13 +3,13 @@ import makeAsyncScriptLoader from "react-async-script"; const callbackName = "onloadcallback"; const lang = typeof window !== "undefined" && (window.recaptchaOptions && window.recaptchaOptions.lang) ? - "&hl=" + window.recaptchaOptions.lang : + `&hl=${window.recaptchaOptions.lang}` : ""; const URL = `https://www.google.com/recaptcha/api.js?onload=${callbackName}&render=explicit${lang}`; const globalName = "grecaptcha"; export default makeAsyncScriptLoader(ReCAPTCHA, URL, { - callbackName: callbackName, - globalName: globalName, - exposeFuncs: ["getValue", "reset"], + callbackName, + globalName, + exposeFuncs: ["getValue", "reset", "execute"], }); diff --git a/src/recaptcha.js b/src/recaptcha.js index 400e978..6882942 100644 --- a/src/recaptcha.js +++ b/src/recaptcha.js @@ -10,15 +10,15 @@ const ReCAPTCHA = React.createClass({ type: PropTypes.oneOf(["image", "audio"]), tabindex: PropTypes.number, onExpired: PropTypes.func, - size: PropTypes.oneOf(["compact", "normal"]), + size: PropTypes.oneOf(["compact", "normal", "invisible"]), stoken: PropTypes.string, }, - getInitialState() { + getInitialState () { return {}; }, - getDefaultProps() { + getDefaultProps () { return { theme: "light", type: "image", @@ -27,20 +27,29 @@ const ReCAPTCHA = React.createClass({ }; }, - getValue() { + getValue () { if (this.props.grecaptcha && this.state.widgetId !== undefined) { return this.props.grecaptcha.getResponse(this.state.widgetId); } return null; }, - reset() { + execute () { + const { grecaptcha } = this.props; + const { widgetId } = this.state; + + if (grecaptcha && widgetId !== undefined) { + return grecaptcha.execute(widgetId); + } + }, + + reset () { if (this.props.grecaptcha && this.state.widgetId !== undefined) { this.props.grecaptcha.reset(this.state.widgetId); } }, - handleExpired() { + handleExpired () { if (this.props.onExpired) { this.props.onExpired(); } else if (this.props.onChange) { @@ -48,9 +57,9 @@ const ReCAPTCHA = React.createClass({ } }, - explicitRender(cb) { + explicitRender (cb) { if (this.props.grecaptcha && this.state.widgetId === undefined) { - let id = this.props.grecaptcha.render(this.refs.captcha, { + const id = this.props.grecaptcha.render(this.refs.captcha, { sitekey: this.props.sitekey, callback: this.props.onChange, theme: this.props.theme, @@ -66,15 +75,15 @@ const ReCAPTCHA = React.createClass({ } }, - componentDidMount() { + componentDidMount () { this.explicitRender(); }, - componentDidUpdate() { + componentDidUpdate () { this.explicitRender(); }, - render() { + render () { // consume properties owned by the reCATPCHA, pass the rest to the div so the user can style it. /* eslint-disable no-unused-vars */ const { sitekey, onChange, theme, type, tabindex, onExpired, size, stoken, grecaptcha, ...childProps } = this.props; diff --git a/test/recaptcha-spec.js b/test/recaptcha-spec.js index 707b9c9..ff0c7ab 100644 --- a/test/recaptcha-spec.js +++ b/test/recaptcha-spec.js @@ -1,56 +1,72 @@ import React from "react"; import ReactDOM from "react-dom"; import ReactTestUtils from "react-addons-test-utils"; -import ReCAPTCHA from "../src/recaptcha"; +import ReCAPTCHA from "../src/recaptcha"; // eslint-disable-line no-unused-vars describe("ReCAPTCHA", () => { it("Rendered Component should be a div", () => { - let instance = ReactTestUtils.renderIntoDocument( - - ); + const instance = ReactTestUtils.renderIntoDocument( + , + ); assert.equal(ReactDOM.findDOMNode(instance).nodeName, "DIV"); }); it("Rendered Component should contained passed props", () => { - let props = { + const props = { className: "TheClassName", id: "superdefinedId", }; - let instance = ReactTestUtils.renderIntoDocument( - - ); + const instance = ReactTestUtils.renderIntoDocument( + , + ); assert.equal(ReactDOM.findDOMNode(instance).id, props.id); assert.match(ReactDOM.findDOMNode(instance).className, new RegExp(props.className)); }); it("should call grecaptcha.render, when it is already loaded", (done) => { - let grecaptchaMock = { - render(node, options) { + const grecaptchaMock = { + render (node, options) { assert.isNotNull(node); assert.equal(options.sitekey, "xxx"); done(); }, }; - let instance = ReactTestUtils.renderIntoDocument( - - ); + const instance = ReactTestUtils.renderIntoDocument( + , + ); assert.ok(instance); }); it("reset, should call grecaptcha.reset with the widget id", (done) => { - let grecaptchaMock = { - render() { + const grecaptchaMock = { + render () { return "someWidgetId"; }, - reset(widgetId) { + reset (widgetId) { assert.isNotNull(widgetId); done(); }, }; - let instance = ReactTestUtils.renderIntoDocument( - - ); + const instance = ReactTestUtils.renderIntoDocument( + , + ); instance.reset(); }); + it("execute, should call grecaptcha.execute with the widget id", (done) => { + const grecaptchaMock = { + render () { + return "someWidgetId"; + }, + + execute (widgetId) { + assert.isNotNull(widgetId); + done(); + }, + }; + const instance = ReactTestUtils.renderIntoDocument( + , + ); + instance.execute(); + }); describe("Expired", () => { it("should call onChange with null when response is expired"); it("should call onExpired when response is expired"); diff --git a/test/recaptcha-wrapper-spec.js b/test/recaptcha-wrapper-spec.js index f5dc57c..49f4af4 100644 --- a/test/recaptcha-wrapper-spec.js +++ b/test/recaptcha-wrapper-spec.js @@ -1,17 +1,17 @@ import React from "react"; import ReactTestUtils from "react-addons-test-utils"; -import ReCAPTCHA from "../src/recaptcha-wrapper"; +import ReCAPTCHA from "../src/recaptcha-wrapper"; // eslint-disable-line no-unused-vars const VALUE = "some value"; const WIDGET_ID = "someWidgetId"; -let grecaptchaMock = { - render(node, options) { +const grecaptchaMock = { + render (node, options) { assert.ok(node, options); return WIDGET_ID; }, - getResponse(widgetId) { + getResponse (widgetId) { assert.equal(widgetId, WIDGET_ID); return VALUE; }, @@ -22,8 +22,8 @@ describe("ReCAPTCHAWrapper", () => { window.grecaptcha = grecaptchaMock; }); it("should proxy functions", () => { - let instance = ReactTestUtils.renderIntoDocument( - + const instance = ReactTestUtils.renderIntoDocument( + , ); assert.ok(instance); assert.equal(instance.getValue(), VALUE);