From 4dd033c30e7bc9293a8d1ee344cb32cd36c18de2 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sun, 11 Feb 2018 17:56:00 +0100 Subject: [PATCH 01/17] fix(feature): display strategies tab as default --- .../feature/feature-list-item-component.jsx | 2 +- .../component/feature/form-edit-container.jsx | 2 +- frontend/src/component/feature/form/index.jsx | 28 +------------------ .../src/component/feature/view-component.jsx | 10 +++---- .../strategies/strategy-details-component.jsx | 2 +- 5 files changed, 9 insertions(+), 35 deletions(-) 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-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index ee3d9e7e6c..21681a77b8 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -37,7 +37,7 @@ const prepare = (methods, dispatch) => { // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) - .then(() => hashHistory.push(`/features/view/${input.name}`)); + .then(() => hashHistory.push(`/features/strategies/${input.name}`)); }; methods.onCancel = evt => { diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 366227d139..07217e4550 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -5,14 +5,6 @@ import StrategiesSection from './strategies-section-container'; import { FormButtons } from '../../common'; -const trim = value => { - if (value && value.trim) { - return value.trim(); - } else { - return value; - } -}; - class AddFeatureToggleComponent extends Component { componentWillMount() { // TODO unwind this stuff @@ -25,7 +17,6 @@ class AddFeatureToggleComponent extends Component { const { input, setValue, - validateName, addStrategy, removeStrategy, updateStrategy, @@ -35,29 +26,12 @@ class AddFeatureToggleComponent extends Component { editmode = false, } = this.props; - const { - name, // eslint-disable-line - nameError, - description, - enabled, - } = input; + const { description, enabled } = input; const configuredStrategies = input.strategies || []; return (
- validateName(v.target.value)} - onChange={v => setValue('name', trim(v.target.value))} - /> -
; - } else if (TABS[activeTab] === TABS.edit) { + } else if (TABS[activeTab] === TABS.strategies) { return ; } else { return ; @@ -80,7 +80,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 = () => { @@ -125,8 +125,8 @@ export default class ViewFeatureToggleComponent extends React.Component { tabBarProps={{ style: { width: '100%' } }} className="mdl-color--grey-100" > + 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/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 ; From 2781c4304c4c0183c138cf8015f458daa9b74115 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sun, 11 Feb 2018 18:31:48 +0100 Subject: [PATCH 02/17] fix(feature): naviagation issue when updating feature --- frontend/src/component/feature/form-edit-container.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index 21681a77b8..9b68e43b33 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -37,6 +37,7 @@ const prepare = (methods, dispatch) => { // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) + .then(() => hashHistory.push(`/features`)) .then(() => hashHistory.push(`/features/strategies/${input.name}`)); }; From ea5858b33dc981c7ea847513785dbf5ebfe2669a Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sun, 11 Feb 2018 18:35:26 +0100 Subject: [PATCH 03/17] fix(feature): remove duplicate description in feature deatil view --- frontend/src/component/feature/view-component.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index 2387b71050..54c5a88898 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -96,7 +96,6 @@ export default class ViewFeatureToggleComponent extends React.Component { return ( {featureToggle.name} - {featureToggle.description} Date: Mon, 12 Feb 2018 09:23:50 +0100 Subject: [PATCH 04/17] fix(feature): get rid of the regression, create feature can have a name --- frontend/src/component/feature/form/index.jsx | 29 ++++++++++++++++++- .../src/component/feature/view-component.jsx | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 07217e4550..1d2c249f22 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -5,6 +5,14 @@ import StrategiesSection from './strategies-section-container'; import { FormButtons } from '../../common'; +const trim = value => { + if (value && value.trim) { + return value.trim(); + } else { + return value; + } +}; + class AddFeatureToggleComponent extends Component { componentWillMount() { // TODO unwind this stuff @@ -17,6 +25,7 @@ class AddFeatureToggleComponent extends Component { const { input, setValue, + validateName, addStrategy, removeStrategy, updateStrategy, @@ -26,12 +35,30 @@ class AddFeatureToggleComponent extends Component { editmode = false, } = this.props; - const { description, enabled } = input; + const { + name, // eslint-disable-line + nameError, + description, + enabled, + } = input; const configuredStrategies = input.strategies || []; return (
+ {!editmode && ( + validateName(v.target.value)} + onChange={v => setValue('name', trim(v.target.value))} + /> + )} Date: Thu, 15 Feb 2018 17:09:00 +0100 Subject: [PATCH 05/17] fixt(feature): move description outside of strategies block --- .../component/feature/form-add-container.jsx | 2 +- .../component/feature/form-edit-container.jsx | 4 +++ frontend/src/component/feature/form/index.jsx | 23 +++++++------- .../src/component/feature/view-component.jsx | 31 ++++++++++++++++++- .../src/component/feature/view-container.jsx | 8 ++++- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/frontend/src/component/feature/form-add-container.jsx b/frontend/src/component/feature/form-add-container.jsx index d058ce0cf8..9699f49c36 100644 --- a/frontend/src/component/feature/form-add-container.jsx +++ b/frontend/src/component/feature/form-add-container.jsx @@ -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 => { diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index 9b68e43b33..f75961dad4 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -34,6 +34,10 @@ const prepare = (methods, dispatch) => { delete s.id; }); } + if (input.editmode) { + delete input.description; + } + // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 1d2c249f22..43d6575874 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -42,7 +42,7 @@ class AddFeatureToggleComponent extends Component { enabled, } = input; const configuredStrategies = input.strategies || []; - + input.editmode = editmode; return (
@@ -59,16 +59,17 @@ class AddFeatureToggleComponent extends Component { onChange={v => setValue('name', trim(v.target.value))} /> )} - setValue('description', v.target.value)} - /> - + {!editmode && ( + setValue('description', v.target.value)} + /> + )} {!editmode && (

diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index b9a0ee1931..b186460892 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Tabs, Tab, ProgressBar, Button, Card, CardTitle, CardActions, Switch } from 'react-mdl'; +import { Tabs, Tab, ProgressBar, Button, Card, CardText, CardTitle, CardActions, Textfield, Switch } from 'react-mdl'; import { hashHistory, Link } from 'react-router'; import HistoryComponent from '../history/history-list-toggle-container'; @@ -26,6 +26,7 @@ export default class ViewFeatureToggleComponent extends React.Component { toggleFeature: PropTypes.func.isRequired, removeFeatureToggle: PropTypes.func.isRequired, fetchFeatureToggles: PropTypes.func.isRequired, + editFeatureToggle: PropTypes.func.isRequired, featureToggle: PropTypes.object, }; @@ -56,6 +57,7 @@ export default class ViewFeatureToggleComponent extends React.Component { featureToggle, features, activeTab, + // setValue, featureToggleName, toggleFeature, removeFeatureToggle, @@ -92,10 +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} + + setValue('description', v)} + onBlur={updateFeatureToggle} + /> + + Date: Thu, 15 Feb 2018 17:28:09 +0100 Subject: [PATCH 06/17] clean(feature): remove unused code --- frontend/src/component/feature/form-edit-container.jsx | 4 +--- frontend/src/component/feature/form/index.jsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index f75961dad4..eb0821f723 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -34,9 +34,7 @@ const prepare = (methods, dispatch) => { delete s.id; }); } - if (input.editmode) { - delete input.description; - } + delete input.description; // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 43d6575874..4f0ec44809 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -42,7 +42,7 @@ class AddFeatureToggleComponent extends Component { enabled, } = input; const configuredStrategies = input.strategies || []; - input.editmode = editmode; + return (
From 056cb4cda234349ba9458611cf3a6796b0b41113 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sun, 11 Feb 2018 17:56:00 +0100 Subject: [PATCH 07/17] fix(feature): display strategies tab as default --- .../feature/feature-list-item-component.jsx | 2 +- .../component/feature/form-edit-container.jsx | 2 +- frontend/src/component/feature/form/index.jsx | 28 +------------------ .../src/component/feature/view-component.jsx | 10 +++---- .../strategies/strategy-details-component.jsx | 2 +- 5 files changed, 9 insertions(+), 35 deletions(-) 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-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index ee3d9e7e6c..21681a77b8 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -37,7 +37,7 @@ const prepare = (methods, dispatch) => { // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) - .then(() => hashHistory.push(`/features/view/${input.name}`)); + .then(() => hashHistory.push(`/features/strategies/${input.name}`)); }; methods.onCancel = evt => { diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 366227d139..07217e4550 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -5,14 +5,6 @@ import StrategiesSection from './strategies-section-container'; import { FormButtons } from '../../common'; -const trim = value => { - if (value && value.trim) { - return value.trim(); - } else { - return value; - } -}; - class AddFeatureToggleComponent extends Component { componentWillMount() { // TODO unwind this stuff @@ -25,7 +17,6 @@ class AddFeatureToggleComponent extends Component { const { input, setValue, - validateName, addStrategy, removeStrategy, updateStrategy, @@ -35,29 +26,12 @@ class AddFeatureToggleComponent extends Component { editmode = false, } = this.props; - const { - name, // eslint-disable-line - nameError, - description, - enabled, - } = input; + const { description, enabled } = input; const configuredStrategies = input.strategies || []; return (
- validateName(v.target.value)} - onChange={v => setValue('name', trim(v.target.value))} - /> -
; - } else if (TABS[activeTab] === TABS.edit) { + } else if (TABS[activeTab] === TABS.strategies) { return ; } else { return ; @@ -80,7 +80,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 = () => { @@ -125,8 +125,8 @@ export default class ViewFeatureToggleComponent extends React.Component { tabBarProps={{ style: { width: '100%' } }} className="mdl-color--grey-100" > + 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/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 ; From 63e0fc65684285fc5b0f43d7533bc76a8f57fd2e Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sun, 11 Feb 2018 18:31:48 +0100 Subject: [PATCH 08/17] fix(feature): naviagation issue when updating feature --- frontend/src/component/feature/form-edit-container.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index 21681a77b8..9b68e43b33 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -37,6 +37,7 @@ const prepare = (methods, dispatch) => { // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) + .then(() => hashHistory.push(`/features`)) .then(() => hashHistory.push(`/features/strategies/${input.name}`)); }; From ae252a7ad3efea41941e3a716ef3090d557d9825 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sun, 11 Feb 2018 18:35:26 +0100 Subject: [PATCH 09/17] fix(feature): remove duplicate description in feature deatil view --- frontend/src/component/feature/view-component.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index 2387b71050..54c5a88898 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -96,7 +96,6 @@ export default class ViewFeatureToggleComponent extends React.Component { return ( {featureToggle.name} - {featureToggle.description} Date: Mon, 12 Feb 2018 09:23:50 +0100 Subject: [PATCH 10/17] fix(feature): get rid of the regression, create feature can have a name --- frontend/src/component/feature/form/index.jsx | 29 ++++++++++++++++++- .../src/component/feature/view-component.jsx | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 07217e4550..1d2c249f22 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -5,6 +5,14 @@ import StrategiesSection from './strategies-section-container'; import { FormButtons } from '../../common'; +const trim = value => { + if (value && value.trim) { + return value.trim(); + } else { + return value; + } +}; + class AddFeatureToggleComponent extends Component { componentWillMount() { // TODO unwind this stuff @@ -17,6 +25,7 @@ class AddFeatureToggleComponent extends Component { const { input, setValue, + validateName, addStrategy, removeStrategy, updateStrategy, @@ -26,12 +35,30 @@ class AddFeatureToggleComponent extends Component { editmode = false, } = this.props; - const { description, enabled } = input; + const { + name, // eslint-disable-line + nameError, + description, + enabled, + } = input; const configuredStrategies = input.strategies || []; return (
+ {!editmode && ( + validateName(v.target.value)} + onChange={v => setValue('name', trim(v.target.value))} + /> + )} Date: Thu, 15 Feb 2018 17:09:00 +0100 Subject: [PATCH 11/17] fixt(feature): move description outside of strategies block --- .../component/feature/form-add-container.jsx | 2 +- .../component/feature/form-edit-container.jsx | 4 +++ frontend/src/component/feature/form/index.jsx | 23 +++++++------- .../src/component/feature/view-component.jsx | 31 ++++++++++++++++++- .../src/component/feature/view-container.jsx | 8 ++++- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/frontend/src/component/feature/form-add-container.jsx b/frontend/src/component/feature/form-add-container.jsx index d058ce0cf8..9699f49c36 100644 --- a/frontend/src/component/feature/form-add-container.jsx +++ b/frontend/src/component/feature/form-add-container.jsx @@ -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 => { diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index 9b68e43b33..f75961dad4 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -34,6 +34,10 @@ const prepare = (methods, dispatch) => { delete s.id; }); } + if (input.editmode) { + delete input.description; + } + // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 1d2c249f22..43d6575874 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -42,7 +42,7 @@ class AddFeatureToggleComponent extends Component { enabled, } = input; const configuredStrategies = input.strategies || []; - + input.editmode = editmode; return (
@@ -59,16 +59,17 @@ class AddFeatureToggleComponent extends Component { onChange={v => setValue('name', trim(v.target.value))} /> )} - setValue('description', v.target.value)} - /> - + {!editmode && ( + setValue('description', v.target.value)} + /> + )} {!editmode && (

diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index b9a0ee1931..b186460892 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Tabs, Tab, ProgressBar, Button, Card, CardTitle, CardActions, Switch } from 'react-mdl'; +import { Tabs, Tab, ProgressBar, Button, Card, CardText, CardTitle, CardActions, Textfield, Switch } from 'react-mdl'; import { hashHistory, Link } from 'react-router'; import HistoryComponent from '../history/history-list-toggle-container'; @@ -26,6 +26,7 @@ export default class ViewFeatureToggleComponent extends React.Component { toggleFeature: PropTypes.func.isRequired, removeFeatureToggle: PropTypes.func.isRequired, fetchFeatureToggles: PropTypes.func.isRequired, + editFeatureToggle: PropTypes.func.isRequired, featureToggle: PropTypes.object, }; @@ -56,6 +57,7 @@ export default class ViewFeatureToggleComponent extends React.Component { featureToggle, features, activeTab, + // setValue, featureToggleName, toggleFeature, removeFeatureToggle, @@ -92,10 +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} + + setValue('description', v)} + onBlur={updateFeatureToggle} + /> + + Date: Thu, 15 Feb 2018 17:28:09 +0100 Subject: [PATCH 12/17] clean(feature): remove unused code --- frontend/src/component/feature/form-edit-container.jsx | 4 +--- frontend/src/component/feature/form/index.jsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index f75961dad4..eb0821f723 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -34,9 +34,7 @@ const prepare = (methods, dispatch) => { delete s.id; }); } - if (input.editmode) { - delete input.description; - } + delete input.description; // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index 43d6575874..4f0ec44809 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -42,7 +42,7 @@ class AddFeatureToggleComponent extends Component { enabled, } = input; const configuredStrategies = input.strategies || []; - input.editmode = editmode; + return (
From f8fb2bbc769e37f004f81644059de3a65cb5e436 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Fri, 16 Feb 2018 09:19:30 +0100 Subject: [PATCH 13/17] refactor(form): separate add-feature and update-feature components --- .../application/application-edit-container.js | 2 +- .../application/application-list-container.js | 2 +- .../archive/archive-list-container.js | 2 +- frontend/src/component/common/index.js | 3 + .../component/feature/form-add-component.jsx | 19 ----- ...dex.jsx => form-add-feature-component.jsx} | 83 +++++++++---------- .../form-add-feature-container.jsx} | 8 +- .../form/form-update-feature-component.jsx | 57 +++++++++++++ .../form-update-feature-container.jsx} | 8 +- .../src/component/feature/view-component.jsx | 2 +- .../src/component/feature/view-container.jsx | 2 +- .../component/history/history-container.js | 2 +- .../src/component/strategies/add-container.js | 4 +- .../component/strategies/list-container.jsx | 2 +- .../strategies/strategy-details-container.js | 6 +- frontend/src/page/features/create.js | 2 +- frontend/src/page/features/index.js | 2 +- frontend/src/page/features/show.js | 2 +- 18 files changed, 121 insertions(+), 87 deletions(-) delete mode 100644 frontend/src/component/feature/form-add-component.jsx rename frontend/src/component/feature/form/{index.jsx => form-add-feature-component.jsx} (50%) rename frontend/src/component/feature/{form-add-container.jsx => form/form-add-feature-container.jsx} (85%) create mode 100644 frontend/src/component/feature/form/form-update-feature-component.jsx rename frontend/src/component/feature/{form-edit-container.jsx => form/form-update-feature-container.jsx} (86%) 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-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..f704a9c8de 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/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/index.jsx b/frontend/src/component/feature/form/form-add-feature-component.jsx similarity index 50% rename from frontend/src/component/feature/form/index.jsx rename to frontend/src/component/feature/form/form-add-feature-component.jsx index 4f0ec44809..439149dcda 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, getDisplayName } 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 = `Add2FeatureToggleComponent${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 { @@ -46,44 +46,38 @@ class AddFeatureToggleComponent extends Component { return (
- {!editmode && ( - validateName(v.target.value)} - onChange={v => setValue('name', trim(v.target.value))} - /> - )} - {!editmode && ( - setValue('description', v.target.value)} - /> - )} - {!editmode && ( -
-
- { - setValue('enabled', !enabled); - }} - > - Enabled - -
-
- )} + validateName(v.target.value)} + onChange={v => setValue('name', trim(v.target.value))} + /> + setValue('description', v.target.value)} + /> +
+
+ { + setValue('enabled', !enabled); + }} + > + Enabled + +
+
+
- +
); } } -AddFeatureToggleComponent.propTypes = { +AddFeatureComponent.propTypes = { input: PropTypes.object, setValue: PropTypes.func.isRequired, addStrategy: PropTypes.func.isRequired, @@ -110,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 85% rename from frontend/src/component/feature/form-add-container.jsx rename to frontend/src/component/feature/form/form-add-feature-container.jsx index 9699f49c36..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({ @@ -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..daca108c17 --- /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, getDisplayName } from './../../common'; + +class UpdateFeatureComponent extends Component { + static displayName = `AddFeatureToggleComponent${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 86% rename from frontend/src/component/feature/form-edit-container.jsx rename to frontend/src/component/feature/form/form-update-feature-container.jsx index eb0821f723..185df3f99a 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) { @@ -76,4 +76,4 @@ const actions = createActions({ prepare, }); -export default connect(mapStateToProps, actions)(FormComponent); +export default connect(mapStateToProps, actions)(UpdateFeatureToggleComponent); diff --git a/frontend/src/component/feature/view-component.jsx b/frontend/src/component/feature/view-component.jsx index b186460892..4f2546fe33 100644 --- a/frontend/src/component/feature/view-component.jsx +++ b/frontend/src/component/feature/view-component.jsx @@ -5,7 +5,7 @@ import { hashHistory, Link } from 'react-router'; import HistoryComponent from '../history/history-list-toggle-container'; import MetricComponent from './metric-container'; -import EditFeatureToggle from './form-edit-container.jsx'; +import EditFeatureToggle from './form/form-update-feature-container'; import { styles as commonStyles } from '../common'; const TABS = { diff --git a/frontend/src/component/feature/view-container.jsx b/frontend/src/component/feature/view-container.jsx index 6827012bfd..f8a33ae007 100644 --- a/frontend/src/component/feature/view-container.jsx +++ b/frontend/src/component/feature/view-container.jsx @@ -5,7 +5,7 @@ import { toggleFeature, removeFeatureToggle, editFeatureToggle, -} from '../../store/feature-actions'; +} from './../../store/feature-actions'; import ViewToggleComponent from './view-component'; 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-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 = { From bfee62ed820d8d7c356be6715880972ea3616424 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Fri, 16 Feb 2018 20:45:05 +0100 Subject: [PATCH 14/17] test(form): add enzyme tests --- frontend/package.json | 4 + .../archive/archive-list-component.jsx | 1 + .../src/component/feature/__tests__/.eslintrc | 5 + .../feature-list-item-component-test.jsx.snap | 55 +++++++++ .../__snapshots__/progress-test.jsx.snap | 107 ++++++++++++++++++ .../feature-list-item-component-test.jsx | 37 ++++++ .../feature/__tests__/progress-test.jsx | 34 ++++++ .../feature/form/__tests__/.eslintrc | 5 + .../strategy-input-list-test.jsx.snap | 103 +++++++++++++++++ .../__tests__/strategy-input-list-test.jsx | 68 +++++++++++ .../form/form-add-feature-component.jsx | 4 +- .../form/form-update-feature-component.jsx | 4 +- .../form/strategies-section-container.jsx | 7 +- .../feature/form/strategies-section.jsx | 4 +- .../feature/form/strategy-input-list.jsx | 21 ++-- frontend/src/setupTests.js | 4 + 16 files changed, 443 insertions(+), 20 deletions(-) create mode 100644 frontend/src/component/feature/__tests__/.eslintrc create mode 100644 frontend/src/component/feature/__tests__/__snapshots__/feature-list-item-component-test.jsx.snap create mode 100644 frontend/src/component/feature/__tests__/__snapshots__/progress-test.jsx.snap create mode 100644 frontend/src/component/feature/__tests__/feature-list-item-component-test.jsx create mode 100644 frontend/src/component/feature/__tests__/progress-test.jsx create mode 100644 frontend/src/component/feature/form/__tests__/.eslintrc create mode 100644 frontend/src/component/feature/form/__tests__/__snapshots__/strategy-input-list-test.jsx.snap create mode 100644 frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx create mode 100644 frontend/src/setupTests.js 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; }} /> Date: Fri, 16 Feb 2018 21:18:20 +0100 Subject: [PATCH 15/17] lint(error): make lint happy --- frontend/src/component/archive/archive-list-component.jsx | 2 +- frontend/src/component/common/index.js | 2 +- frontend/src/component/feature/__tests__/progress-test.jsx | 4 ++-- .../src/component/feature/form/form-add-feature-component.jsx | 2 +- .../component/feature/form/form-update-feature-component.jsx | 2 +- frontend/src/component/feature/form/strategy-input-list.jsx | 4 +++- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx index 77e32f1065..1757dcd75a 100644 --- a/frontend/src/component/archive/archive-list-component.jsx +++ b/frontend/src/component/archive/archive-list-component.jsx @@ -27,7 +27,7 @@ class ArchiveList extends Component { ))} ); - debugger; + return strategiesList; } renderStrategiesInList(feature) { diff --git a/frontend/src/component/common/index.js b/frontend/src/component/common/index.js index f704a9c8de..73145d6bc9 100644 --- a/frontend/src/component/common/index.js +++ b/frontend/src/component/common/index.js @@ -182,4 +182,4 @@ export function calc(value, total, decimal) { } export function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; -}; +} diff --git a/frontend/src/component/feature/__tests__/progress-test.jsx b/frontend/src/component/feature/__tests__/progress-test.jsx index 8326fe9c16..b7bf7b1324 100644 --- a/frontend/src/component/feature/__tests__/progress-test.jsx +++ b/frontend/src/component/feature/__tests__/progress-test.jsx @@ -21,14 +21,14 @@ test('renders correctly with 0% done no fallback', () => { test('renders correctly with 15% done with fallback', () => { const percent = 15; - const tree = renderer.create(); + const tree = renderer.create(); expect(tree).toMatchSnapshot(); }); test('renders correctly with 0% done with fallback', () => { const percent = 0; - const tree = renderer.create(); + const tree = renderer.create(); expect(tree).toMatchSnapshot(); }); 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 addc3d9faa..03b8bc99e9 100644 --- a/frontend/src/component/feature/form/form-add-feature-component.jsx +++ b/frontend/src/component/feature/form/form-add-feature-component.jsx @@ -14,7 +14,7 @@ const trim = value => { }; class AddFeatureComponent extends Component { - //static displayName = `AddFeatureComponent-${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 e47fa59aa7..b624f340ef 100644 --- a/frontend/src/component/feature/form/form-update-feature-component.jsx +++ b/frontend/src/component/feature/form/form-update-feature-component.jsx @@ -5,7 +5,7 @@ import StrategiesSection from './strategies-section-container'; import { FormButtons } from './../../common'; class UpdateFeatureComponent extends Component { - //static displayName = `UpdateFeatureComponent-{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/strategy-input-list.jsx b/frontend/src/component/feature/form/strategy-input-list.jsx index f70a4e1e88..102b61eb6e 100644 --- a/frontend/src/component/feature/form/strategy-input-list.jsx +++ b/frontend/src/component/feature/form/strategy-input-list.jsx @@ -67,7 +67,9 @@ export default class InputList extends Component { label="Add list entry" onFocus={this.onFocus.bind(this)} onBlur={this.onBlur.bind(this)} - ref={(input) => { this.textInput = input; }} + ref={input => { + this.textInput = input; + }} /> Date: Sat, 17 Feb 2018 16:57:03 +0100 Subject: [PATCH 16/17] test(feature): test add, update feature form --- frontend/package.json | 1 - frontend/src/__mocks__/react-mdl.js | 2 + .../form-add-feature-component-test.jsx.snap | 555 ++++++++++++++++++ ...orm-update-feature-component-test.jsx.snap | 245 ++++++++ .../__snapshots__/strategy-add-test.jsx.snap | 296 ++++++++++ .../form-add-feature-component-test.jsx | 124 ++++ .../form-update-feature-component-test.jsx | 31 + .../form/__tests__/strategy-add-test.jsx | 46 ++ .../__tests__/strategy-input-list-test.jsx | 13 + .../component/feature/form/strategies-add.jsx | 4 +- 10 files changed, 1314 insertions(+), 3 deletions(-) create mode 100644 frontend/src/component/feature/form/__tests__/__snapshots__/form-add-feature-component-test.jsx.snap create mode 100644 frontend/src/component/feature/form/__tests__/__snapshots__/form-update-feature-component-test.jsx.snap create mode 100644 frontend/src/component/feature/form/__tests__/__snapshots__/strategy-add-test.jsx.snap create mode 100644 frontend/src/component/feature/form/__tests__/form-add-feature-component-test.jsx create mode 100644 frontend/src/component/feature/form/__tests__/form-update-feature-component-test.jsx create mode 100644 frontend/src/component/feature/form/__tests__/strategy-add-test.jsx diff --git a/frontend/package.json b/frontend/package.json index 37e3553da3..fbcfe0607b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -35,7 +35,6 @@ "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", 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/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__/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 index 31e1032daa..ad49344c7c 100644 --- a/frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx +++ b/frontend/src/component/feature/form/__tests__/strategy-input-list-test.jsx @@ -66,3 +66,16 @@ it('spy onBlur', () => { 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/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(); From 78f6bf02e08f9cdde08342d6dd7aff2d8617bb19 Mon Sep 17 00:00:00 2001 From: Corinne Krych Date: Sat, 17 Feb 2018 17:23:56 +0100 Subject: [PATCH 17/17] fix(feature): redirect to list of features once feature is updated --- .../component/feature/form/form-update-feature-container.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/component/feature/form/form-update-feature-container.jsx b/frontend/src/component/feature/form/form-update-feature-container.jsx index 185df3f99a..58c755487e 100644 --- a/frontend/src/component/feature/form/form-update-feature-container.jsx +++ b/frontend/src/component/feature/form/form-update-feature-container.jsx @@ -39,8 +39,7 @@ const prepare = (methods, dispatch) => { // TODO: should add error handling requestUpdateFeatureToggle(input)(dispatch) .then(() => methods.clear()) - .then(() => hashHistory.push(`/features`)) - .then(() => hashHistory.push(`/features/strategies/${input.name}`)); + .then(() => hashHistory.push(`/features`)); }; methods.onCancel = evt => {