Feature selector (#4074)
* WIP * ParityBar verification * import from index.js * i18n expansion & tests * Features component * Adapt language selector to use features * Add features to settings view * typo * Convert logging * Fix earlier merge issues resulting in test failures * Lint failure fixes (new rules) * Fix additional listing rules * Re-add FormattedMessage (missing after merge), fix tests * Fix loader overrides * grumble: split item rendering (& test) * grumble: allow enable/disable while testing (default on) * grumble: move LanguageSelector below Features * grumble: don't pass visiblity prop (& update tests) * grumble: missing observable (onClick misbehaving) * grumble: don't reset to defaults per session * Fix to single store instance
This commit is contained in:
21
js/src/ui/Features/constants.js
Normal file
21
js/src/ui/Features/constants.js
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const LS_STORE_KEY = '_parity::features';
|
||||
|
||||
export {
|
||||
LS_STORE_KEY
|
||||
};
|
||||
61
js/src/ui/Features/defaults.js
Normal file
61
js/src/ui/Features/defaults.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
const MODES = {
|
||||
DEVELOPMENT: 1000, // only in dev mode, disabled by default, can be toggled
|
||||
TESTING: 1011, // feature is available in dev mode
|
||||
PRODUCTION: 1022 // feature is available
|
||||
};
|
||||
|
||||
const FEATURES = {
|
||||
LANGUAGE: 'LANGUAGE',
|
||||
LOGLEVELS: 'LOGLEVELS'
|
||||
};
|
||||
|
||||
const DEFAULTS = {
|
||||
[FEATURES.LANGUAGE]: {
|
||||
mode: MODES.TESTING,
|
||||
name: 'Language Selection',
|
||||
description: 'Allows changing the default interface language'
|
||||
},
|
||||
[FEATURES.LOGLEVELS]: {
|
||||
mode: MODES.TESTING,
|
||||
name: 'Logging Level Selection',
|
||||
description: 'Allows changing of the log levels for various components'
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
Object
|
||||
.keys(MODES)
|
||||
.forEach((mode) => {
|
||||
const key = `.${mode}`;
|
||||
|
||||
FEATURES[key] = key;
|
||||
DEFAULTS[key] = {
|
||||
mode: MODES[mode],
|
||||
name: key,
|
||||
description: key
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export default DEFAULTS;
|
||||
|
||||
export {
|
||||
FEATURES,
|
||||
MODES
|
||||
};
|
||||
67
js/src/ui/Features/defaults.spec.js
Normal file
67
js/src/ui/Features/defaults.spec.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import defaults, { FEATURES, MODES } from './defaults';
|
||||
|
||||
const features = Object.values(FEATURES);
|
||||
const modes = Object.values(MODES);
|
||||
|
||||
describe('ui/Features/Defaults', () => {
|
||||
describe('feature codes', () => {
|
||||
Object.keys(FEATURES).forEach((key) => {
|
||||
describe(key, () => {
|
||||
let value;
|
||||
|
||||
beforeEach(() => {
|
||||
value = FEATURES[key];
|
||||
});
|
||||
|
||||
it('exists as an default', () => {
|
||||
expect(defaults[value]).to.be.ok;
|
||||
});
|
||||
|
||||
it('has a single unique code', () => {
|
||||
expect(features.filter((code) => code === value).length).to.equal(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('defaults', () => {
|
||||
Object.keys(defaults).forEach((key) => {
|
||||
describe(key, () => {
|
||||
let value;
|
||||
|
||||
beforeEach(() => {
|
||||
value = defaults[key];
|
||||
});
|
||||
|
||||
it('exists as an exposed feature', () => {
|
||||
expect(features.includes(key)).to.be.ok;
|
||||
});
|
||||
|
||||
it('has a valid mode', () => {
|
||||
expect(modes.includes(value.mode)).to.be.true;
|
||||
});
|
||||
|
||||
it('has a name and description', () => {
|
||||
expect(value.description).to.be.ok;
|
||||
expect(value.name).to.be.ok;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
20
js/src/ui/Features/features.css
Normal file
20
js/src/ui/Features/features.css
Normal file
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.description {
|
||||
opacity: 0.75;
|
||||
}
|
||||
69
js/src/ui/Features/features.js
Normal file
69
js/src/ui/Features/features.js
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { Checkbox } from 'material-ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import { List, ListItem } from 'material-ui/List';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import defaults, { MODES } from './defaults';
|
||||
import Store from './store';
|
||||
import styles from './features.css';
|
||||
|
||||
@observer
|
||||
export default class Features extends Component {
|
||||
store = Store.get();
|
||||
|
||||
render () {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<List>
|
||||
{
|
||||
Object
|
||||
.keys(defaults)
|
||||
.filter((key) => defaults[key].mode !== MODES.PRODUCTION)
|
||||
.map(this.renderItem)
|
||||
}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
renderItem = (key) => {
|
||||
const feature = defaults[key];
|
||||
const onCheck = () => this.store.toggleActive(key);
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
key={ `feature_${key}` }
|
||||
leftCheckbox={
|
||||
<Checkbox
|
||||
checked={ this.store.active[key] }
|
||||
onCheck={ onCheck }
|
||||
/>
|
||||
}
|
||||
primaryText={ feature.name }
|
||||
secondaryText={
|
||||
<div className={ styles.description }>
|
||||
{ feature.description }
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
89
js/src/ui/Features/features.spec.js
Normal file
89
js/src/ui/Features/features.spec.js
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import defaults, { MODES } from './defaults';
|
||||
|
||||
import Features from './';
|
||||
|
||||
let component;
|
||||
let instance;
|
||||
|
||||
function render (props = { visible: true }) {
|
||||
component = shallow(
|
||||
<Features { ...props } />
|
||||
);
|
||||
instance = component.instance();
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('views/Settings/Features', () => {
|
||||
beforeEach(() => {
|
||||
render();
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
describe('visibility', () => {
|
||||
let oldEnv;
|
||||
|
||||
beforeEach(() => {
|
||||
oldEnv = process.env.NODE_ENV;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env.NODE_ENV = oldEnv;
|
||||
});
|
||||
|
||||
it('renders null when NODE_ENV === production', () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
render();
|
||||
expect(component.get(0)).to.be.null;
|
||||
});
|
||||
|
||||
it('renders component when NODE_ENV !== production', () => {
|
||||
process.env.NODE_ENV = 'development';
|
||||
render();
|
||||
expect(component.get(0)).not.to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('instance methods', () => {
|
||||
describe('renderItem', () => {
|
||||
const keys = Object.keys(defaults).filter((key) => defaults[key].mode !== MODES.PRODUCTION);
|
||||
const key = keys[0];
|
||||
|
||||
let item;
|
||||
|
||||
beforeEach(() => {
|
||||
item = instance.renderItem(key);
|
||||
});
|
||||
|
||||
it('renders an item', () => {
|
||||
expect(item).not.to.be.null;
|
||||
});
|
||||
|
||||
it('displays the correct name', () => {
|
||||
expect(item.props.primaryText).to.equal(defaults[key].name);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
25
js/src/ui/Features/index.js
Normal file
25
js/src/ui/Features/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { FEATURES } from './defaults';
|
||||
import FeaturesStore from './store';
|
||||
|
||||
export default from './features';
|
||||
|
||||
export {
|
||||
FEATURES,
|
||||
FeaturesStore
|
||||
};
|
||||
73
js/src/ui/Features/store.js
Normal file
73
js/src/ui/Features/store.js
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { action, observable } from 'mobx';
|
||||
import store from 'store';
|
||||
|
||||
import { LS_STORE_KEY } from './constants';
|
||||
import defaults, { FEATURES, MODES } from './defaults';
|
||||
|
||||
const isProductionMode = process.env.NODE_ENV === 'production';
|
||||
|
||||
let instance = null;
|
||||
|
||||
export default class Store {
|
||||
@observable active = {};
|
||||
|
||||
constructor () {
|
||||
this.loadActiveFeatures();
|
||||
}
|
||||
|
||||
@action setActiveFeatures = (features = {}, isProduction) => {
|
||||
this.active = Object.assign({}, this.getDefaultActive(isProduction), features);
|
||||
}
|
||||
|
||||
@action toggleActive = (featureKey) => {
|
||||
this.active = Object.assign({}, this.active, { [featureKey]: !this.active[featureKey] });
|
||||
this.saveActiveFeatures();
|
||||
}
|
||||
|
||||
getDefaultActive (isProduction = isProductionMode) {
|
||||
const modesTest = [MODES.PRODUCTION];
|
||||
|
||||
if (!isProduction) {
|
||||
modesTest.push(MODES.TESTING);
|
||||
}
|
||||
|
||||
return Object
|
||||
.keys(FEATURES)
|
||||
.reduce((visibility, feature) => {
|
||||
visibility[feature] = modesTest.includes(defaults[feature].mode);
|
||||
return visibility;
|
||||
}, {});
|
||||
}
|
||||
|
||||
loadActiveFeatures () {
|
||||
this.setActiveFeatures(store.get(LS_STORE_KEY));
|
||||
}
|
||||
|
||||
saveActiveFeatures () {
|
||||
store.set(LS_STORE_KEY, this.active);
|
||||
}
|
||||
|
||||
static get () {
|
||||
if (!instance) {
|
||||
instance = new Store();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
96
js/src/ui/Features/store.spec.js
Normal file
96
js/src/ui/Features/store.spec.js
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import lstore from 'store';
|
||||
|
||||
import { LS_STORE_KEY } from './constants';
|
||||
import defaults, { MODES } from './defaults';
|
||||
|
||||
import Store from './store';
|
||||
|
||||
let store;
|
||||
|
||||
function createStore () {
|
||||
store = new Store();
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
describe('ui/Features/Store', () => {
|
||||
beforeEach(() => {
|
||||
lstore.set(LS_STORE_KEY, { 'testingFromStorage': true });
|
||||
createStore();
|
||||
});
|
||||
|
||||
it('loads with values from localStorage', () => {
|
||||
expect(store.active.testingFromStorage).to.be.true;
|
||||
});
|
||||
|
||||
describe('@action', () => {
|
||||
describe('setActiveFeatures', () => {
|
||||
it('sets the active features', () => {
|
||||
store.setActiveFeatures({ 'testing': true });
|
||||
expect(store.active.testing).to.be.true;
|
||||
});
|
||||
|
||||
it('overrides the defaults', () => {
|
||||
store.setActiveFeatures({ '.PRODUCTION': false });
|
||||
expect(store.active['.PRODUCTION']).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('toggleActive', () => {
|
||||
it('changes the state of a feature', () => {
|
||||
expect(store.active['.PRODUCTION']).to.be.true;
|
||||
store.toggleActive('.PRODUCTION');
|
||||
expect(store.active['.PRODUCTION']).to.be.false;
|
||||
});
|
||||
|
||||
it('saves the updated state to localStorage', () => {
|
||||
store.toggleActive('.PRODUCTION');
|
||||
expect(lstore.get(LS_STORE_KEY)).to.deep.equal(store.active);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('operations', () => {
|
||||
describe('getDefaultActive', () => {
|
||||
it('returns features where mode === TESTING|PRODUCTION (non-production)', () => {
|
||||
const visibility = store.getDefaultActive(false);
|
||||
|
||||
expect(
|
||||
Object
|
||||
.keys(visibility)
|
||||
.filter((key) => visibility[key])
|
||||
.filter((key) => ![MODES.TESTING, MODES.PRODUCTION].includes(defaults[key].mode))
|
||||
.length
|
||||
).to.equal(0);
|
||||
});
|
||||
|
||||
it('returns features where mode === PRODUCTION (production)', () => {
|
||||
const visibility = store.getDefaultActive(true);
|
||||
|
||||
expect(
|
||||
Object
|
||||
.keys(visibility)
|
||||
.filter((key) => visibility[key])
|
||||
.filter((key) => ![MODES.PRODUCTION].includes(defaults[key].mode))
|
||||
.length
|
||||
).to.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -14,20 +14,23 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { MenuItem } from 'material-ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { LocaleStore } from '~/i18n';
|
||||
import { FeaturesStore, FEATURES } from '../Features';
|
||||
|
||||
import Select from '../Form/Select';
|
||||
import { LocaleStore } from '../../i18n';
|
||||
|
||||
@observer
|
||||
export default class LanguageSelector extends Component {
|
||||
features = FeaturesStore.get();
|
||||
store = LocaleStore.get();
|
||||
|
||||
render () {
|
||||
if (!this.store.isDevelopment) {
|
||||
if (!this.features.active[FEATURES.LANGUAGE]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -70,6 +73,6 @@ export default class LanguageSelector extends Component {
|
||||
}
|
||||
|
||||
onChange = (event, index, locale) => {
|
||||
this.store.setLocale(locale);
|
||||
this.store.setLocale(locale || event.target.value);
|
||||
}
|
||||
}
|
||||
|
||||
69
js/src/ui/LanguageSelector/langugeSelector.spec.js
Normal file
69
js/src/ui/LanguageSelector/langugeSelector.spec.js
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import { LocaleStore } from '~/i18n';
|
||||
|
||||
import LanguageSelector from './';
|
||||
|
||||
let component;
|
||||
|
||||
function render (props = {}) {
|
||||
component = shallow(
|
||||
<LanguageSelector { ...props } />
|
||||
);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('LanguageSelector', () => {
|
||||
it('renders defaults', () => {
|
||||
expect(render()).to.be.ok;
|
||||
});
|
||||
|
||||
describe('Select', () => {
|
||||
let select;
|
||||
let localeStore;
|
||||
|
||||
beforeEach(() => {
|
||||
localeStore = LocaleStore.get();
|
||||
sinon.stub(localeStore, 'setLocale');
|
||||
|
||||
render();
|
||||
select = component.find('Select');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
localeStore.setLocale.restore();
|
||||
});
|
||||
|
||||
it('renders the Select', () => {
|
||||
expect(select).to.have.length(1);
|
||||
});
|
||||
|
||||
it('has locale items', () => {
|
||||
expect(select.find('MenuItem').length > 0).to.be.true;
|
||||
});
|
||||
|
||||
it('calls localeStore.setLocale when changed', () => {
|
||||
select.simulate('change', { target: { value: 'de' } });
|
||||
expect(localeStore.setLocale).to.have.been.calledWith('de');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -31,6 +31,7 @@ import CopyToClipboard from './CopyToClipboard';
|
||||
import CurrencySymbol from './CurrencySymbol';
|
||||
import Editor from './Editor';
|
||||
import Errors from './Errors';
|
||||
import Features, { FEATURES, FeaturesStore } from './Features';
|
||||
import Form, { AddressSelect, FormWrap, TypedInput, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select, RadioButtons } from './Form';
|
||||
import GasPriceEditor from './GasPriceEditor';
|
||||
import GasPriceSelector from './GasPriceSelector';
|
||||
@@ -74,6 +75,9 @@ export {
|
||||
CurrencySymbol,
|
||||
Editor,
|
||||
Errors,
|
||||
FEATURES,
|
||||
Features,
|
||||
FeaturesStore,
|
||||
Form,
|
||||
FormWrap,
|
||||
GasPriceEditor,
|
||||
|
||||
Reference in New Issue
Block a user