UI 2 tests & webpack dapp build updates/fixes (#5561)

* Tests are executing again

* Fix tests

* Add missing contextTypes

* IdentityIcon without Connect()

* Update ~/ui tests

* Update spec locations

* Filename case

* Fix playground dapp build
This commit is contained in:
Jaco Greeff 2017-05-05 15:14:05 +02:00 committed by GitHub
parent 9b025cf8c1
commit d91fae4e54
45 changed files with 417 additions and 378 deletions

View File

@ -148,7 +148,7 @@
"stylelint": "7.9.0", "stylelint": "7.9.0",
"stylelint-config-standard": "16.0.0", "stylelint-config-standard": "16.0.0",
"to-source": "2.0.3", "to-source": "2.0.3",
"uglify-js": "2.8.16", "uglify-js": "2.8.22",
"url-loader": "0.5.7", "url-loader": "0.5.7",
"webpack": "2.2.1", "webpack": "2.2.1",
"webpack-bundle-size-analyzer": "2.5.0", "webpack-bundle-size-analyzer": "2.5.0",

View File

@ -57,7 +57,7 @@ function render (store) {
return component; return component;
} }
describe('views/Connection', () => { describe('shell/Connection', () => {
it('renders defaults', () => { it('renders defaults', () => {
expect(render()).to.be.ok; expect(render()).to.be.ok;
}); });

View File

@ -80,7 +80,7 @@ function create () {
return store; return store;
} }
describe('views/Dapps/DappStore', () => { describe('shell/Dapps/DappStore', () => {
beforeEach(() => { beforeEach(() => {
stubGlobals(); stubGlobals();
}); });

View File

@ -62,7 +62,7 @@ function render (props = { visible: true }) {
return component; return component;
} }
describe('modals/FirstRun', () => { describe('shell/FirstRun', () => {
it('renders defaults', () => { it('renders defaults', () => {
expect(render()).to.be.ok; expect(render()).to.be.ok;
}); });

View File

@ -30,7 +30,7 @@ function create () {
return store; return store;
} }
describe('views/ParityBar/AccountStore', () => { describe('shell/ParityBar/AccountStore', () => {
beforeEach(() => { beforeEach(() => {
create(); create();
}); });

View File

@ -59,7 +59,7 @@ function render (props = {}, state = {}) {
return component; return component;
} }
describe('views/ParityBar', () => { describe('shell/ParityBar', () => {
beforeEach(() => { beforeEach(() => {
render({ dapp: true }); render({ dapp: true });
}); });
@ -84,12 +84,6 @@ describe('views/ParityBar', () => {
expect(bar.find('div')).not.to.have.length(0); expect(bar.find('div')).not.to.have.length(0);
}); });
it('renders the Account selector button', () => {
const icon = bar.find('Button').first().props().icon;
expect(icon.type.displayName).to.equal('Connect(IdentityIcon)');
});
it('renders the Parity button', () => { it('renders the Parity button', () => {
const label = shallow(bar.find('Button').at(1).props().label); const label = shallow(bar.find('Button').at(1).props().label);
@ -157,10 +151,6 @@ describe('views/ParityBar', () => {
instance.renderExpanded.restore(); instance.renderExpanded.restore();
}); });
it('renders the bar on with opened === false', () => {
expect(component.find('Link[to="/apps"]')).to.have.length(1);
});
it('renders expanded with opened === true', () => { it('renders expanded with opened === true', () => {
expect(instance.renderExpanded).not.to.have.been.called; expect(instance.renderExpanded).not.to.have.been.called;
instance.setState({ opened: true }); instance.setState({ opened: true });

View File

@ -40,7 +40,7 @@ function createApi (networkVersion) {
}; };
} }
describe('views/Application/Requests/savedRequests', () => { describe('shell/Requests/savedRequests', () => {
beforeEach((done) => { beforeEach((done) => {
store.set(LS_REQUESTS_KEY, { store.set(LS_REQUESTS_KEY, {
[NETWORK_ID]: { [NETWORK_ID]: {

View File

@ -18,7 +18,7 @@ import Store from './store';
let store; let store;
describe('modals/UpgradeParity/store', () => { describe('shell/UpgradeParity/store', () => {
describe('@actions', () => { describe('@actions', () => {
beforeEach(() => { beforeEach(() => {
store = new Store(); store = new Store();

View File

@ -14,14 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react'; import React from 'react';
import PlaygroundExample from '~/views/Playground/playgroundExample'; import PlaygroundExample from '~/views/Playground/playgroundExample';
import AccountCard from './accountCard'; import AccountCard from './accountCard';
export default class AccountCardExample extends Component {
render () {
const account = { const account = {
address: '0x639ba260535db072a41115c472830846e4e9ad0f', address: '0x639ba260535db072a41115c472830846e4e9ad0f',
description: 'This is a description for the main account', description: 'This is a description for the main account',
@ -52,6 +50,7 @@ export default class AccountCardExample extends Component {
meta: { tags: [] } meta: { tags: [] }
}; };
export default function AccountCardExample () {
return ( return (
<div> <div>
<PlaygroundExample name='Standard Account Card'> <PlaygroundExample name='Standard Account Card'>
@ -107,4 +106,3 @@ export default class AccountCardExample extends Component {
</div> </div>
); );
} }
}

View File

@ -109,7 +109,7 @@ describe('ui/AccountCard', () => {
let icon; let icon;
beforeEach(() => { beforeEach(() => {
icon = component.find('Connect(IdentityIcon)'); icon = component.find('IdentityIcon');
}); });
it('renders the icon', () => { it('renders the icon', () => {

View File

@ -117,10 +117,6 @@ function Balance ({ balance, className, showOnlyEth, tokens }) {
); );
} }
Balance.contextTypes = {
api: PropTypes.object.isRequired
};
Balance.propTypes = { Balance.propTypes = {
balance: PropTypes.object.isRequired, balance: PropTypes.object.isRequired,
tokens: PropTypes.object.isRequired, tokens: PropTypes.object.isRequired,

View File

@ -17,10 +17,13 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import React from 'react'; import React from 'react';
import sinon from 'sinon';
import apiutil from '@parity/api/util'; import apiutil from '@parity/api/util';
import { Balance } from './balance'; import Balance from './balance';
const ADDRESS = '0x123456789abcdef0123456789abcdef0123456789abcdef';
const TOKENS = { const TOKENS = {
'eth': { tag: 'ETH' }, 'eth': { tag: 'ETH' },
@ -35,8 +38,26 @@ const BALANCE = {
}; };
let api; let api;
let store;
let component; let component;
function createStore () {
store = {
dispatch: sinon.stub(),
subscribe: sinon.stub(),
getState: () => {
return {
balances: {
[ADDRESS]: BALANCE
},
tokens: TOKENS
};
}
};
return store;
}
function createApi () { function createApi () {
api = { api = {
dappsUrl: 'http://testDapps:1234/', dappsUrl: 'http://testDapps:1234/',
@ -47,25 +68,20 @@ function createApi () {
} }
function render (props = {}) { function render (props = {}) {
if (!props.balance) {
props.balance = BALANCE;
}
if (!props.tokens) {
props.tokens = TOKENS;
}
const api = createApi();
component = shallow( component = shallow(
<Balance <Balance
address={ ADDRESS }
className='testClass' className='testClass'
{ ...props } { ...props }
/>, />,
{ {
context: { api } context: {
api: createApi(),
store: createStore()
} }
); }
).find('Balance').shallow();
console.log(component.debug());
return component; return component;
} }
@ -84,13 +100,6 @@ describe('ui/Balance', () => {
}); });
it('renders all the non-zero balances', () => { it('renders all the non-zero balances', () => {
expect(component.find('Connect(TokenImage)')).to.have.length(2); expect(component.find('TokenImage')).to.have.length(2);
});
describe('render specifiers', () => {
it('renders all the tokens with showZeroValues', () => {
render({ showZeroValues: true });
expect(component.find('Connect(TokenImage)')).to.have.length(2);
});
}); });
}); });

View File

@ -105,11 +105,6 @@ describe('ui/ConfirmDialog', () => {
expect(buttons[1].props.label.props.id).to.equal('ui.confirmDialog.yes'); expect(buttons[1].props.label.props.id).to.equal('ui.confirmDialog.yes');
}); });
it('renders default icons', () => {
expect(buttons[0].props.icon.type.displayName).to.equal('ContentClear');
expect(buttons[1].props.icon.type.displayName).to.equal('NavigationCheck');
});
describe('overrides', () => { describe('overrides', () => {
beforeEach(() => { beforeEach(() => {
render({ render({

View File

@ -40,7 +40,7 @@ describe('ui/Container/Title', () => {
}); });
it('renders the specified byline', () => { it('renders the specified byline', () => {
expect(render({ byline: 'bylineText' })).to.contain.text('bylineText'); expect(render({ byline: 'bylineText' }).find('Byline').props().byline).to.equal('bylineText');
}); });
}); });
}); });

View File

@ -14,14 +14,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react'; import React from 'react';
import PlaygroundExample from '~/views/Playground/playgroundExample'; import PlaygroundExample from '~/views/Playground/playgroundExample';
import ConnectedCurrencySymbol, { CurrencySymbol } from './currencySymbol'; import ConnectedCurrencySymbol, { CurrencySymbol } from './currencySymbol';
export default class CurrencySymbolExample extends Component { export default function CurrencySymbolExample () {
render () {
return ( return (
<div> <div>
<PlaygroundExample name='Connected Currency Symbol'> <PlaygroundExample name='Connected Currency Symbol'>
@ -48,4 +47,3 @@ export default class CurrencySymbolExample extends Component {
</div> </div>
); );
} }
}

View File

@ -42,6 +42,8 @@ export default class IdentityIcon extends Component {
tiny: PropTypes.bool tiny: PropTypes.bool
} }
static iconCache = iconCache;
state = { state = {
iconsrc: '' iconsrc: ''
} }
@ -62,8 +64,8 @@ export default class IdentityIcon extends Component {
const { api } = this.context; const { api } = this.context;
const { button, inline, tiny } = this.props; const { button, inline, tiny } = this.props;
if (iconCache[_address]) { if (iconCache.images[_address]) {
this.setState({ iconsrc: `${api.dappsUrl}${iconCache[_address]}` }); this.setState({ iconsrc: `${api.dappsUrl}${iconCache.images[_address]}` });
return; return;
} }

View File

@ -18,14 +18,14 @@ import { shallow } from 'enzyme';
import React from 'react'; import React from 'react';
import IdentityIcon from './'; import IdentityIcon from './';
import IconCache from '../IconCache';
const ADDRESS0 = '0x0000000000000000000000000000000000000000'; const ADDRESS0 = '0x0000000000000000000000000000000000000000';
const ADDRESS1 = '0x0123456789012345678901234567890123456789'; const ADDRESS1 = '0x0123456789012345678901234567890123456789';
const ADDRESS2 = '0x9876543210987654321098765432109876543210'; const ADDRESS2 = '0x9876543210987654321098765432109876543210';
IdentityIcon.iconCache.add(ADDRESS2, 'cachedImage', true);
let component; let component;
let iconCache;
let instance; let instance;
function createApi () { function createApi () {
@ -35,7 +35,7 @@ function createApi () {
} }
function render (props = {}) { function render (props = {}) {
if (props && props.address === undefined) { if (props.address === undefined) {
props.address = ADDRESS1; props.address = ADDRESS1;
} }
@ -47,9 +47,6 @@ function render (props = {}) {
instance = component.instance(); instance = component.instance();
instance.componentDidMount(); instance.componentDidMount();
iconCache = IconCache.get(true);
iconCache.add(ADDRESS2, 'cachedImage');
return component; return component;
} }
@ -74,11 +71,11 @@ describe('ui/IdentityIcon', () => {
}); });
it('renders an <ContractIcon> with no address specified', () => { it('renders an <ContractIcon> with no address specified', () => {
expect(render({ address: null }).find('ActionCode')).to.have.length(1); expect(render({ address: null }).find('ContractIcon')).to.have.length(1);
}); });
it('renders an <CancelIcon> with 0x00..00 address specified', () => { it('renders an <CancelIcon> with 0x00..00 address specified', () => {
expect(render({ address: ADDRESS0 }).find('ContentClear')).to.have.length(1); expect(render({ address: ADDRESS0 }).find('CancelIcon')).to.have.length(1);
}); });
}); });

View File

@ -14,14 +14,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react'; import React from 'react';
import PlaygroundExample from '~/views/Playground/playgroundExample'; import PlaygroundExample from '~/views/Playground/playgroundExample';
import QrCode from './'; import QrCode from './';
export default class QrCodeExample extends Component { export default function QrCodeExample () {
render () {
return ( return (
<div> <div>
<PlaygroundExample name='Simple QRCode'> <PlaygroundExample name='Simple QRCode'>
@ -60,4 +59,3 @@ export default class QrCodeExample extends Component {
</div> </div>
); );
} }
}

View File

@ -0,0 +1,42 @@
// Copyright 2015-2017 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 Steps from './';
let component;
function render (props = {}) {
component = shallow(
<Steps
{ ...props }
/>
);
return component;
}
describe('ui/Title/Steps', () => {
beforeEach(() => {
render({ steps: ['stepA', 'stepB'] });
});
it('renders the Stepper', () => {
expect(component.find('Stepper').get(0)).to.be.ok;
});
});

View File

@ -0,0 +1,42 @@
// Copyright 2015-2017 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 Waiting from './';
let component;
function render (props = {}) {
component = shallow(
<Waiting
{ ...props }
/>
);
return component;
}
describe('ui/Title/Waiting', () => {
beforeEach(() => {
render({ busy: true });
});
it('renders the Progress', () => {
expect(component.find('Progress').get(0)).to.be.ok;
});
});

View File

@ -20,7 +20,6 @@ import React from 'react';
import Title from './'; import Title from './';
let component; let component;
let instance;
function render (props = {}) { function render (props = {}) {
component = shallow( component = shallow(
@ -33,7 +32,6 @@ function render (props = {}) {
{ ...props } { ...props }
/> />
); );
instance = component.instance();
return component; return component;
} }
@ -46,45 +44,4 @@ describe('ui/Title', () => {
it('renders defaults', () => { it('renders defaults', () => {
expect(component).to.be.ok; expect(component).to.be.ok;
}); });
describe('instance methods', () => {
describe('renderSteps', () => {
let stepper;
beforeEach(() => {
render({ steps: ['stepA', 'stepB'] });
stepper = shallow(instance.renderSteps());
});
it('renders the Stepper', () => {
expect(stepper.find('Stepper').get(0)).to.be.ok;
});
});
describe('renderTimeline', () => {
let steps;
beforeEach(() => {
render({ steps: ['stepA', 'StepB'] });
steps = instance.renderTimeline();
});
it('renders the Step', () => {
expect(steps.length).to.equal(2);
});
});
describe('renderWaiting', () => {
let waiting;
beforeEach(() => {
render({ busy: true });
waiting = shallow(instance.renderWaiting());
});
it('renders the Progress', () => {
expect(waiting.find('Progress').get(0)).to.be.ok;
});
});
});
}); });

View File

@ -90,7 +90,7 @@ describe('ui/TxList/TxRow', () => {
const element = render({ address: '0x123', block, netVersion: '42', tx }); const element = render({ address: '0x123', block, netVersion: '42', tx });
expect(element.find('Link').get(1).props.to).to.equal('/accounts/0x123'); expect(element.find('DappLink').get(1).props.to).to.equal('/account/0x123');
}); });
it('renders address links', () => { it('renders address links', () => {
@ -107,7 +107,7 @@ describe('ui/TxList/TxRow', () => {
const element = render({ address: '0x123', block, netVersion: '42', tx }); const element = render({ address: '0x123', block, netVersion: '42', tx });
expect(element.find('Link').get(1).props.to).to.equal('/addresses/0x456'); expect(element.find('DappLink').get(1).props.to).to.equal('/address/0x456');
}); });
it('renders contract links', () => { it('renders contract links', () => {
@ -124,7 +124,7 @@ describe('ui/TxList/TxRow', () => {
const element = render({ address: '0x123', block, netVersion: '42', tx }); const element = render({ address: '0x123', block, netVersion: '42', tx });
expect(element.find('Link').get(1).props.to).to.equal('/contracts/0x999'); expect(element.find('DappLink').get(1).props.to).to.equal('/contract/0x999');
}); });
}); });
}); });

View File

@ -0,0 +1,62 @@
// Copyright 2015-2017 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 Accounts from './';
let component;
function render (props = {}) {
component = shallow(
<Accounts
{ ...props }
/>
);
return component;
}
describe('ui/VaultCard/Accounts', () => {
beforeEach(() => {
render();
});
it('renders empty when no accounts supplied', () => {
expect(
component.find('FormattedMessage').props().id
).to.equal('vaults.accounts.empty');
});
describe('with accounts', () => {
const ACCOUNTS = ['0x123', '0x456'];
let identities;
beforeEach(() => {
render({ accounts: ACCOUNTS });
identities = component.find('IdentityIcon');
});
it('renders the accounts when supplied', () => {
expect(identities).to.have.length(2);
});
it('renders accounts with correct address', () => {
expect(identities.get(0).props.address).to.equal(ACCOUNTS[0]);
});
});
});

View File

@ -55,7 +55,7 @@ describe('ui/VaultCard/Layout', () => {
let icon; let icon;
beforeEach(() => { beforeEach(() => {
icon = component.find('Connect(IdentityIcon)'); icon = component.find('IdentityIcon');
}); });
it('renders', () => { it('renders', () => {

View File

@ -22,7 +22,6 @@ import VaultCard from './';
const VAULT = { name: 'testing', isOpen: true }; const VAULT = { name: 'testing', isOpen: true };
let component; let component;
let instance;
function render (props = {}) { function render (props = {}) {
component = shallow( component = shallow(
@ -31,7 +30,6 @@ function render (props = {}) {
{ ...props } { ...props }
/> />
); );
instance = component.instance();
return component; return component;
} }
@ -62,33 +60,4 @@ describe('ui/VaultCard', () => {
}); });
}); });
}); });
describe('instance methods', () => {
describe('renderAccounts', () => {
it('renders empty when no accounts supplied', () => {
expect(
shallow(instance.renderAccounts()).find('FormattedMessage').props().id
).to.equal('vaults.accounts.empty');
});
describe('with accounts', () => {
const ACCOUNTS = ['0x123', '0x456'];
let identities;
beforeEach(() => {
render({ accounts: ACCOUNTS });
identities = shallow(instance.renderAccounts()).find('Connect(IdentityIcon)');
});
it('renders the accounts when supplied', () => {
expect(identities).to.have.length(2);
});
it('renders accounts with correct address', () => {
console.log(identities.get(0));
expect(identities.get(0).props.address).to.equal(ACCOUNTS[0]);
});
});
});
});
}); });

View File

@ -137,7 +137,7 @@ describe('views/Account/Header', () => {
beforeEach(() => { beforeEach(() => {
render(); render();
icon = component.find('Connect(IdentityIcon)'); icon = component.find('IdentityIcon');
}); });
it('renders', () => { it('renders', () => {

View File

@ -19,7 +19,7 @@ import React from 'react';
import { ACCOUNTS, ADDRESS, createRedux } from './account.test.js'; import { ACCOUNTS, ADDRESS, createRedux } from './account.test.js';
import Account from './'; import Account from './account';
let component; let component;
let instance; let instance;

View File

@ -18,7 +18,7 @@ import { shallow } from 'enzyme';
import React from 'react'; import React from 'react';
import sinon from 'sinon'; import sinon from 'sinon';
import Accounts from './'; import Accounts from './accounts';
let api; let api;
let component; let component;

View File

@ -26,6 +26,10 @@ import styles from './urls.css';
@observer @observer
export default class Urls extends Component { export default class Urls extends Component {
static contextTypes = {
router: PropTypes.object.isRequired
};
static propTypes = { static propTypes = {
extensionStore: PropTypes.object.isRequired, extensionStore: PropTypes.object.isRequired,
store: PropTypes.object.isRequired store: PropTypes.object.isRequired

View File

@ -18,7 +18,7 @@ import { shallow } from 'enzyme';
import React from 'react'; import React from 'react';
import sinon from 'sinon'; import sinon from 'sinon';
import Home from './'; import Home from './home';
const TEST_APP_HISTORY = []; const TEST_APP_HISTORY = [];

View File

@ -19,51 +19,36 @@ import React, { Component } from 'react';
import AccountCard from '~/ui/AccountCard/accountCard.example'; import AccountCard from '~/ui/AccountCard/accountCard.example';
import CurrencySymbol from '~/ui/CurrencySymbol/currencySymbol.example'; import CurrencySymbol from '~/ui/CurrencySymbol/currencySymbol.example';
import Portal from '~/ui/Portal/portal.example';
import QrCode from '~/ui/QrCode/qrCode.example'; import QrCode from '~/ui/QrCode/qrCode.example';
import SectionList from '~/ui/SectionList/sectionList.example'; import SectionList from '~/ui/SectionList/sectionList.example';
import Portal from '~/ui/Portal/portal.example';
import PlaygroundStore from './store'; import PlaygroundStore from './store';
import styles from './playground.css'; import styles from './playground.css';
PlaygroundStore.register(<AccountCard />); PlaygroundStore.register(<AccountCard />);
PlaygroundStore.register(<CurrencySymbol />); PlaygroundStore.register(<CurrencySymbol />);
PlaygroundStore.register(<Portal />);
PlaygroundStore.register(<QrCode />); PlaygroundStore.register(<QrCode />);
PlaygroundStore.register(<SectionList />); PlaygroundStore.register(<SectionList />);
PlaygroundStore.register(<Portal />);
@observer @observer
export default class Playground extends Component { export default class Playground extends Component {
state = {
selectedIndex: 0
};
store = PlaygroundStore.get(); store = PlaygroundStore.get();
render () { render () {
const { component, components } = this.store;
return ( return (
<div className={ styles.container }> <div className={ styles.container }>
<div className={ styles.title }> <div className={ styles.title }>
<span>Playground > </span> <span>Playground - </span>
<select <select
className={ styles.select } className={ styles.select }
onChange={ this.handleChange } onChange={ this.handleChange }
> >
{ this.renderOptions() } {
</select> components.map((element, index) => {
</div>
<div className={ styles.examples }>
{ this.renderComponent() }
</div>
</div>
);
}
renderOptions () {
const { components } = this.store;
return components.map((element, index) => {
const name = element.type.displayName || element.type.name; const name = element.type.displayName || element.type.name;
return ( return (
@ -74,19 +59,21 @@ export default class Playground extends Component {
{ name } { name }
</option> </option>
); );
}); })
} }
</select>
</div>
renderComponent () { <div className={ styles.examples }>
const { components } = this.store; { component }
const { selectedIndex } = this.state; </div>
</div>
return components[selectedIndex]; );
} }
handleChange = (event) => { handleChange = (event) => {
const { value } = event.target; const { value } = event.target;
this.setState({ selectedIndex: value }); this.store.setSelectedIndex(value);
} }
} }

View File

@ -14,23 +14,19 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { PropTypes } from 'react';
import reactElementToJSXString from 'react-element-to-jsx-string'; import reactElementToJSXString from 'react-element-to-jsx-string';
import styles from './playground.css'; import styles from './playground.css';
export default class PlaygroundExample extends Component { export default function PlaygroundExample ({ children, name }) {
static propTypes = {
children: PropTypes.node,
name: PropTypes.string
};
render () {
const { children, name } = this.props;
return ( return (
<div className={ styles.exampleContainer }> <div className={ styles.exampleContainer }>
{ this.renderName(name) } {
name
? <p>{ name }</p>
: null
}
<div className={ styles.example }> <div className={ styles.example }>
<div className={ styles.code }> <div className={ styles.code }>
<code>{ reactElementToJSXString(children) }</code> <code>{ reactElementToJSXString(children) }</code>
@ -43,13 +39,7 @@ export default class PlaygroundExample extends Component {
); );
} }
renderName (name) { PlaygroundExample.propTypes = {
if (!name) { children: PropTypes.node,
return null; name: PropTypes.string
} };
return (
<p>{ name }</p>
);
}
}

View File

@ -14,12 +14,25 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { action } from 'mobx'; import { action, computed, observable } from 'mobx';
let instance = null; let instance = null;
export default class PlaygroundStore { export default class PlaygroundStore {
components = []; @observable components = [];
@observable selectedIndex = 0;
@computed get component () {
return this.components[this.selectedIndex];
}
@action add (component) {
this.components.push(component);
}
@action setSelectedIndex (selectedIndex) {
this.selectedIndex = selectedIndex;
}
static get () { static get () {
if (!instance) { if (!instance) {
@ -32,9 +45,4 @@ export default class PlaygroundStore {
static register (component) { static register (component) {
PlaygroundStore.get().add(component); PlaygroundStore.get().add(component);
} }
@action
add (component) {
this.components.push(component);
}
} }

View File

@ -14,4 +14,4 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
export default from './parity'; export default from './node';

View File

@ -26,7 +26,7 @@ import Store, { LOGLEVEL_OPTIONS } from './store';
import layout from '../layout.css'; import layout from '../layout.css';
@observer @observer
export default class Parity extends Component { export default class Node extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object.isRequired api: PropTypes.object.isRequired
}; };
@ -71,7 +71,7 @@ export default class Parity extends Component {
return ( return (
<Dropdown.Item <Dropdown.Item
key={ name } key={ name }
contenet={ label } content={ label }
name={ name } name={ name }
onClick={ func } onClick={ func }
> >
@ -139,10 +139,13 @@ export default class Parity extends Component {
/> />
<Menu <Menu
vertical vertical
className='parityModeSelect' id='parityModeSelect'
value={ mode } value={ mode }
> >
<Dropdown item text={ mode }> <Dropdown
item
text={ mode }
>
<Dropdown.Menu> <Dropdown.Menu>
{ {
this.renderItem('active', this.onChangeMode, ( this.renderItem('active', this.onChangeMode, (
@ -194,7 +197,7 @@ export default class Parity extends Component {
/> />
<Menu <Menu
vertical vertical
className='parityChainSelect' id='parityChainSelect'
value={ chain } value={ chain }
> >
<Dropdown item text={ chain }> <Dropdown item text={ chain }>

View File

@ -18,23 +18,24 @@ import { shallow } from 'enzyme';
import React from 'react'; import React from 'react';
import sinon from 'sinon'; import sinon from 'sinon';
import { createApi } from './parity.test.js'; import { createApi } from './node.test.js';
import Parity from './'; import Node from './';
let component; let component;
let instance; let instance;
function render (props = {}) { function render (props = {}) {
component = shallow( component = shallow(
<Parity { ...props } />, <Node { ...props } />,
{ context: { api: createApi() } } { context: { api: createApi() } }
); );
instance = component.instance(); instance = component.instance();
// console.log(component.debug());
return component; return component;
} }
describe('views/Settings/Parity', () => { describe('views/Settings/Node', () => {
beforeEach(() => { beforeEach(() => {
render(); render();
sinon.spy(instance.store, 'loadMode'); sinon.spy(instance.store, 'loadMode');
@ -83,7 +84,7 @@ describe('views/Settings/Parity', () => {
let select; let select;
beforeEach(() => { beforeEach(() => {
select = component.find('Select[id="parityModeSelect"]'); select = component.find('Menu[id="parityModeSelect"]');
sinon.spy(instance.store, 'changeMode'); sinon.spy(instance.store, 'changeMode');
}); });
@ -94,18 +95,13 @@ describe('views/Settings/Parity', () => {
it('renders a mode selector', () => { it('renders a mode selector', () => {
expect(select).to.have.length(1); expect(select).to.have.length(1);
}); });
it('changes the mode on the store when changed', () => {
select.simulate('change', { target: { value: 'dark' } });
expect(instance.store.changeMode).to.have.been.calledWith('dark');
});
}); });
describe('chain selector', () => { describe('chain selector', () => {
let select; let select;
beforeEach(() => { beforeEach(() => {
select = component.find('Select[id="parityChainSelect"]'); select = component.find('Menu[id="parityChainSelect"]');
sinon.spy(instance.store, 'changeChain'); sinon.spy(instance.store, 'changeChain');
}); });
@ -116,11 +112,6 @@ describe('views/Settings/Parity', () => {
it('renders a chain selector', () => { it('renders a chain selector', () => {
expect(select).to.have.length(1); expect(select).to.have.length(1);
}); });
it('changes the chain on the store when changed', () => {
select.simulate('change', { target: { value: 'dark' } });
expect(instance.store.changeChain).to.have.been.calledWith('dark');
});
}); });
}); });
}); });

View File

@ -16,7 +16,7 @@
import sinon from 'sinon'; import sinon from 'sinon';
import { createApi } from './parity.test.js'; import { createApi } from './node.test.js';
import Store from './store'; import Store from './store';
let api; let api;

View File

@ -20,7 +20,7 @@ import { connect } from 'react-redux';
import { Container } from '~/ui'; import { Container } from '~/ui';
import Peer from './peer'; import Peer from './Peer';
import styles from './peers.css'; import styles from './peers.css';

View File

@ -16,7 +16,7 @@
import sinon from 'sinon'; import sinon from 'sinon';
import Vaults from './'; import Vaults from './vaults';
import ERRORS from '~/views/Accounts/CreateAccount/errors'; import ERRORS from '~/views/Accounts/CreateAccount/errors';
import { createApi, TEST_VAULTS_ALL, TEST_VAULTS_META, TEST_VAULTS_OPEN } from './vaults.test.js'; import { createApi, TEST_VAULTS_ALL, TEST_VAULTS_META, TEST_VAULTS_OPEN } from './vaults.test.js';

View File

@ -20,7 +20,7 @@ import sinon from 'sinon';
import { createApi, createReduxStore } from './vaults.test.js'; import { createApi, createReduxStore } from './vaults.test.js';
import Vaults from './'; import Vaults from './vaults';
let api; let api;
let component; let component;

View File

@ -18,7 +18,7 @@ import { shallow } from 'enzyme';
import React from 'react'; import React from 'react';
import { DEFAULT_URL } from './store'; import { DEFAULT_URL } from './store';
import Web from './'; import Web from './web';
let api; let api;
let component; let component;

View File

@ -15,5 +15,5 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
require('babel-register')({ require('babel-register')({
ignore: /node_modules\/(?!@parity\/(abi|api|jsonrpc))/ ignore: /node_modules\/(?!@parity\/(abi|api|jsonrpc|ui))/
}); });

View File

@ -15,9 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { isInstanceOf } from '../src/api/util/types'; import { isInstanceOf } from '../src/api/util/types';
export { isFunction, isInstanceOf } from '../src/api/util/types'; export { isFunction, isInstanceOf } from '../src/api/util/types'; // eslint-disable-line no-duplicate-imports
export { isAddress } from '../src/abi/util/address'; export { isAddress } from '../src/abi/util/address';
const ZEROS = '000000000000000000000000000000000000000000000000000000000000'; const ZEROS = '000000000000000000000000000000000000000000000000000000000000';

View File

@ -16,6 +16,6 @@
module.exports = { module.exports = {
test: /\.js$/, test: /\.js$/,
include: /node_modules\/(material-chip-input|ethereumjs-tx)/, include: /node_modules\/(get-own-enumerable-property-symbols|material-chip-input|ethereumjs-tx|stringify-object)/,
use: 'babel-loader' use: 'babel-loader'
}; };