From bd12bad21e0303d0bbfec8851a544412ebd9b5e3 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Fri, 29 Apr 2016 11:10:34 +0100 Subject: [PATCH 01/16] Setup Mocha --- .eslintrc | 3 ++- package.json | 4 ++++ src/js/__tests__/__helpers__/mocha.opts | 5 +++++ src/js/__tests__/__helpers__/tests-dom.js | 5 +++++ src/js/__tests__/basic.js | 9 +++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/js/__tests__/__helpers__/mocha.opts create mode 100644 src/js/__tests__/__helpers__/tests-dom.js create mode 100644 src/js/__tests__/basic.js diff --git a/.eslintrc b/.eslintrc index a7166a495..9d19514f1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,8 @@ env: { browser: true, es6: true, - node: true + node: true, + mocha: true }, "parserOptions": { "ecmaVersion": 6, diff --git a/package.json b/package.json index a05a7d84c..8d49823b5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dist": "npm run release-js && npm run package && npm run codesign", "lint-js": "eslint 'src/js/' 'src/js/app.js' 'main.js'", "lint-sass": "sass-lint -c .sass-lint.yml -v -q", + "mocha": "./node_modules/mocha/bin/mocha --opts src/js/__tests__/__helpers__/mocha.opts", "test": "npm run lint-js && npm run lint-sass", "start": "electron . --enable-logging" }, @@ -81,13 +82,16 @@ "babel-preset-es2015": "=6.6.0", "babel-preset-react": "=6.5.0", "babel-preset-stage-0": "=6.5.0", + "chai": "=3.5.0", "css-loader": "=0.23.1", "electron-packager": "=7.0.1", "electron-prebuilt": "=0.37.7", "eslint": "=2.8.0", "eslint-plugin-react": "=5.0.1", "file-loader": "=0.8.5", + "jsdom": "=8.4.1", "json-loader": "=0.5.4", + "mocha": "=2.4.5", "node-sass": "=3.6.0", "sass-lint": "=1.7.0", "sass-loader": "=3.2.0", diff --git a/src/js/__tests__/__helpers__/mocha.opts b/src/js/__tests__/__helpers__/mocha.opts new file mode 100644 index 000000000..fe8414c4b --- /dev/null +++ b/src/js/__tests__/__helpers__/mocha.opts @@ -0,0 +1,5 @@ +--compilers js:babel-core/register +--require src/js/__tests__/__helpers__/tests-dom.js +--bail +--recursive +src/js/__tests__**/*.js diff --git a/src/js/__tests__/__helpers__/tests-dom.js b/src/js/__tests__/__helpers__/tests-dom.js new file mode 100644 index 000000000..a6e6d5d77 --- /dev/null +++ b/src/js/__tests__/__helpers__/tests-dom.js @@ -0,0 +1,5 @@ +import React from 'react'; // eslint-disable-line no-unused-vars +import jsdom from 'jsdom'; + +global.document = jsdom.jsdom(''); +global.window = document.parentWindow; diff --git a/src/js/__tests__/basic.js b/src/js/__tests__/basic.js new file mode 100644 index 000000000..b51bb7176 --- /dev/null +++ b/src/js/__tests__/basic.js @@ -0,0 +1,9 @@ +import { expect } from 'chai'; + +describe('basic.js', function () { + + it('should make a basic test.', function () { + expect(2).to.equal(2); + }); + +}); From 5116077901c9df9d6ecfc9b204d9aabf7e7c73e6 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Fri, 29 Apr 2016 11:16:56 +0100 Subject: [PATCH 02/16] Setup Coverage --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 8d49823b5..fd3e9f159 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "lint-js": "eslint 'src/js/' 'src/js/app.js' 'main.js'", "lint-sass": "sass-lint -c .sass-lint.yml -v -q", "mocha": "./node_modules/mocha/bin/mocha --opts src/js/__tests__/__helpers__/mocha.opts", + "coverage": "babel-node ./node_modules/istanbul/lib/cli cover node_modules/mocha/bin/_mocha -- --opts src/js/__tests__/__helpers__/mocha.opts", "test": "npm run lint-js && npm run lint-sass", "start": "electron . --enable-logging" }, @@ -75,6 +76,7 @@ "underscore": "=1.8.3" }, "devDependencies": { + "babel-cli": "=6.7.7", "babel-core": "=6.7.7", "babel-eslint": "=6.0.3", "babel-jest": "=11.0.2", @@ -89,6 +91,7 @@ "eslint": "=2.8.0", "eslint-plugin-react": "=5.0.1", "file-loader": "=0.8.5", + "istanbul": "=1.0.0-alpha.2", "jsdom": "=8.4.1", "json-loader": "=0.5.4", "mocha": "=2.4.5", From 331aab6c0b16d05d0b72bf0db5da77af13e94fcd Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Fri, 29 Apr 2016 21:49:03 +0100 Subject: [PATCH 03/16] Fix mocha with coverage --- .istanbul.yml | 8 ++++++++ package.json | 2 +- src/js/__tests__/__helpers__/mocha.opts | 2 +- src/js/__tests__/__helpers__/tests-dom.js | 4 ++-- src/js/__tests__/components/all-read.js | 23 +++++++++++++++++++++++ src/js/utils/constants.js | 4 +++- 6 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 .istanbul.yml create mode 100644 src/js/__tests__/components/all-read.js diff --git a/.istanbul.yml b/.istanbul.yml new file mode 100644 index 000000000..d20933f11 --- /dev/null +++ b/.istanbul.yml @@ -0,0 +1,8 @@ +verbose: false +instrumentation: + root: 'src/js/' + extensions: + - .js + default-excludes: true + excludes: ['**/__tests__/**'] + include-all-sources: true diff --git a/package.json b/package.json index fd3e9f159..dbda608fd 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lint-sass": "sass-lint -c .sass-lint.yml -v -q", "mocha": "./node_modules/mocha/bin/mocha --opts src/js/__tests__/__helpers__/mocha.opts", "coverage": "babel-node ./node_modules/istanbul/lib/cli cover node_modules/mocha/bin/_mocha -- --opts src/js/__tests__/__helpers__/mocha.opts", - "test": "npm run lint-js && npm run lint-sass", + "test": "npm run lint-js && npm run lint-sass && npm run coverage", "start": "electron . --enable-logging" }, "repository": { diff --git a/src/js/__tests__/__helpers__/mocha.opts b/src/js/__tests__/__helpers__/mocha.opts index fe8414c4b..6ee861941 100644 --- a/src/js/__tests__/__helpers__/mocha.opts +++ b/src/js/__tests__/__helpers__/mocha.opts @@ -2,4 +2,4 @@ --require src/js/__tests__/__helpers__/tests-dom.js --bail --recursive -src/js/__tests__**/*.js +src/js/__tests__/**/*.js diff --git a/src/js/__tests__/__helpers__/tests-dom.js b/src/js/__tests__/__helpers__/tests-dom.js index a6e6d5d77..d1a82c939 100644 --- a/src/js/__tests__/__helpers__/tests-dom.js +++ b/src/js/__tests__/__helpers__/tests-dom.js @@ -1,5 +1,5 @@ -import React from 'react'; // eslint-disable-line no-unused-vars import jsdom from 'jsdom'; global.document = jsdom.jsdom(''); -global.window = document.parentWindow; +global.window = document.defaultView; +global.navigator = {userAgent: 'node.js'}; diff --git a/src/js/__tests__/components/all-read.js b/src/js/__tests__/components/all-read.js new file mode 100644 index 000000000..11b2d0da7 --- /dev/null +++ b/src/js/__tests__/components/all-read.js @@ -0,0 +1,23 @@ +import { expect } from 'chai'; + +describe('all-read.js', function () { + + const React = require('react'); // eslint-disable-line no-unused-vars + const ReactDOM = require('react-dom'); + const TestUtils = require('react-addons-test-utils'); + const AllRead = require('../../components/all-read').default; + + it('should render itself & its children', function () { + var instance = TestUtils.renderIntoDocument(); + + const node = ReactDOM.findDOMNode(instance); + + expect(node).to.exist; + + var paragraphs = node.getElementsByTagName('h4'); + + expect(paragraphs.length).to.equal(1); + expect(paragraphs[0].textContent).to.equal('No new notifications.'); + }); + +}); diff --git a/src/js/utils/constants.js b/src/js/utils/constants.js index 80f613ac3..e0462ed7f 100644 --- a/src/js/utils/constants.js +++ b/src/js/utils/constants.js @@ -1,4 +1,4 @@ -export default { +let constants = { // GitHub OAuth CLIENT_ID: '3fef4433a29c6ad8f22c', CLIENT_SECRET: '9670de733096c15322183ff17ed0fc8704050379', @@ -16,3 +16,5 @@ export default { 'Yay! Good news.', ] }; + +export default constants; From adcd1f031f6ebe0ab115d3093a455e8ac4f6d35b Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 02:12:17 +0100 Subject: [PATCH 04/16] More tests --- src/js/__tests__/components/all-read.js | 19 +++++++---- src/js/__tests__/components/settings.js | 43 +++++++++++++++++++++++++ src/js/components/settings.js | 2 +- 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 src/js/__tests__/components/settings.js diff --git a/src/js/__tests__/components/all-read.js b/src/js/__tests__/components/all-read.js index 11b2d0da7..7e40f2104 100644 --- a/src/js/__tests__/components/all-read.js +++ b/src/js/__tests__/components/all-read.js @@ -1,11 +1,16 @@ +import React from 'react'; // eslint-disable-line no-unused-vars +import ReactDOM from 'react-dom'; +import TestUtils from 'react-addons-test-utils'; import { expect } from 'chai'; describe('all-read.js', function () { - const React = require('react'); // eslint-disable-line no-unused-vars - const ReactDOM = require('react-dom'); - const TestUtils = require('react-addons-test-utils'); - const AllRead = require('../../components/all-read').default; + var AllRead; + + beforeEach(function () { + AllRead = require('../../components/all-read').default; + }); + it('should render itself & its children', function () { var instance = TestUtils.renderIntoDocument(); @@ -14,10 +19,10 @@ describe('all-read.js', function () { expect(node).to.exist; - var paragraphs = node.getElementsByTagName('h4'); + var heading = node.getElementsByTagName('h4'); - expect(paragraphs.length).to.equal(1); - expect(paragraphs[0].textContent).to.equal('No new notifications.'); + expect(heading.length).to.equal(1); + expect(heading[0].textContent).to.equal('No new notifications.'); }); }); diff --git a/src/js/__tests__/components/settings.js b/src/js/__tests__/components/settings.js new file mode 100644 index 000000000..eccc9efb3 --- /dev/null +++ b/src/js/__tests__/components/settings.js @@ -0,0 +1,43 @@ +import React from 'react'; // eslint-disable-line no-unused-vars +import TestUtils from 'react-addons-test-utils'; +import { expect } from 'chai'; + +describe('settings.js', function () { + + var SettingsPage, mockSettings; + + beforeEach(function () { + // Mocks for Electron + window.require = function () { + return { + ipcRenderer: { + send: function () { + // Fake sending message to ipcMain + } + }, + }; + }; + + mockSettings = { + participating: false, + playSound: true, + showNotifications: true, + markOnClick: false, + openAtStartup: false + }; + + SettingsPage = require('../../components/settings').SettingsPage; + }); + + it('should render itself & its children', function () { + const instance = TestUtils.renderIntoDocument( + true} + settings={mockSettings} /> + ); + + const node = TestUtils.findRenderedDOMComponentWithClass(instance, 'settings'); + expect(node).to.exist; + }); + +}); diff --git a/src/js/components/settings.js b/src/js/components/settings.js index 63d378d50..c8d1da92d 100644 --- a/src/js/components/settings.js +++ b/src/js/components/settings.js @@ -6,7 +6,7 @@ const ipcRenderer = window.require('electron').ipcRenderer; import { updateSetting } from '../actions'; -class SettingsPage extends React.Component { +export class SettingsPage extends React.Component { toggleSetting(key, event) { this.props.updateSetting(key, event.target.checked); } From 00e0733055ff585fee5ab60e3914e68f7fc6ea72 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 20:21:45 +0100 Subject: [PATCH 05/16] Use enzyme --- package.json | 4 +-- src/js/__tests__/__helpers__/tests-dom.js | 11 ++++++++ src/js/__tests__/components/all-read.js | 33 +++++++++++++---------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index dbda608fd..031fe8516 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,7 @@ "redux-storage": "=4.0.0", "redux-storage-decorator-filter": "=1.1.3", "redux-storage-engine-localstorage": "=1.1.0", - "reflux": "=0.4.1", "reloading": "0.0.6", - "superagent": "=1.8.3", "underscore": "=1.8.3" }, "devDependencies": { @@ -88,6 +86,7 @@ "css-loader": "=0.23.1", "electron-packager": "=7.0.1", "electron-prebuilt": "=0.37.7", + "enzyme": "=2.2.0", "eslint": "=2.8.0", "eslint-plugin-react": "=5.0.1", "file-loader": "=0.8.5", @@ -98,6 +97,7 @@ "node-sass": "=3.6.0", "sass-lint": "=1.7.0", "sass-loader": "=3.2.0", + "sinon": "=1.17.3", "style-loader": "=0.13.1", "webpack": "=1.13.0" } diff --git a/src/js/__tests__/__helpers__/tests-dom.js b/src/js/__tests__/__helpers__/tests-dom.js index d1a82c939..fcb41cd63 100644 --- a/src/js/__tests__/__helpers__/tests-dom.js +++ b/src/js/__tests__/__helpers__/tests-dom.js @@ -3,3 +3,14 @@ import jsdom from 'jsdom'; global.document = jsdom.jsdom(''); global.window = document.defaultView; global.navigator = {userAgent: 'node.js'}; + +// Mocks for Electron +window.require = function () { + return { + ipcRenderer: { + send: function () { + // Fake sending message to ipcMain + } + }, + }; +}; diff --git a/src/js/__tests__/components/all-read.js b/src/js/__tests__/components/all-read.js index 7e40f2104..1761f28aa 100644 --- a/src/js/__tests__/components/all-read.js +++ b/src/js/__tests__/components/all-read.js @@ -1,28 +1,33 @@ import React from 'react'; // eslint-disable-line no-unused-vars -import ReactDOM from 'react-dom'; -import TestUtils from 'react-addons-test-utils'; import { expect } from 'chai'; +import { mount } from 'enzyme'; +import sinon from 'sinon'; +import AllRead from '../../components/all-read'; -describe('all-read.js', function () { - - var AllRead; +function setup() { + const props = {}; + const wrapper = mount(); - beforeEach(function () { - AllRead = require('../../components/all-read').default; - }); + return { + props: props, + wrapper: wrapper, + }; +}; +describe('all-read.js', function () { it('should render itself & its children', function () { - var instance = TestUtils.renderIntoDocument(); - const node = ReactDOM.findDOMNode(instance); + sinon.spy(AllRead.prototype, 'componentDidMount'); + + const { wrapper } = setup(); - expect(node).to.exist; + expect(wrapper).to.exist; + expect(AllRead.prototype.componentDidMount.calledOnce).to.be.true; + expect(wrapper.find('h4').text()).to.equal('No new notifications.'); - var heading = node.getElementsByTagName('h4'); + AllRead.prototype.componentDidMount.restore(); - expect(heading.length).to.equal(1); - expect(heading[0].textContent).to.equal('No new notifications.'); }); }); From fa45a1d3bfd307d4e772ac37204f00aa80ba6ca2 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 20:32:48 +0100 Subject: [PATCH 06/16] Test settings with enzyme --- src/js/__tests__/components/settings.js | 83 ++++++++++++++++--------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/src/js/__tests__/components/settings.js b/src/js/__tests__/components/settings.js index eccc9efb3..e5e4fdeed 100644 --- a/src/js/__tests__/components/settings.js +++ b/src/js/__tests__/components/settings.js @@ -1,43 +1,68 @@ import React from 'react'; // eslint-disable-line no-unused-vars -import TestUtils from 'react-addons-test-utils'; import { expect } from 'chai'; +import { mount } from 'enzyme'; +import sinon from 'sinon'; +import Toggle from 'react-toggle'; +import { SettingsPage } from '../../components/settings'; -describe('settings.js', function () { - - var SettingsPage, mockSettings; - - beforeEach(function () { - // Mocks for Electron - window.require = function () { - return { - ipcRenderer: { - send: function () { - // Fake sending message to ipcMain - } - }, - }; - }; - - mockSettings = { +function setup() { + const props = { + updateSetting: () => true, + settings: { participating: false, playSound: true, showNotifications: true, markOnClick: false, openAtStartup: false - }; + } + }; + const wrapper = mount(); - SettingsPage = require('../../components/settings').SettingsPage; - }); + return { + props: props, + wrapper: wrapper, + }; +}; + +describe('settings.js', function () { it('should render itself & its children', function () { - const instance = TestUtils.renderIntoDocument( - true} - settings={mockSettings} /> - ); - - const node = TestUtils.findRenderedDOMComponentWithClass(instance, 'settings'); - expect(node).to.exist; + + const { wrapper } = setup(); + + expect(wrapper).to.exist; + expect(wrapper.props().settings.participating).to.be.false; + expect(wrapper.find(Toggle).length).to.equal(5); + expect(wrapper.find('.footer').find('.text-right').text()).to.contain('Gitify - Version'); + }); }); + +// function setup() { +// const props = { +// updateSetting: sinon.spy(), +// }; +// }; +// +// describe('settings.js', function () { +// +// it('should render itself & its children', function () { +// +// sinon.spy(SettingsPage.prototype, 'componentDidMount'); +// +// const { props } = setup(); +// // const [ Toggle ] = output.props.children; +// +// const wrapper = mount(); +// +// // expect(SettingsPage.prototype.componentDidMount.calledOnce).to.be.true; +// // +// // console.log('YES YESY ESY'); +// // console.log(node); +// // expect(output.props.className).toBe('container-fluid main-container settings'); +// +// // expect(node).toExist(); +// }); +// +// }); From 1b09981b0ed29e161cfd2d59288ab1783b6b6c0c Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 21:02:45 +0100 Subject: [PATCH 07/16] Better Test --- src/js/__tests__/components/settings.js | 43 ++++++++----------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/js/__tests__/components/settings.js b/src/js/__tests__/components/settings.js index e5e4fdeed..2307e81fe 100644 --- a/src/js/__tests__/components/settings.js +++ b/src/js/__tests__/components/settings.js @@ -7,7 +7,7 @@ import { SettingsPage } from '../../components/settings'; function setup() { const props = { - updateSetting: () => true, + updateSetting: sinon.spy(), settings: { participating: false, playSound: true, @@ -16,6 +16,7 @@ function setup() { openAtStartup: false } }; + const wrapper = mount(); return { @@ -37,32 +38,16 @@ describe('settings.js', function () { }); -}); + it('should update a setting', function () { + + const { wrapper } = setup(); -// function setup() { -// const props = { -// updateSetting: sinon.spy(), -// }; -// }; -// -// describe('settings.js', function () { -// -// it('should render itself & its children', function () { -// -// sinon.spy(SettingsPage.prototype, 'componentDidMount'); -// -// const { props } = setup(); -// // const [ Toggle ] = output.props.children; -// -// const wrapper = mount(); -// -// // expect(SettingsPage.prototype.componentDidMount.calledOnce).to.be.true; -// // -// // console.log('YES YESY ESY'); -// // console.log(node); -// // expect(output.props.className).toBe('container-fluid main-container settings'); -// -// // expect(node).toExist(); -// }); -// -// }); + expect(wrapper).to.exist; + expect(wrapper.props().settings.participating).to.be.false; + + wrapper.find(Toggle).nodes[0].props.onChange({target: {checked: true}}); + expect(wrapper.props().updateSetting.calledOnce).to.be.true; + + }); + +}); From 7ee65dc6fbc25d12fba60793527566cdf3700478 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 21:12:41 +0100 Subject: [PATCH 08/16] Complete settings tests --- src/js/__tests__/basic.js | 2 +- src/js/__tests__/components/settings.js | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/js/__tests__/basic.js b/src/js/__tests__/basic.js index b51bb7176..3c8ad3e27 100644 --- a/src/js/__tests__/basic.js +++ b/src/js/__tests__/basic.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; describe('basic.js', function () { - it('should make a basic test.', function () { + it('should make a basic test', function () { expect(2).to.equal(2); }); diff --git a/src/js/__tests__/components/settings.js b/src/js/__tests__/components/settings.js index 2307e81fe..11d7713d6 100644 --- a/src/js/__tests__/components/settings.js +++ b/src/js/__tests__/components/settings.js @@ -43,11 +43,20 @@ describe('settings.js', function () { const { wrapper } = setup(); expect(wrapper).to.exist; - expect(wrapper.props().settings.participating).to.be.false; - - wrapper.find(Toggle).nodes[0].props.onChange({target: {checked: true}}); + wrapper.find(Toggle).first().props().onChange({target: {checked: true}}); expect(wrapper.props().updateSetting.calledOnce).to.be.true; }); + it('should check for updates and quit the app', function () { + + const { wrapper } = setup(); + + expect(wrapper).to.exist; + + wrapper.find('.btn-primary').simulate('click'); + wrapper.find('.btn-danger').simulate('click'); + + }); + }); From e083daa194c98cd81436287c88240f9896c66ad8 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 21:34:59 +0100 Subject: [PATCH 09/16] Start testing reducer --- src/js/__tests__/components/all-read.js | 2 +- src/js/__tests__/components/settings.js | 2 +- src/js/__tests__/reducers/settings.js | 42 +++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/js/__tests__/reducers/settings.js diff --git a/src/js/__tests__/components/all-read.js b/src/js/__tests__/components/all-read.js index 1761f28aa..51b4a92e3 100644 --- a/src/js/__tests__/components/all-read.js +++ b/src/js/__tests__/components/all-read.js @@ -14,7 +14,7 @@ function setup() { }; }; -describe('all-read.js', function () { +describe('components/all-read.js', function () { it('should render itself & its children', function () { diff --git a/src/js/__tests__/components/settings.js b/src/js/__tests__/components/settings.js index 11d7713d6..b57f16701 100644 --- a/src/js/__tests__/components/settings.js +++ b/src/js/__tests__/components/settings.js @@ -25,7 +25,7 @@ function setup() { }; }; -describe('settings.js', function () { +describe('components/settings.js', function () { it('should render itself & its children', function () { diff --git a/src/js/__tests__/reducers/settings.js b/src/js/__tests__/reducers/settings.js new file mode 100644 index 000000000..aaf391b91 --- /dev/null +++ b/src/js/__tests__/reducers/settings.js @@ -0,0 +1,42 @@ +import { expect } from 'chai'; +import reducer from '../../reducers/settings'; +// import { UPDATE_SETTING } from '../../actions'; + +describe('reducers/settings.js', () => { + it('should return the initial state', () => { + const initialState = { + participating: false, + playSound: true, + showNotifications: true, + markOnClick: false, + openAtStartup: false + }; + + expect(reducer(undefined, {})).to.eql(initialState); + }); + + // it('should handle UPDATE_SETTING', () => { + // expect( + // reducer([], { + // type: types.ADD_TODO, + // text: 'Run the tests' + // }) + // ).toEqual({}) + // + // expect( + // reducer( + // [ + // { + // text: 'Use Redux', + // completed: false, + // id: 0 + // } + // ], + // { + // type: types.ADD_TODO, + // text: 'Run the tests' + // } + // ) + // ).toEqual({}) + // }) +}); From 387aa0305e6d49bdc2a463c0635710f0f988d7ea Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 22:05:22 +0100 Subject: [PATCH 10/16] Test Settings Reducer --- src/js/__tests__/reducers/settings.js | 67 ++++++++++++++------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/js/__tests__/reducers/settings.js b/src/js/__tests__/reducers/settings.js index aaf391b91..4d143554f 100644 --- a/src/js/__tests__/reducers/settings.js +++ b/src/js/__tests__/reducers/settings.js @@ -1,42 +1,45 @@ import { expect } from 'chai'; import reducer from '../../reducers/settings'; -// import { UPDATE_SETTING } from '../../actions'; +import { UPDATE_SETTING } from '../../actions'; describe('reducers/settings.js', () => { + const initialState = { + participating: false, + playSound: true, + showNotifications: true, + markOnClick: false, + openAtStartup: false + }; + it('should return the initial state', () => { - const initialState = { - participating: false, - playSound: true, - showNotifications: true, - markOnClick: false, - openAtStartup: false - }; expect(reducer(undefined, {})).to.eql(initialState); + }); - // it('should handle UPDATE_SETTING', () => { - // expect( - // reducer([], { - // type: types.ADD_TODO, - // text: 'Run the tests' - // }) - // ).toEqual({}) - // - // expect( - // reducer( - // [ - // { - // text: 'Use Redux', - // completed: false, - // id: 0 - // } - // ], - // { - // type: types.ADD_TODO, - // text: 'Run the tests' - // } - // ) - // ).toEqual({}) - // }) + it('should handle UPDATE_SETTING', () => { + + const actionParticipating = { + type: UPDATE_SETTING, + setting: 'participating', + value: true + }; + + expect(reducer(undefined, actionParticipating)).to.eql({ + ...initialState, + participating: true + }); + + const actionOpenAtStartUp = { + type: UPDATE_SETTING, + setting: 'openAtStartup', + value: true + }; + + expect(reducer(undefined, actionOpenAtStartUp)).to.eql({ + ...initialState, + openAtStartup: true + }); + + }); }); From f9378ec48babb8d857a0364294dd57a5bf6fc450 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 22:15:34 +0100 Subject: [PATCH 11/16] Test searchFilter --- src/js/__tests__/reducers/searchFilter.js | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/js/__tests__/reducers/searchFilter.js diff --git a/src/js/__tests__/reducers/searchFilter.js b/src/js/__tests__/reducers/searchFilter.js new file mode 100644 index 000000000..8bf72a381 --- /dev/null +++ b/src/js/__tests__/reducers/searchFilter.js @@ -0,0 +1,48 @@ +import { expect } from 'chai'; +import reducer from '../../reducers/searchFilter'; +import { SEARCH_NOTIFICATIONS, CLEAR_SEARCH } from '../../actions'; + +describe('reducers/searchFilter.js', () => { + const initialState = { + query: '' + }; + + it('should return the initial state', () => { + + expect(reducer(undefined, {})).to.eql(initialState); + + }); + + it('should handle SEARCH_NOTIFICATIONS', () => { + + const action = { + type: SEARCH_NOTIFICATIONS, + query: 'hello' + }; + + expect(reducer(undefined, action)).to.eql({ + ...initialState, + query: 'hello' + }); + + }); + + it('should handle CLEAR_SEARCH', () => { + + const fakeState = { + query: 'hello' + }; + + expect(reducer(fakeState, {})).to.eql(fakeState); + + const action = { + type: CLEAR_SEARCH + }; + + expect(reducer(fakeState, action)).to.eql({ + ...initialState, + query: '' + }); + + }); +}); From d57deeeaaa090761a13d73adbc2ad665c62dfb32 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 22:35:36 +0100 Subject: [PATCH 12/16] Start testing notifications reducer --- src/js/__tests__/reducers/notifications.js | 100 +++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/js/__tests__/reducers/notifications.js diff --git a/src/js/__tests__/reducers/notifications.js b/src/js/__tests__/reducers/notifications.js new file mode 100644 index 000000000..68efe7ac9 --- /dev/null +++ b/src/js/__tests__/reducers/notifications.js @@ -0,0 +1,100 @@ +import { expect } from 'chai'; +import reducer from '../../reducers/notifications'; +import { + NOTIFICATIONS_REQUEST, NOTIFICATIONS_SUCCESS, NOTIFICATIONS_FAILURE, + MARK_NOTIFICATION_SUCCESS, MARK_REPO_NOTIFICATION_SUCCESS +} from '../../actions'; + +describe('reducers/notifications.js', () => { + const initialState = { + response: [], + isFetching: false, + failed: false + }; + + it('should return the initial state', () => { + + expect(reducer(undefined, {})).to.eql(initialState); + + }); + + it('should handle NOTIFICATIONS_REQUEST', () => { + + const action = { + type: NOTIFICATIONS_REQUEST, + query: 'hello' + }; + + expect(reducer(undefined, action)).to.eql({ + ...initialState, + isFetching: true, + failed: false + }); + + }); + + it('should handle NOTIFICATIONS_SUCCESS', () => { + + const notifications = [ + { + id: 1, + repository: 'ekonstantinidis/gitify', + text: 'New Release' + }, + { + id: 2, + repository: 'ekonstantinidis/gitify', + text: 'It\'s Great' + } + ]; + + expect(reducer(undefined, {})).to.eql(initialState); + + const action = { + type: NOTIFICATIONS_SUCCESS, + payload: notifications + }; + + const currentState = { + ...initialState, + isFetching: true, + failed: false + }; + + expect(reducer(currentState, action)).to.eql({ + ...initialState, + isFetching: false, + response: notifications + }); + + }); + + it('should handle NOTIFICATIONS_FAILURE', () => { + + const response = { + error: 404, + message: 'Oops! Something went wrong.' + }; + + const currentState = { + ...initialState, + isFetching: true, + failed: false + }; + + expect(reducer(currentState, {})).to.eql(currentState); + + const action = { + type: NOTIFICATIONS_FAILURE, + payload: response + }; + + expect(reducer(currentState, action)).to.eql({ + ...initialState, + isFetching: false, + failed: true, + response: response + }); + + }); +}); From 2784b5cad73f2da92301025b43280d88ab10bdb7 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 22:43:23 +0100 Subject: [PATCH 13/16] Complete tests for notifications reducer --- src/js/__tests__/reducers/notifications.js | 70 ++++++++++++++++++---- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/src/js/__tests__/reducers/notifications.js b/src/js/__tests__/reducers/notifications.js index 68efe7ac9..089cc7549 100644 --- a/src/js/__tests__/reducers/notifications.js +++ b/src/js/__tests__/reducers/notifications.js @@ -12,6 +12,23 @@ describe('reducers/notifications.js', () => { failed: false }; + const notifications = [ + { + id: 1, + repository: { + full_name: 'ekonstantinidis/gitify' + }, + text: 'New Release' + }, + { + id: 2, + repository: { + full_name: 'ekonstantinidis/gitify' + }, + text: 'It\'s Great' + } + ]; + it('should return the initial state', () => { expect(reducer(undefined, {})).to.eql(initialState); @@ -35,19 +52,6 @@ describe('reducers/notifications.js', () => { it('should handle NOTIFICATIONS_SUCCESS', () => { - const notifications = [ - { - id: 1, - repository: 'ekonstantinidis/gitify', - text: 'New Release' - }, - { - id: 2, - repository: 'ekonstantinidis/gitify', - text: 'It\'s Great' - } - ]; - expect(reducer(undefined, {})).to.eql(initialState); const action = { @@ -97,4 +101,44 @@ describe('reducers/notifications.js', () => { }); }); + + it('should handle MARK_NOTIFICATION_SUCCESS', () => { + + const currentState = { + ...initialState, + response: notifications + }; + + expect(reducer(currentState, {}).response.length).to.equal(2); + + const action = { + type: MARK_NOTIFICATION_SUCCESS, + meta: { + id: 1 + } + }; + + expect(reducer(currentState, action).response.length).to.equal(1); + + }); + + it('should handle MARK_REPO_NOTIFICATION_SUCCESS', () => { + + const currentState = { + ...initialState, + response: notifications + }; + + expect(reducer(currentState, {}).response.length).to.equal(2); + + const action = { + type: MARK_REPO_NOTIFICATION_SUCCESS, + meta: { + repoFullName: 'ekonstantinidis/gitify' + } + }; + + expect(reducer(currentState, action).response.length).to.equal(0); + + }); }); From ea386a9f0f4c50653ed83efa43ab09795c20e2b6 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sat, 30 Apr 2016 23:19:16 +0100 Subject: [PATCH 14/16] More tests --- src/js/__tests__/reducers/auth.js | 116 ++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/js/__tests__/reducers/auth.js diff --git a/src/js/__tests__/reducers/auth.js b/src/js/__tests__/reducers/auth.js new file mode 100644 index 000000000..c177f2c3b --- /dev/null +++ b/src/js/__tests__/reducers/auth.js @@ -0,0 +1,116 @@ +import { expect } from 'chai'; +import reducer from '../../reducers/auth'; +import { + LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE, LOGOUT, CHECK_AUTH +} from '../../actions'; + +describe('reducers/auth.js', () => { + const initialState = { + response: {}, + token: null, + isFetching: false, + failed: false + }; + + it('should return the initial state', () => { + + expect(reducer(undefined, {})).to.eql(initialState); + + }); + + it('should handle LOGIN_REQUEST', () => { + + const action = { + type: LOGIN_REQUEST + }; + + expect(reducer(undefined, action)).to.eql({ + ...initialState, + isFetching: true, + failed: false, + response: {}, + token: null + }); + + }); + + it('should handle LOGIN_SUCCESS', () => { + + const fakeState = { + isFetching: true, + failed: false, + response: {}, + token: null + }; + + expect(reducer(fakeState, {}).token).to.be.null; + + const action = { + type: LOGIN_SUCCESS, + payload: { + access_token: '123HELLOWORLDTOKEN' + } + }; + + expect(reducer(fakeState, action)).to.eql({ + ...initialState, + isFetching: false, + token: action.payload.access_token + }); + + expect(reducer(fakeState, action).token).to.not.be.null; + + }); + + it('should handle LOGIN_FAILURE', () => { + + const fakeState = { + isFetching: true, + failed: false, + response: {}, + token: null + }; + + expect(reducer(fakeState, {}).token).to.be.null; + + const action = { + type: LOGIN_FAILURE, + payload: 'Failed to login.' + }; + + expect(reducer(fakeState, action)).to.eql({ + ...initialState, + isFetching: false, + failed: true, + response: action.payload + }); + + expect(reducer(fakeState, action).token).to.be.null; + + }); + + it('should handle LOGOUT', () => { + + const fakeState = { + isFetching: false, + failed: false, + response: {}, + token: 'LOGGEDINTOKEN' + }; + + expect(reducer(fakeState, {}).token).to.not.be.null; + + const action = { + type: LOGOUT + }; + + expect(reducer(fakeState, action)).to.eql({ + ...initialState, + token: null, + response: null + }); + + expect(reducer(fakeState, action).token).to.be.null; + + }); +}); From db409a715b8c1469b3c3a35f5b428cb889e91258 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sun, 1 May 2016 02:17:49 +0100 Subject: [PATCH 15/16] Complete Reducers Tests --- src/js/__tests__/reducers/auth.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/js/__tests__/reducers/auth.js b/src/js/__tests__/reducers/auth.js index c177f2c3b..32299e67a 100644 --- a/src/js/__tests__/reducers/auth.js +++ b/src/js/__tests__/reducers/auth.js @@ -113,4 +113,31 @@ describe('reducers/auth.js', () => { expect(reducer(fakeState, action).token).to.be.null; }); + + it('should handle CHECK_AUTH', () => { + + const fakeState = { + isFetching: false, + failed: false, + response: {}, + token: null + }; + + const fakeToken = '123HELLOWORLDTOKEN'; + + expect(reducer(fakeState, {}).token).to.be.null; + + const action = { + type: CHECK_AUTH, + token: fakeToken + }; + + expect(reducer(fakeState, action)).to.eql({ + ...initialState, + token: fakeToken + }); + + expect(reducer(fakeState, action).token).to.not.be.null; + + }); }); From 921cf4610bec3c22e4d1f09739e9e3cf9864f3b5 Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Sun, 1 May 2016 12:27:19 +0100 Subject: [PATCH 16/16] Test SearchBar --- src/js/__tests__/components/search.js | 95 +++++++++++++++++++++++++++ src/js/components/search.js | 2 +- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/js/__tests__/components/search.js diff --git a/src/js/__tests__/components/search.js b/src/js/__tests__/components/search.js new file mode 100644 index 000000000..ea09c4ed3 --- /dev/null +++ b/src/js/__tests__/components/search.js @@ -0,0 +1,95 @@ +import React from 'react'; // eslint-disable-line no-unused-vars +import { expect } from 'chai'; +import { mount } from 'enzyme'; +import sinon from 'sinon'; +import { SearchBar } from '../../components/search'; + +function setup(props) { + const wrapper = mount(); + + return { + props: props, + wrapper: wrapper, + }; +}; + +describe('components/search.js', function () { + + it('should render itself & its children', function () { + + const props = { + searchNotifications: sinon.spy(), + clearSearch: sinon.spy(), + showSearch: true, + query: '' + }; + + const { wrapper } = setup(props); + + expect(wrapper).to.exist; + expect(wrapper.find('.octicon-x').length).to.equal(0); + + wrapper.find('input').props().onChange({target: {value: 'hello'}}); + expect(wrapper.props().searchNotifications.calledOnce).to.be.true; + + }); + + it('should hide the search bar if not showSearch', function () { + + const props = { + searchNotifications: sinon.spy(), + clearSearch: sinon.spy(), + showSearch: false, + query: '' + }; + + const { wrapper } = setup(props); + + expect(wrapper).to.exist; + + expect(wrapper.find('.container-fluid').length).to.equal(1); + expect(wrapper.find('.search-bar').length).to.equal(0); + + }); + + it('should show the clear icon/button', function () { + + const props = { + searchNotifications: sinon.spy(), + clearSearch: sinon.spy(), + showSearch: true, + query: 'hello' + }; + + const { wrapper } = setup(props); + + expect(wrapper).to.exist; + + wrapper.find('input').props().onChange({target: {value: 'hello'}}); + expect(wrapper.find('.octicon-x').length).to.equal(1); + + }); + + it('should test the componentWillReceiveProps function', function () { + + sinon.spy(SearchBar.prototype, 'componentWillReceiveProps'); + + const props = { + searchNotifications: sinon.spy(), + clearSearch: sinon.spy(), + showSearch: true, + query: 'hello' + }; + + const { wrapper } = setup(props); + + expect(wrapper).to.exist; + + wrapper.setProps({showSearch: false}); + + expect(wrapper.props().clearSearch.calledOnce).to.be.true; + expect(SearchBar.prototype.componentWillReceiveProps.calledOnce).to.be.true; + + }); + +}); diff --git a/src/js/components/search.js b/src/js/components/search.js index 45974983c..5076e9ede 100644 --- a/src/js/components/search.js +++ b/src/js/components/search.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import { searchNotifications, clearSearch } from '../actions'; -class SearchBar extends React.Component { +export class SearchBar extends React.Component { componentWillReceiveProps(nextProps) { if (nextProps.showSearch === false) {