diff options
-rw-r--r-- | web-ui/package.json | 6 | ||||
-rw-r--r-- | web-ui/src/backup_account/backup_account.js | 2 | ||||
-rw-r--r-- | web-ui/src/backup_account/backup_email/backup_email.js | 16 | ||||
-rw-r--r-- | web-ui/src/backup_account/backup_email/backup_email.spec.js | 89 | ||||
-rw-r--r-- | web-ui/src/backup_account/page.js | 6 | ||||
-rw-r--r-- | web-ui/src/backup_account/page.spec.js | 4 | ||||
-rw-r--r-- | web-ui/webpack.test.config.js | 10 |
7 files changed, 91 insertions, 42 deletions
diff --git a/web-ui/package.json b/web-ui/package.json index 5a5375e6..d26fc7f8 100644 --- a/web-ui/package.json +++ b/web-ui/package.json @@ -19,12 +19,14 @@ "css-loader": "^0.26.1", "dompurify": "^0.8.4", "enzyme": "^2.7.1", + "es6-promise": "^4.1.0", "eslint": "^3.17.1", "eslint-config-airbnb": "^14.1.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-react": "^6.9.0", "expect": "^1.20.2", + "fetch-mock": "^5.9.4", "file-loader": "^0.10.0", "font-awesome": "^4.7.0", "handlebars": "^4.0.5", @@ -37,6 +39,7 @@ "imagemin": "5.2.1", "imagemin-pngquant": "^5.0.0", "imagemin-svgo": "^5.2.0", + "isomorphic-fetch": "^2.2.1", "jasmine-flight": "^4.0.0", "jasmine-jquery": "^2.1.1", "jquery": "^3.1.1", @@ -78,7 +81,8 @@ "utf8": "^2.1.2", "validator": "^7.0.0", "watch": "0.19.1", - "webpack": "^1.14.0" + "webpack": "^1.14.0", + "webpack-node-externals": "^1.5.4" }, "scripts": { "test": "npm run lint --silent && npm run build:statics --silent && npm run test:unit && npm run test:integration", diff --git a/web-ui/src/backup_account/backup_account.js b/web-ui/src/backup_account/backup_account.js index ac218a39..19b7c19c 100644 --- a/web-ui/src/backup_account/backup_account.js +++ b/web-ui/src/backup_account/backup_account.js @@ -22,6 +22,8 @@ import a11y from 'react-a11y'; import App from 'src/common/app'; import PageWrapper from './page'; +require('es6-promise').polyfill(); + if (process.env.NODE_ENV === 'development') a11y(React); render( diff --git a/web-ui/src/backup_account/backup_email/backup_email.js b/web-ui/src/backup_account/backup_email/backup_email.js index 05cba35e..09863950 100644 --- a/web-ui/src/backup_account/backup_email/backup_email.js +++ b/web-ui/src/backup_account/backup_email/backup_email.js @@ -15,11 +15,13 @@ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>. */ +import 'isomorphic-fetch'; import React from 'react'; import { translate } from 'react-i18next'; import SubmitButton from 'src/common/submit_button/submit_button'; import InputField from 'src/common/input_field/input_field'; import validator from 'validator'; +import browser from 'helpers/browser'; import './backup_email.scss'; @@ -42,9 +44,17 @@ export class BackupEmail extends React.Component { submitHandler = (event) => { event.preventDefault(); - if (typeof this.props.onSubmit === 'function') { - this.props.onSubmit(); - } + + fetch('/backup-account', { + credentials: 'same-origin', + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + csrftoken: [browser.getCookie('XSRF-TOKEN')] + }) + }).then(() => this.props.onSubmit('success')); } render() { diff --git a/web-ui/src/backup_account/backup_email/backup_email.spec.js b/web-ui/src/backup_account/backup_email/backup_email.spec.js index 8732003b..48199738 100644 --- a/web-ui/src/backup_account/backup_email/backup_email.spec.js +++ b/web-ui/src/backup_account/backup_email/backup_email.spec.js @@ -1,90 +1,125 @@ import { shallow } from 'enzyme'; import expect from 'expect'; import React from 'react'; +import fetchMock from 'fetch-mock'; import { BackupEmail } from 'src/backup_account/backup_email/backup_email'; +import browser from 'helpers/browser'; describe('BackupEmail', () => { - let page; + let backupEmail; + let mockOnSubmit; let mockTranslations; beforeEach(() => { + mockOnSubmit = expect.createSpy(); + mockTranslations = key => key; - page = shallow(<BackupEmail t={mockTranslations} />); + backupEmail = shallow(<BackupEmail t={mockTranslations} onSubmit={mockOnSubmit} />); }); it('renders backup email title', () => { - expect(page.find('h1').text()).toEqual('backup-account.backup-email.title'); + expect(backupEmail.find('h1').text()).toEqual('backup-account.backup-email.title'); }); it('renders backup account email input field', () => { - expect(page.find('InputField').props().name).toEqual('email'); + expect(backupEmail.find('InputField').props().name).toEqual('email'); }); it('renders backup account submit button', () => { - expect(page.find('SubmitButton').props().buttonText).toEqual('backup-account.backup-email.button'); - }); - - it('form submit should call parameter custom submit', () => { - const mockOnSubmit = expect.createSpy(); - const event = { preventDefault() {} }; - page = shallow(<BackupEmail t={mockTranslations} onSubmit={mockOnSubmit} />); - - page.instance().submitHandler(event); - expect(mockOnSubmit).toHaveBeenCalled(); + expect(backupEmail.find('SubmitButton').props().buttonText).toEqual('backup-account.backup-email.button'); }); describe('Email validation', () => { - let pageInstance; + let backupEmailInstance; beforeEach(() => { - pageInstance = page.instance(); + backupEmailInstance = backupEmail.instance(); }); it('verify initial state', () => { - expect(pageInstance.state.error).toEqual(''); - expect(page.find('SubmitButton').props().disabled).toEqual(true); + expect(backupEmailInstance.state.error).toEqual(''); + expect(backupEmail.find('SubmitButton').props().disabled).toBe(true); }); context('with invalid email', () => { beforeEach(() => { - pageInstance.validateEmail({ target: { value: 'test' } }); + backupEmailInstance.validateEmail({ target: { value: 'test' } }); }); it('sets error in state', () => { - expect(pageInstance.state.error).toEqual('backup-account.backup-email.error.invalid-email'); + expect(backupEmailInstance.state.error).toEqual('backup-account.backup-email.error.invalid-email'); }); it('disables submit button', () => { - expect(page.find('SubmitButton').props().disabled).toEqual(true); + expect(backupEmail.find('SubmitButton').props().disabled).toBe(true); }); }); context('with valid email', () => { beforeEach(() => { - pageInstance.validateEmail({ target: { value: 'test@test.com' } }); + backupEmailInstance.validateEmail({ target: { value: 'test@test.com' } }); }); it('does not set error in state', () => { - expect(pageInstance.state.error).toEqual(''); + expect(backupEmailInstance.state.error).toEqual(''); }); it('submit button is enabled', () => { - expect(page.find('SubmitButton').props().disabled).toEqual(false); + expect(backupEmail.find('SubmitButton').props().disabled).toBe(false); }); }); context('with empty email', () => { beforeEach(() => { - pageInstance.validateEmail({ target: { value: '' } }); + backupEmailInstance.validateEmail({ target: { value: '' } }); }); it('not set error in state', () => { - expect(pageInstance.state.error).toEqual(''); + expect(backupEmailInstance.state.error).toEqual(''); }); it('disables submit button', () => { - expect(page.find('SubmitButton').props().disabled).toEqual(true); + expect(backupEmail.find('SubmitButton').props().disabled).toBe(true); }); }); }); + + describe('Submit', () => { + let preventDefaultSpy; + + beforeEach((done) => { + mockOnSubmit = expect.createSpy().andCall(() => done()); + preventDefaultSpy = expect.createSpy(); + expect.spyOn(browser, 'getCookie').andReturn('abc123'); + + backupEmail = shallow(<BackupEmail t={mockTranslations} onSubmit={mockOnSubmit} />); + + fetchMock.post('/backup-account', 204); + backupEmail.find('form').simulate('submit', { preventDefault: preventDefaultSpy }); + }); + + it('posts backup email', () => { + expect(fetchMock.called('/backup-account')).toBe(true, 'Backup account POST was not called'); + }); + + it('sends csrftoken as content', () => { + expect(fetchMock.lastOptions('/backup-account').body).toContain('"csrftoken":["abc123"]'); + }); + + it('sends content-type header', () => { + expect(fetchMock.lastOptions('/backup-account').headers['Content-Type']).toEqual('application/json'); + }); + + it('sends same origin headers', () => { + expect(fetchMock.lastOptions('/backup-account').credentials).toEqual('same-origin'); + }); + + it('prevents default call to refresh page', () => { + expect(preventDefaultSpy).toHaveBeenCalled(); + }); + + it('calls onSubmit from props when success', () => { + expect(mockOnSubmit).toHaveBeenCalledWith('success'); + }); + }); }); diff --git a/web-ui/src/backup_account/page.js b/web-ui/src/backup_account/page.js index 221c6978..49e4b316 100644 --- a/web-ui/src/backup_account/page.js +++ b/web-ui/src/backup_account/page.js @@ -34,10 +34,8 @@ export class Page extends React.Component { this.state = { status: '' }; } - saveBackupEmail = () => { - this.setState({ - status: 'success' - }); + saveBackupEmail = (status) => { + this.setState({ status }); } mainContent = () => { diff --git a/web-ui/src/backup_account/page.spec.js b/web-ui/src/backup_account/page.spec.js index 23c117a0..bd7bb884 100644 --- a/web-ui/src/backup_account/page.spec.js +++ b/web-ui/src/backup_account/page.spec.js @@ -29,7 +29,7 @@ describe('BackupAccount', () => { }); it('changes state', () => { - pageInstance.saveBackupEmail(); + pageInstance.saveBackupEmail('success'); expect(pageInstance.state.status).toEqual('success'); }); @@ -38,7 +38,7 @@ describe('BackupAccount', () => { }); it('renders confirmation component', () => { - pageInstance.saveBackupEmail(); + pageInstance.saveBackupEmail('success'); expect(page.find(Confirmation).length).toEqual(1); }); }); diff --git a/web-ui/webpack.test.config.js b/web-ui/webpack.test.config.js index 3dc1b311..699aa12e 100644 --- a/web-ui/webpack.test.config.js +++ b/web-ui/webpack.test.config.js @@ -1,17 +1,17 @@ var path = require('path'); var webpack = require('webpack'); var aliases = require('./config/alias-webpack'); +var nodeExternals = require('webpack-node-externals'); module.exports = { + target: 'node', resolve: { alias: aliases, extensions: ['', '.js'] }, - externals: { - 'react/lib/ExecutionEnvironment': true, - 'react/addons': true, - 'react/lib/ReactContext': 'window' - }, + externals: [nodeExternals({ + whitelist: [/\.(?!(?:jsx?|json)$).{1,5}$/i] + })], module: { loaders: [ { |