diff --git a/frontend/package.json b/frontend/package.json index 07c5e565c9..37e3553da3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -35,6 +35,7 @@ "lint:fix": "eslint . --ext js,jsx --fix", "test": "jest", "test:ci": "npm run lint && npm run build && npm run test", + "test:debug": "./node_modules/.bin/node-debug ./node_modules/.bin/jest -i --watch", "prepublish": "npm run build" }, "main": "./index.js", @@ -67,6 +68,8 @@ "babel-preset-stage-0": "^6.5.0", "babel-preset-stage-2": "^6.13.0", "css-loader": "^0.28.4", + "enzyme": "^3.3.0", + "enzyme-adapter-react-16": "^1.1.1", "eslint": "^4.5.0", "eslint-config-finn": "^3.0.0", "eslint-config-finn-prettier": "^3.0.0", @@ -92,6 +95,7 @@ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/src/__mocks__/fileMock.js", "\\.(css|scss)$": "identity-obj-proxy" }, + "setupTestFrameworkScriptFile": "/src/setupTests.js", "setupFiles": [ "/jest-setup.js" ] diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx index 95d7690849..77e32f1065 100644 --- a/frontend/src/component/archive/archive-list-component.jsx +++ b/frontend/src/component/archive/archive-list-component.jsx @@ -27,6 +27,7 @@ class ArchiveList extends Component { ))} ); + debugger; return strategiesList; } renderStrategiesInList(feature) { diff --git a/frontend/src/component/feature/__tests__/.eslintrc b/frontend/src/component/feature/__tests__/.eslintrc new file mode 100644 index 0000000000..eba2077219 --- /dev/null +++ b/frontend/src/component/feature/__tests__/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "jest": true + } +} diff --git a/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap new file mode 100644 index 0000000000..1bc9ad72fc --- /dev/null +++ b/frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap @@ -0,0 +1,55 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly with one feature 1`] = ` + + + + + + + + + + + + Another + + another's description + + + + + + gradualRolloutRandom + + + +`; diff --git a/frontend/src/component/feature/__tests__/__snapshots__/progress-test.jsx.snap b/frontend/src/component/feature/__tests__/__snapshots__/progress-test.jsx.snap new file mode 100644 index 0000000000..d36e393cdf --- /dev/null +++ b/frontend/src/component/feature/__tests__/__snapshots__/progress-test.jsx.snap @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly with 0% done no fallback 1`] = ` + + + + + 0 + % + + +`; + +exports[`renders correctly with 0% done with fallback 1`] = ` + + + +`; + +exports[`renders correctly with 15% done no fallback 1`] = ` + + + + + 15 + % + + +`; + +exports[`renders correctly with 15% done with fallback 1`] = ` + + + +`; diff --git a/frontend/src/component/feature/__tests__/feature-list-item-component-test.jsx b/frontend/src/component/feature/__tests__/feature-list-item-component-test.jsx new file mode 100644 index 0000000000..a3b5944f6d --- /dev/null +++ b/frontend/src/component/feature/__tests__/feature-list-item-component-test.jsx @@ -0,0 +1,37 @@ +import React from 'react'; + +import Feature from './../feature-list-item-component'; +import renderer from 'react-test-renderer'; + +jest.mock('react-mdl'); + +test('renders correctly with one feature', () => { + const feature = { + name: 'Another', + description: "another's description", + enabled: false, + strategies: [ + { + name: 'gradualRolloutRandom', + parameters: { + percentage: 50, + }, + }, + ], + createdAt: '2018-02-04T20:27:52.127Z', + }; + const featureMetrics = { lastHour: {}, lastMinute: {}, seenApps: {} }; + const settings = { sort: 'name' }; + const tree = renderer.create( + + ); + + expect(tree).toMatchSnapshot(); +}); diff --git a/frontend/src/component/feature/__tests__/progress-test.jsx b/frontend/src/component/feature/__tests__/progress-test.jsx new file mode 100644 index 0000000000..8326fe9c16 --- /dev/null +++ b/frontend/src/component/feature/__tests__/progress-test.jsx @@ -0,0 +1,34 @@ +import React from 'react'; + +import Progress from './../progress'; +import renderer from 'react-test-renderer'; + +jest.mock('react-mdl'); + +test('renders correctly with 15% done no fallback', () => { + const percent = 15; + const tree = renderer.create(); + + expect(tree).toMatchSnapshot(); +}); + +test('renders correctly with 0% done no fallback', () => { + const percent = 0; + const tree = renderer.create(); + + expect(tree).toMatchSnapshot(); +}); + +test('renders correctly with 15% done with fallback', () => { + const percent = 15; + const tree = renderer.create(); + + expect(tree).toMatchSnapshot(); +}); + +test('renders correctly with 0% done with fallback', () => { + const percent = 0; + const tree = renderer.create(); + + expect(tree).toMatchSnapshot(); +}); diff --git a/frontend/src/component/feature/form/__tests__/.eslintrc b/frontend/src/component/feature/form/__tests__/.eslintrc new file mode 100644 index 0000000000..eba2077219 --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/.eslintrc @@ -0,0 +1,5 @@ +{ + "env": { + "jest": true + } +} diff --git a/frontend/src/component/feature/form/__tests__/__snapshots__/strategy-input-list-test.jsx.snap b/frontend/src/component/feature/form/__tests__/__snapshots__/strategy-input-list-test.jsx.snap new file mode 100644 index 0000000000..b9410f89ce --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/__snapshots__/strategy-input-list-test.jsx.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders strategy with empty list as param 1`] = ` +
+

