diff --git a/frontend/package.json b/frontend/package.json index 07c5e565c9..fbcfe0607b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -67,6 +67,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 +94,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/__mocks__/react-mdl.js b/frontend/src/__mocks__/react-mdl.js index b8fe741af9..dde54f173c 100644 --- a/frontend/src/__mocks__/react-mdl.js +++ b/frontend/src/__mocks__/react-mdl.js @@ -13,6 +13,8 @@ module.exports = { ListItem: 'react-mdl-ListItem', ListItemContent: 'react-mdl-ListItemContent', ListItemAction: 'react-mdl-ListItemAction', + Menu: 'react-mdl-Menu', + MenuItem: 'react-mdl-MenuItem', ProgressBar: 'react-mdl-ProgressBar', Switch: 'react-mdl-Switch', Tab: 'react-mdl-Tab', diff --git a/frontend/src/component/application/application-edit-container.js b/frontend/src/component/application/application-edit-container.js index 82d9ebde37..cb9daba63d 100644 --- a/frontend/src/component/application/application-edit-container.js +++ b/frontend/src/component/application/application-edit-container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import ApplicationEdit from './application-edit-component'; -import { fetchApplication, storeApplicationMetaData } from '../../store/application/actions'; +import { fetchApplication, storeApplicationMetaData } from './../../store/application/actions'; const mapStateToProps = (state, props) => { let application = state.applications.getIn(['apps', props.appName]); diff --git a/frontend/src/component/application/application-list-container.js b/frontend/src/component/application/application-list-container.js index d213878e05..eb3809c078 100644 --- a/frontend/src/component/application/application-list-container.js +++ b/frontend/src/component/application/application-list-container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import ApplicationList from './application-list-component'; -import { fetchAll } from '../../store/application/actions'; +import { fetchAll } from './../../store/application/actions'; const mapStateToProps = state => ({ applications: state.applications.get('list').toJS() }); diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx index 95d7690849..1757dcd75a 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 { ))} ); + return strategiesList; } renderStrategiesInList(feature) { diff --git a/frontend/src/component/archive/archive-list-container.js b/frontend/src/component/archive/archive-list-container.js index 3d2ea58d3e..577187c6e5 100644 --- a/frontend/src/component/archive/archive-list-container.js +++ b/frontend/src/component/archive/archive-list-container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import ListComponent from './archive-list-component'; -import { fetchArchive, revive } from '../../store/archive-actions'; +import { fetchArchive, revive } from './../../store/archive-actions'; const mapStateToProps = state => { const archive = state.archive.get('list').toArray(); diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js index 706faf38bd..73145d6bc9 100644 --- a/frontend/src/component/common/index.js +++ b/frontend/src/component/common/index.js @@ -180,3 +180,6 @@ export function calc(value, total, decimal) { return (value / total * 100).toFixed(decimal); } +export function getDisplayName(WrappedComponent) { + return WrappedComponent.displayName || WrappedComponent.name || 'Component'; +} 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..b7bf7b1324 --- /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/feature-list-item-component.jsx b/frontend/src/component/feature/feature-list-item-component.jsx index 23991b5479..6d4a831f8a 100644 --- a/frontend/src/component/feature/feature-list-item-component.jsx +++ b/frontend/src/component/feature/feature-list-item-component.jsx @@ -52,7 +52,7 @@ const Feature = ({ {name} diff --git a/frontend/src/component/feature/form-add-component.jsx b/frontend/src/component/feature/form-add-component.jsx deleted file mode 100644 index 06139d12fe..0000000000 --- a/frontend/src/component/feature/form-add-component.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Card, CardTitle } from 'react-mdl'; - -import FormComponent from './form'; -import { styles as commonStyles } from '../common'; - -const FormAddComponent = ({ title, ...formProps }) => ( - - {title} - - -); - -FormAddComponent.propTypes = { - title: PropTypes.string, -}; - -export default FormAddComponent; 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__/form-add-feature-component-test.jsx.snap b/frontend/src/component/feature/form/__tests__/__snapshots__/form-add-feature-component-test.jsx.snap new file mode 100644 index 0000000000..32d202f00e --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/__snapshots__/form-add-feature-component-test.jsx.snap @@ -0,0 +1,555 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the create feature page 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children":
+ + +
+
+ + Enabled + +
+
+ +
+ +
, + "onSubmit": undefined, + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , + , +
+
+ + Enabled + +
+
, + , +
, + , + ], + "style": Object { + "padding": "16px", + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "error": Object {}, + "floatingLabel": true, + "label": "Name", + "name": "name", + "onBlur": [Function], + "onChange": [Function], + "required": true, + "value": "feature", + }, + "ref": null, + "rendered": null, + "type": "react-mdl-Textfield", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "floatingLabel": true, + "label": "Description", + "onChange": [Function], + "required": true, + "rows": 1, + "style": Object { + "width": "100%", + }, + "value": "Description", + }, + "ref": null, + "rendered": null, + "type": "react-mdl-Textfield", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ +
, + + Enabled + , +
, + ], + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "br", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "checked": false, + "children": "Enabled", + "onChange": [Function], + }, + "ref": null, + "rendered": "Enabled", + "type": "react-mdl-Switch", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "hr", + }, + ], + "type": "div", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "addStrategy": [MockFunction], + "configuredStrategies": Array [], + "moveStrategy": [MockFunction], + "removeStrategy": [MockFunction], + "updateStrategy": [MockFunction], + }, + "ref": null, + "rendered": null, + "type": "StrategiesSection", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "br", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object { + "onCancel": [MockFunction], + "submitText": "Create", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": "section", + }, + "type": "form", + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children":
+ + +
+
+ + Enabled + +
+
+ +
+ +
, + "onSubmit": undefined, + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , + , +
+
+ + Enabled + +
+
, + , +
, + , + ], + "style": Object { + "padding": "16px", + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "error": Object {}, + "floatingLabel": true, + "label": "Name", + "name": "name", + "onBlur": [Function], + "onChange": [Function], + "required": true, + "value": "feature", + }, + "ref": null, + "rendered": null, + "type": "react-mdl-Textfield", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "floatingLabel": true, + "label": "Description", + "onChange": [Function], + "required": true, + "rows": 1, + "style": Object { + "width": "100%", + }, + "value": "Description", + }, + "ref": null, + "rendered": null, + "type": "react-mdl-Textfield", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ +
, + + Enabled + , +
, + ], + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "br", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "checked": false, + "children": "Enabled", + "onChange": [Function], + }, + "ref": null, + "rendered": "Enabled", + "type": "react-mdl-Switch", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "hr", + }, + ], + "type": "div", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "addStrategy": [MockFunction], + "configuredStrategies": Array [], + "moveStrategy": [MockFunction], + "removeStrategy": [MockFunction], + "updateStrategy": [MockFunction], + }, + "ref": null, + "rendered": null, + "type": "StrategiesSection", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "br", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object { + "onCancel": [MockFunction], + "submitText": "Create", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": "section", + }, + "type": "form", + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + }, + }, + }, +} +`; diff --git a/frontend/src/component/feature/form/__tests__/__snapshots__/form-update-feature-component-test.jsx.snap b/frontend/src/component/feature/form/__tests__/__snapshots__/form-update-feature-component-test.jsx.snap new file mode 100644 index 0000000000..8125a56293 --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/__snapshots__/form-update-feature-component-test.jsx.snap @@ -0,0 +1,245 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`render the create feature page 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children":
+ +
+ +
, + "onSubmit": undefined, + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , +
, + , + ], + "style": Object { + "padding": "16px", + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "addStrategy": [MockFunction], + "configuredStrategies": Array [], + "moveStrategy": [MockFunction], + "removeStrategy": [MockFunction], + "updateStrategy": [MockFunction], + }, + "ref": null, + "rendered": null, + "type": "StrategiesSection", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "br", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object { + "onCancel": [MockFunction], + "submitText": "Update", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": "section", + }, + "type": "form", + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children":
+ +
+ +
, + "onSubmit": undefined, + }, + "ref": null, + "rendered": Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , +
, + , + ], + "style": Object { + "padding": "16px", + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "addStrategy": [MockFunction], + "configuredStrategies": Array [], + "moveStrategy": [MockFunction], + "removeStrategy": [MockFunction], + "updateStrategy": [MockFunction], + }, + "ref": null, + "rendered": null, + "type": "StrategiesSection", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object {}, + "ref": null, + "rendered": null, + "type": "br", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "function", + "props": Object { + "onCancel": [MockFunction], + "submitText": "Update", + }, + "ref": null, + "rendered": null, + "type": [Function], + }, + ], + "type": "section", + }, + "type": "form", + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": true, + }, + }, + }, +} +`; diff --git a/frontend/src/component/feature/form/__tests__/__snapshots__/strategy-add-test.jsx.snap b/frontend/src/component/feature/form/__tests__/__snapshots__/strategy-add-test.jsx.snap new file mode 100644 index 0000000000..b0d06f4124 --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/__snapshots__/strategy-add-test.jsx.snap @@ -0,0 +1,296 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders add strategy form with a list of available strategies 1`] = ` +ShallowWrapper { + "length": 1, + Symbol(enzyme.__root__): [Circular], + Symbol(enzyme.__unrendered__): , + Symbol(enzyme.__renderer__): Object { + "batchedUpdates": [Function], + "getNode": [Function], + "render": [Function], + "simulateEvent": [Function], + "unmount": [Function], + }, + Symbol(enzyme.__node__): Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , + + + Add Strategy: + + + default + + , + ], + "style": Object { + "display": "inline-block", + "height": "25px", + "position": "relative", + "width": "25px", + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "accent": true, + "id": "strategies-add", + "name": "add", + "onClick": [Function], + "raised": true, + "title": "Add Strategy", + }, + "ref": null, + "rendered": null, + "type": "react-mdl-IconButton", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "align": "right", + "children": Array [ + + Add Strategy: + , + Array [ + + default + , + ], + ], + "ripple": true, + "style": Object { + "backgroundColor": "rgb(247, 248, 255)", + "maxHeight": "300px", + "overflowY": "auto", + }, + "target": "strategies-add", + "valign": "bottom", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": "Add Strategy:", + "disabled": true, + }, + "ref": null, + "rendered": "Add Strategy:", + "type": "react-mdl-MenuItem", + }, + Object { + "instance": null, + "key": "default", + "nodeType": "host", + "props": Object { + "children": "default", + "onClick": [Function], + "title": "Default on/off strategy.", + }, + "ref": null, + "rendered": "default", + "type": "react-mdl-MenuItem", + }, + ], + "type": "react-mdl-Menu", + }, + ], + "type": "div", + }, + Symbol(enzyme.__nodes__): Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": Array [ + , + + + Add Strategy: + + + default + + , + ], + "style": Object { + "display": "inline-block", + "height": "25px", + "position": "relative", + "width": "25px", + }, + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "accent": true, + "id": "strategies-add", + "name": "add", + "onClick": [Function], + "raised": true, + "title": "Add Strategy", + }, + "ref": null, + "rendered": null, + "type": "react-mdl-IconButton", + }, + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "align": "right", + "children": Array [ + + Add Strategy: + , + Array [ + + default + , + ], + ], + "ripple": true, + "style": Object { + "backgroundColor": "rgb(247, 248, 255)", + "maxHeight": "300px", + "overflowY": "auto", + }, + "target": "strategies-add", + "valign": "bottom", + }, + "ref": null, + "rendered": Array [ + Object { + "instance": null, + "key": undefined, + "nodeType": "host", + "props": Object { + "children": "Add Strategy:", + "disabled": true, + }, + "ref": null, + "rendered": "Add Strategy:", + "type": "react-mdl-MenuItem", + }, + Object { + "instance": null, + "key": "default", + "nodeType": "host", + "props": Object { + "children": "default", + "onClick": [Function], + "title": "Default on/off strategy.", + }, + "ref": null, + "rendered": "default", + "type": "react-mdl-MenuItem", + }, + ], + "type": "react-mdl-Menu", + }, + ], + "type": "div", + }, + ], + Symbol(enzyme.__options__): Object { + "adapter": ReactSixteenAdapter { + "options": Object { + "enableComponentDidUpdateOnSetState": 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__/form-add-feature-component-test.jsx b/frontend/src/component/feature/form/__tests__/form-add-feature-component-test.jsx new file mode 100644 index 0000000000..52b4f03dc5 --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/form-add-feature-component-test.jsx @@ -0,0 +1,124 @@ +import React from 'react'; +import AddFeatureComponent from './../form-add-feature-component'; +import { shallow } from 'enzyme/build/index'; + +jest.mock('react-mdl'); +jest.mock('../strategies-section-container', () => 'StrategiesSection'); + +it('render the create feature page', () => { + let input = { + name: 'feature', + nameError: {}, + description: 'Description', + enabled: false, + }; + const tree = shallow( + + ); + expect(tree).toMatchSnapshot(); +}); + +let input = { + name: 'feature', + nameError: {}, + description: 'Description', + enabled: false, +}; + +let validateName = jest.fn(); +let setValue = jest.fn(); +let onSubmit = jest.fn(); +let addStrategy = jest.fn(); +let removeStrategy = jest.fn(); +let moveStrategy = jest.fn(); +let onCancel = jest.fn(); +let updateStratgy = jest.fn(); +let init = jest.fn(); +let eventMock = { + preventDefault: () => {}, + stopPropagation: () => {}, + target: { + name: 'NAME', + }, +}; +const buildComponent = (setValue, validateName) => ( + +); + +it('add a feature name with validation', () => { + let called = false; + validateName = () => { + called = true; + }; + const wrapper = shallow(buildComponent(setValue, validateName)); + wrapper + .find('react-mdl-Textfield') + .first() + .simulate('blur', eventMock); + expect(called).toBe(true); +}); + +it('set a value for feature name', () => { + let called = false; + setValue = () => { + called = true; + }; + let wrapper = shallow(buildComponent(setValue, validateName)); + wrapper + .find('react-mdl-Textfield') + .first() + .simulate('change', eventMock); + expect(called).toBe(true); +}); + +it('set a description for feature name', () => { + let called = false; + setValue = () => { + called = true; + }; + let wrapper = shallow(buildComponent(setValue, validateName)); + wrapper + .find('react-mdl-Textfield') + .last() + .simulate('change', eventMock); + expect(called).toBe(true); +}); + +it('switch the toggle', () => { + let called = false; + setValue = () => { + called = true; + }; + let wrapper = shallow(buildComponent(setValue, validateName)); + eventMock.target.enabled = false; + wrapper + .find('react-mdl-Switch') + .last() + .simulate('change', eventMock); + expect(called).toBe(true); +}); diff --git a/frontend/src/component/feature/form/__tests__/form-update-feature-component-test.jsx b/frontend/src/component/feature/form/__tests__/form-update-feature-component-test.jsx new file mode 100644 index 0000000000..845fed1c53 --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/form-update-feature-component-test.jsx @@ -0,0 +1,31 @@ +import React from 'react'; +import UpdateFeatureComponent from './../form-update-feature-component'; +import { shallow } from 'enzyme/build/index'; + +jest.mock('react-mdl'); +jest.mock('../strategies-section-container', () => 'StrategiesSection'); + +it('render the create feature page', () => { + let input = { + name: 'feature', + nameError: {}, + description: 'Description', + enabled: false, + }; + const tree = shallow( + + ); + expect(tree).toMatchSnapshot(); +}); diff --git a/frontend/src/component/feature/form/__tests__/strategy-add-test.jsx b/frontend/src/component/feature/form/__tests__/strategy-add-test.jsx new file mode 100644 index 0000000000..46a35c6130 --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/strategy-add-test.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import AddStrategy from './../strategies-add'; +import { shallow } from 'enzyme/build/index'; + +jest.mock('react-mdl'); + +const strategies = [ + { + name: 'default', + editable: false, + description: 'Default on/off strategy.', + parameters: ['t'], + }, +]; +let addStrategy = jest.fn(); +let fetchStrategies = jest.fn(); +let eventMock = { + preventDefault: () => {}, + stopPropagation: () => {}, + target: { + name: 'default', + }, +}; +const buildComponent = (addStrategy, fetchStrategies, strategies) => ( + +); + +it('renders add strategy form with a list of available strategies', () => { + const tree = shallow(buildComponent(addStrategy, fetchStrategies, strategies)); + expect(tree).toMatchSnapshot(); +}); + +it('add a strategy', () => { + let called = false; + addStrategy = () => { + called = true; + }; + const addStrategyProto = jest.spyOn(AddStrategy.prototype, 'addStrategy'); + const wrapper = shallow(buildComponent(addStrategy, fetchStrategies, strategies)); + wrapper + .find('react-mdl-MenuItem') + .last() + .simulate('click', eventMock); + expect(called).toBe(true); + expect(addStrategyProto).toHaveBeenCalled(); +}); 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..ad49344c7c --- /dev/null +++ b/frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx @@ -0,0 +1,81 @@ +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(); +}); + +it('spy onClose', () => { + let list = ['item1']; + const name = 'featureName'; + const onClose = jest.spyOn(InputList.prototype, 'onClose'); + let closeMock = { + preventDefault: () => {}, + stopPropagation: () => {}, + }; + const wrapper = shallow(); + wrapper.find('react-mdl-Chip').simulate('close', closeMock); + expect(onClose).toHaveBeenCalled(); +}); diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/form-add-feature-component.jsx similarity index 74% rename from frontend/src/component/feature/form/index.jsx rename to frontend/src/component/feature/form/form-add-feature-component.jsx index 366227d139..03b8bc99e9 100644 --- a/frontend/src/component/feature/form/index.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 } from '../../common'; +import { FormButtons } from './../../common'; const trim = value => { if (value && value.trim) { @@ -13,7 +13,8 @@ const trim = value => { } }; -class AddFeatureToggleComponent extends Component { +class AddFeatureComponent extends Component { + // static displayName = `AddFeatureComponent-${getDisplayName(Component)}`; componentWillMount() { // TODO unwind this stuff if (this.props.initCallRequired === true) { @@ -32,7 +33,6 @@ class AddFeatureToggleComponent extends Component { moveStrategy, onSubmit, onCancel, - editmode = false, } = this.props; const { @@ -50,14 +50,12 @@ class AddFeatureToggleComponent extends Component { floatingLabel label="Name" name="name" - disabled={editmode} required value={name} error={nameError} onBlur={v => validateName(v.target.value)} onChange={v => setValue('name', trim(v.target.value))} /> -
setValue('description', v.target.value)} /> +
+
+ { + setValue('enabled', !enabled); + }} + > + Enabled + +
+
- {!editmode && ( -
-
- { - setValue('enabled', !enabled); - }} - > - Enabled - -
-
- )}
- + ); } } -AddFeatureToggleComponent.propTypes = { +AddFeatureComponent.propTypes = { input: PropTypes.object, setValue: PropTypes.func.isRequired, addStrategy: PropTypes.func.isRequired, @@ -108,9 +104,8 @@ AddFeatureToggleComponent.propTypes = { onSubmit: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired, validateName: PropTypes.func.isRequired, - editmode: PropTypes.bool, initCallRequired: PropTypes.bool, init: PropTypes.func, }; -export default AddFeatureToggleComponent; +export default AddFeatureComponent; diff --git a/frontend/src/component/feature/form-add-container.jsx b/frontend/src/component/feature/form/form-add-feature-container.jsx similarity index 81% rename from frontend/src/component/feature/form-add-container.jsx rename to frontend/src/component/feature/form/form-add-feature-container.jsx index d058ce0cf8..8361e1f0ea 100644 --- a/frontend/src/component/feature/form-add-container.jsx +++ b/frontend/src/component/feature/form/form-add-feature-container.jsx @@ -1,8 +1,8 @@ import { connect } from 'react-redux'; import { hashHistory } from 'react-router'; -import { createFeatureToggles, validateName } from '../../store/feature-actions'; -import { createMapper, createActions } from '../input-helpers'; -import FormAddComponent from './form-add-component'; +import { createFeatureToggles, validateName } from './../../../store/feature-actions'; +import { createMapper, createActions } from './../../input-helpers'; +import AddFeatureComponent from './form-add-feature-component'; const ID = 'add-feature-toggle'; const mapStateToProps = createMapper({ @@ -31,7 +31,7 @@ const prepare = (methods, dispatch) => { createFeatureToggles(input)(dispatch) .then(() => methods.clear()) - .then(() => hashHistory.push(`/features/edit/${input.name}`)); + .then(() => hashHistory.push(`/features/strategies/${input.name}`)); }; methods.onCancel = evt => { @@ -67,6 +67,6 @@ const prepare = (methods, dispatch) => { }; const actions = createActions({ id: ID, prepare }); -const FormAddContainer = connect(mapStateToProps, actions)(FormAddComponent); +const FormAddContainer = connect(mapStateToProps, actions)(AddFeatureComponent); export default FormAddContainer; diff --git a/frontend/src/component/feature/form/form-update-feature-component.jsx b/frontend/src/component/feature/form/form-update-feature-component.jsx new file mode 100644 index 0000000000..b624f340ef --- /dev/null +++ b/frontend/src/component/feature/form/form-update-feature-component.jsx @@ -0,0 +1,57 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import StrategiesSection from './strategies-section-container'; + +import { FormButtons } from './../../common'; + +class UpdateFeatureComponent extends Component { + // static displayName = `UpdateFeatureComponent-{getDisplayName(Component)}`; + componentWillMount() { + // TODO unwind this stuff + if (this.props.initCallRequired === true) { + this.props.init(this.props.input); + } + } + + render() { + const { input, addStrategy, removeStrategy, updateStrategy, moveStrategy, onSubmit, onCancel } = this.props; + + const { + name, // eslint-disable-line + } = input; + const configuredStrategies = input.strategies || []; + + return ( +
+
+ + +
+ +
+
+ ); + } +} + +UpdateFeatureComponent.propTypes = { + input: PropTypes.object, + setValue: PropTypes.func.isRequired, + addStrategy: PropTypes.func.isRequired, + removeStrategy: PropTypes.func.isRequired, + moveStrategy: PropTypes.func.isRequired, + updateStrategy: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + validateName: PropTypes.func.isRequired, + initCallRequired: PropTypes.bool, + init: PropTypes.func, +}; + +export default UpdateFeatureComponent; diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form/form-update-feature-container.jsx similarity index 82% rename from frontend/src/component/feature/form-edit-container.jsx rename to frontend/src/component/feature/form/form-update-feature-container.jsx index ee3d9e7e6c..58c755487e 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form/form-update-feature-container.jsx @@ -1,9 +1,9 @@ import { connect } from 'react-redux'; import { hashHistory } from 'react-router'; -import { requestUpdateFeatureToggle } from '../../store/feature-actions'; -import { createMapper, createActions } from '../input-helpers'; -import FormComponent from './form'; +import { requestUpdateFeatureToggle } from '../../../store/feature-actions'; +import { createMapper, createActions } from '../../input-helpers'; +import UpdateFeatureToggleComponent from './form-update-feature-component'; const ID = 'edit-feature-toggle'; function getId(props) { @@ -34,10 +34,12 @@ const prepare = (methods, dispatch) => { delete s.id; }); } + delete input.description; + // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) - .then(() => hashHistory.push(`/features/view/${input.name}`)); + .then(() => hashHistory.push(`/features`)); }; methods.onCancel = evt => { @@ -73,4 +75,4 @@ const actions = createActions({ prepare, }); -export default connect(mapStateToProps, actions)(FormComponent); +export default connect(mapStateToProps, actions)(UpdateFeatureToggleComponent); diff --git a/frontend/src/component/feature/form/strategies-add.jsx b/frontend/src/component/feature/form/strategies-add.jsx index a75de9fdc9..aac8731fb5 100644 --- a/frontend/src/component/feature/form/strategies-add.jsx +++ b/frontend/src/component/feature/form/strategies-add.jsx @@ -9,7 +9,7 @@ class AddStrategy extends React.Component { fetchStrategies: PropTypes.func.isRequired, }; - addStrategy = strategyName => { + addStrategy(strategyName) { const selectedStrategy = this.props.strategies.find(s => s.name === strategyName); const parameters = {}; @@ -21,7 +21,7 @@ class AddStrategy extends React.Component { name: selectedStrategy.name, parameters, }); - }; + } stopPropagation(e) { e.stopPropagation(); 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..102b61eb6e 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,11 @@ 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; + }} /> ; - } else if (TABS[activeTab] === TABS.edit) { + } else if (TABS[activeTab] === TABS.strategies) { return ; } else { return ; @@ -56,6 +57,7 @@ export default class ViewFeatureToggleComponent extends React.Component { featureToggle, features, activeTab, + // setValue, featureToggleName, toggleFeature, removeFeatureToggle, @@ -80,7 +82,7 @@ export default class ViewFeatureToggleComponent extends React.Component { ); } - const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.view; + const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.strategies; const tabContent = this.getTabContent(activeTab); const removeToggle = () => { @@ -92,11 +94,37 @@ export default class ViewFeatureToggleComponent extends React.Component { hashHistory.push('/features'); } }; + const updateFeatureToggle = () => { + let feature = { ...featureToggle }; + if (Array.isArray(feature.strategies)) { + feature.strategies.forEach(s => { + delete s.id; + }); + } + + this.props.editFeatureToggle(feature); + }; + const setValue = (v, event) => { + featureToggle[v] = event.target.value; + this.forceUpdate(); + }; return ( {featureToggle.name} - {featureToggle.description} + + setValue('description', v)} + onBlur={updateFeatureToggle} + /> + + + this.goToTab('strategies', featureToggleName)}>Strategies this.goToTab('view', featureToggleName)}>Metrics - this.goToTab('edit', featureToggleName)}>Edit this.goToTab('history', featureToggleName)}>History {tabContent} diff --git a/frontend/src/component/feature/view-container.jsx b/frontend/src/component/feature/view-container.jsx index 8310b6bf14..f8a33ae007 100644 --- a/frontend/src/component/feature/view-container.jsx +++ b/frontend/src/component/feature/view-container.jsx @@ -1,6 +1,11 @@ import { connect } from 'react-redux'; -import { fetchFeatureToggles, toggleFeature, removeFeatureToggle } from '../../store/feature-actions'; +import { + fetchFeatureToggles, + toggleFeature, + removeFeatureToggle, + editFeatureToggle, +} from './../../store/feature-actions'; import ViewToggleComponent from './view-component'; @@ -14,5 +19,6 @@ export default connect( fetchFeatureToggles, toggleFeature, removeFeatureToggle, + editFeatureToggle, } )(ViewToggleComponent); diff --git a/frontend/src/component/history/history-container.js b/frontend/src/component/history/history-container.js index 0197b14bca..ee79b6cd61 100644 --- a/frontend/src/component/history/history-container.js +++ b/frontend/src/component/history/history-container.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import HistoryComponent from './history-component'; -import { fetchHistory } from '../../store/history-actions'; +import { fetchHistory } from './../../store/history-actions'; const mapStateToProps = state => { const history = state.history.get('list').toArray(); diff --git a/frontend/src/component/strategies/add-container.js b/frontend/src/component/strategies/add-container.js index e7d5a0e8fc..b6e74ad1f3 100644 --- a/frontend/src/component/strategies/add-container.js +++ b/frontend/src/component/strategies/add-container.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; -import { createMapper, createActions } from '../input-helpers'; -import { createStrategy } from '../../store/strategy/actions'; +import { createMapper, createActions } from './../input-helpers'; +import { createStrategy } from './../../store/strategy/actions'; import AddStrategy from './add-strategy'; diff --git a/frontend/src/component/strategies/list-container.jsx b/frontend/src/component/strategies/list-container.jsx index 51b6f69381..aec2cf3791 100644 --- a/frontend/src/component/strategies/list-container.jsx +++ b/frontend/src/component/strategies/list-container.jsx @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import StrategiesListComponent from './list-component.jsx'; -import { fetchStrategies, removeStrategy } from '../../store/strategy/actions'; +import { fetchStrategies, removeStrategy } from './../../store/strategy/actions'; const mapStateToProps = state => { const list = state.strategies.get('list').toArray(); diff --git a/frontend/src/component/strategies/strategy-details-component.jsx b/frontend/src/component/strategies/strategy-details-component.jsx index 967830be70..c9762b8e05 100644 --- a/frontend/src/component/strategies/strategy-details-component.jsx +++ b/frontend/src/component/strategies/strategy-details-component.jsx @@ -54,7 +54,7 @@ export default class StrategyDetails extends Component { } render() { - const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.view; + const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.strategies; const strategy = this.props.strategy; if (!strategy) { return ; diff --git a/frontend/src/component/strategies/strategy-details-container.js b/frontend/src/component/strategies/strategy-details-container.js index 0f3eabef5e..486b6e3a06 100644 --- a/frontend/src/component/strategies/strategy-details-container.js +++ b/frontend/src/component/strategies/strategy-details-container.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux'; import ShowStrategy from './strategy-details-component'; -import { fetchStrategies } from '../../store/strategy/actions'; -import { fetchAll } from '../../store/application/actions'; -import { fetchFeatureToggles } from '../../store/feature-actions'; +import { fetchStrategies } from './../../store/strategy/actions'; +import { fetchAll } from './../../store/application/actions'; +import { fetchFeatureToggles } from './../../store/feature-actions'; const mapStateToProps = (state, props) => { let strategy = state.strategies.get('list').find(n => n.name === props.strategyName); diff --git a/frontend/src/page/features/create.js b/frontend/src/page/features/create.js index cab5811e62..7e65314b7d 100644 --- a/frontend/src/page/features/create.js +++ b/frontend/src/page/features/create.js @@ -1,5 +1,5 @@ import React from 'react'; -import AddFeatureToggleForm from '../../component/feature/form-add-container'; +import AddFeatureToggleForm from '../../component/feature/form/form-add-feature-container'; const render = () => ; diff --git a/frontend/src/page/features/index.js b/frontend/src/page/features/index.js index 764327ced3..ccd602443e 100644 --- a/frontend/src/page/features/index.js +++ b/frontend/src/page/features/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import FeatureListContainer from '../../component/feature/list-container'; +import FeatureListContainer from './../../component/feature/list-container'; const render = () => ; diff --git a/frontend/src/page/features/show.js b/frontend/src/page/features/show.js index b17f57861a..4143c1f289 100644 --- a/frontend/src/page/features/show.js +++ b/frontend/src/page/features/show.js @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import ViewFeatureToggle from '../../component/feature/view-container'; +import ViewFeatureToggle from './../../component/feature/view-container'; export default class Features extends PureComponent { static propTypes = { diff --git a/frontend/src/setupTests.js b/frontend/src/setupTests.js new file mode 100644 index 0000000000..82edfc9e5a --- /dev/null +++ b/frontend/src/setupTests.js @@ -0,0 +1,4 @@ +import { configure } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +configure({ adapter: new Adapter() });