+ featureName +

+
+ + +
+
+`; + +exports[`renders strategy with list as param 1`] = ` +
+

+ featureName +

+ + item1 + + + item2 + +
+ + +
+
+`; diff --git a/frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx b/frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx new file mode 100644 index 0000000000..31e1032daa --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import InputList from './../strategy-input-list'; +import renderer from 'react-test-renderer'; +import { shallow } from 'enzyme'; + +it('renders strategy with list as param', () => { + const list = ['item1', 'item2']; + const name = 'featureName'; + const tree = renderer.create(); + + expect(tree).toMatchSnapshot(); +}); + +it('renders strategy with empty list as param', () => { + const list = []; + const name = 'featureName'; + const tree = renderer.create(); + + expect(tree).toMatchSnapshot(); +}); + +it('renders an item as chip', () => { + let list = ['item1']; + const name = 'featureName'; + let wrapper = shallow(); + expect(wrapper.find('react-mdl-Chip').length).toEqual(1); + expect(wrapper.find('react-mdl-Chip').text()).toEqual('item1'); +}); + +it('go inside onFocus', () => { + let list = ['item1']; + const name = 'featureName'; + const wrapper = shallow(); + let focusMock = { + preventDefault: () => {}, + stopPropagation: () => {}, + key: 'e', + }; + wrapper.find('react-mdl-Textfield').simulate('focus', focusMock); +}); + +// https://github.com/airbnb/enzyme/issues/944 +it('spy onFocus', () => { + let list = ['item1']; + const name = 'featureName'; + const onFocus = jest.spyOn(InputList.prototype, 'onFocus'); + let focusMock = { + preventDefault: () => {}, + stopPropagation: () => {}, + key: 'e', + }; + const wrapper = shallow(); + wrapper.find('react-mdl-Textfield').simulate('focus', focusMock); + expect(onFocus).toHaveBeenCalled(); +}); + +it('spy onBlur', () => { + let list = ['item1']; + const name = 'featureName'; + const onFocus = jest.spyOn(InputList.prototype, 'onBlur'); + let focusMock = { + preventDefault: () => {}, + stopPropagation: () => {}, + }; + const wrapper = shallow(); + wrapper.find('react-mdl-Textfield').simulate('blur', focusMock); + expect(onFocus).toHaveBeenCalled(); +}); diff --git a/frontend/src/component/feature/form/form-add-feature-component.jsx b/frontend/src/component/feature/form/form-add-feature-component.jsx index 439149dcda..addc3d9faa 100644 --- a/frontend/src/component/feature/form/form-add-feature-component.jsx +++ b/frontend/src/component/feature/form/form-add-feature-component.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { Textfield, Switch } from 'react-mdl'; import StrategiesSection from './strategies-section-container'; -import { FormButtons, getDisplayName } from './../../common'; +import { FormButtons } from './../../common'; const trim = value => { if (value && value.trim) { @@ -14,7 +14,7 @@ const trim = value => { }; class AddFeatureComponent extends Component { - static displayName = `Add2FeatureToggleComponent${getDisplayName(Component)}`; + //static displayName = `AddFeatureComponent-${getDisplayName(Component)}`; componentWillMount() { // TODO unwind this stuff if (this.props.initCallRequired === true) { diff --git a/frontend/src/component/feature/form/form-update-feature-component.jsx b/frontend/src/component/feature/form/form-update-feature-component.jsx index daca108c17..e47fa59aa7 100644 --- a/frontend/src/component/feature/form/form-update-feature-component.jsx +++ b/frontend/src/component/feature/form/form-update-feature-component.jsx @@ -2,10 +2,10 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import StrategiesSection from './strategies-section-container'; -import { FormButtons, getDisplayName } from './../../common'; +import { FormButtons } from './../../common'; class UpdateFeatureComponent extends Component { - static displayName = `AddFeatureToggleComponent${getDisplayName(Component)}`; + //static displayName = `UpdateFeatureComponent-{getDisplayName(Component)}`; componentWillMount() { // TODO unwind this stuff if (this.props.initCallRequired === true) { diff --git a/frontend/src/component/feature/form/strategies-section-container.jsx b/frontend/src/component/feature/form/strategies-section-container.jsx index 34b4afb225..ac71741718 100644 --- a/frontend/src/component/feature/form/strategies-section-container.jsx +++ b/frontend/src/component/feature/form/strategies-section-container.jsx @@ -1,10 +1,11 @@ import { connect } from 'react-redux'; -import StrategiesSection from './strategies-section'; +import StrategiesSectionComponent from './strategies-section'; import { fetchStrategies } from '../../../store/strategy/actions'; -export default connect( +const StrategiesSection = connect( state => ({ strategies: state.strategies.get('list').toArray(), }), { fetchStrategies } -)(StrategiesSection); +)(StrategiesSectionComponent); +export default StrategiesSection; diff --git a/frontend/src/component/feature/form/strategies-section.jsx b/frontend/src/component/feature/form/strategies-section.jsx index 54ea82fd06..e580fc9006 100644 --- a/frontend/src/component/feature/form/strategies-section.jsx +++ b/frontend/src/component/feature/form/strategies-section.jsx @@ -5,7 +5,7 @@ import StrategiesList from './strategies-list'; import AddStrategy from './strategies-add'; import { HeaderTitle } from '../../common'; -class StrategiesSection extends React.Component { +class StrategiesSectionComponent extends React.Component { static propTypes = { strategies: PropTypes.array.isRequired, addStrategy: PropTypes.func.isRequired, @@ -32,4 +32,4 @@ class StrategiesSection extends React.Component { } } -export default StrategiesSection; +export default StrategiesSectionComponent; diff --git a/frontend/src/component/feature/form/strategy-input-list.jsx b/frontend/src/component/feature/form/strategy-input-list.jsx index 246e407a92..f70a4e1e88 100644 --- a/frontend/src/component/feature/form/strategy-input-list.jsx +++ b/frontend/src/component/feature/form/strategy-input-list.jsx @@ -9,16 +9,16 @@ export default class InputList extends Component { setConfig: PropTypes.func.isRequired, }; - onBlur = e => { + onBlur(e) { this.setValue(e); window.removeEventListener('keydown', this.onKeyHandler, false); - }; + } - onFocus = e => { + onFocus(e) { e.preventDefault(); e.stopPropagation(); window.addEventListener('keydown', this.onKeyHandler, false); - }; + } onKeyHandler = e => { if (e.key === 'Enter') { @@ -35,10 +35,9 @@ export default class InputList extends Component { } const { name, list, setConfig } = this.props; - const inputValue = this.refs.input.inputRef; - if (inputValue && inputValue.value) { - list.push(inputValue.value); - inputValue.value = ''; + if (this.textInput && this.textInput.inputRef && this.textInput.inputRef.value) { + list.push(this.textInput.inputRef.value); + this.textInput.inputRef.value = ''; setConfig(name, list.join(',')); } }; @@ -66,9 +65,9 @@ export default class InputList extends Component { style={{ width: '100%', flex: 1 }} floatingLabel label="Add list entry" - onFocus={this.onFocus} - onBlur={this.onBlur} - ref="input" + onFocus={this.onFocus.bind(this)} + onBlur={this.onBlur.bind(this)} + ref={(input) => { this.textInput = input; }} />