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-config-standard": "16.0.0",
"to-source": "2.0.3",
"uglify-js": "2.8.16",
"uglify-js": "2.8.22",
"url-loader": "0.5.7",
"webpack": "2.2.1",
"webpack-bundle-size-analyzer": "2.5.0",

View File

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

View File

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

View File

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

View File

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

View File

@ -59,7 +59,7 @@ function render (props = {}, state = {}) {
return component;
}
describe('views/ParityBar', () => {
describe('shell/ParityBar', () => {
beforeEach(() => {
render({ dapp: true });
});
@ -84,12 +84,6 @@ describe('views/ParityBar', () => {
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', () => {
const label = shallow(bar.find('Button').at(1).props().label);
@ -157,10 +151,6 @@ describe('views/ParityBar', () => {
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', () => {
expect(instance.renderExpanded).not.to.have.been.called;
instance.setState({ opened: true });

View File

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

View File

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

View File

@ -14,97 +14,95 @@
// 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 React from 'react';
import PlaygroundExample from '~/views/Playground/playgroundExample';
import AccountCard from './accountCard';
export default class AccountCardExample extends Component {
render () {
const account = {
address: '0x639ba260535db072a41115c472830846e4e9ad0f',
description: 'This is a description for the main account',
meta: {
tags: [ 'important', 'zargo' ]
},
name: 'Main Account'
};
const account = {
address: '0x639ba260535db072a41115c472830846e4e9ad0f',
description: 'This is a description for the main account',
meta: {
tags: [ 'important', 'zargo' ]
},
name: 'Main Account'
};
const balance = {
tokens: [
{
value: 100000000000000000000,
token: {
tag: 'ETH'
}
}
]
};
const balance = {
tokens: [
{
value: 100000000000000000000,
token: {
tag: 'ETH'
}
}
]
};
const accountManyTags = {
...account,
meta: { tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => `tag #${n}`) }
};
const accountManyTags = {
...account,
meta: { tags: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((n) => `tag #${n}`) }
};
const accountNoTags = {
...account,
meta: { tags: [] }
};
const accountNoTags = {
...account,
meta: { tags: [] }
};
return (
<div>
<PlaygroundExample name='Standard Account Card'>
export default function AccountCardExample () {
return (
<div>
<PlaygroundExample name='Standard Account Card'>
<AccountCard
account={ account }
balance={ balance }
/>
</PlaygroundExample>
<PlaygroundExample name='Small Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ account }
balance={ balance }
/>
</PlaygroundExample>
</div>
</PlaygroundExample>
<PlaygroundExample name='Small Account Card'>
<div style={ { width: 300 } }>
<PlaygroundExample name='Many Tags Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ accountManyTags }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='No Tags Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ accountNoTags }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='Two Account Card'>
<div style={ { display: 'flex' } }>
<div style={ { margin: '0 0.5em' } }>
<AccountCard
account={ account }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='Many Tags Account Card'>
<div style={ { width: 300 } }>
<div style={ { margin: '0 0.5em' } }>
<AccountCard
account={ accountManyTags }
account={ account }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='No Tags Account Card'>
<div style={ { width: 300 } }>
<AccountCard
account={ accountNoTags }
balance={ balance }
/>
</div>
</PlaygroundExample>
<PlaygroundExample name='Two Account Card'>
<div style={ { display: 'flex' } }>
<div style={ { margin: '0 0.5em' } }>
<AccountCard
account={ account }
balance={ balance }
/>
</div>
<div style={ { margin: '0 0.5em' } }>
<AccountCard
account={ account }
balance={ balance }
/>
</div>
</div>
</PlaygroundExample>
</div>
);
}
</div>
</PlaygroundExample>
</div>
);
}

View File

@ -109,7 +109,7 @@ describe('ui/AccountCard', () => {
let icon;
beforeEach(() => {
icon = component.find('Connect(IdentityIcon)');
icon = component.find('IdentityIcon');
});
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.object.isRequired,
tokens: PropTypes.object.isRequired,

View File

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

View File

@ -40,7 +40,7 @@ describe('ui/Container/Title', () => {
});
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,38 +14,36 @@
// 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 React from 'react';
import PlaygroundExample from '~/views/Playground/playgroundExample';
import ConnectedCurrencySymbol, { CurrencySymbol } from './currencySymbol';
export default class CurrencySymbolExample extends Component {
render () {
return (
<div>
<PlaygroundExample name='Connected Currency Symbol'>
<ConnectedCurrencySymbol />
</PlaygroundExample>
export default function CurrencySymbolExample () {
return (
<div>
<PlaygroundExample name='Connected Currency Symbol'>
<ConnectedCurrencySymbol />
</PlaygroundExample>
<PlaygroundExample name='Simple Currency Symbol'>
<CurrencySymbol
netChain='testnet'
/>
</PlaygroundExample>
<PlaygroundExample name='Simple Currency Symbol'>
<CurrencySymbol
netChain='testnet'
/>
</PlaygroundExample>
<PlaygroundExample name='ETC Currency Symbol'>
<CurrencySymbol
netChain='classic'
/>
</PlaygroundExample>
<PlaygroundExample name='ETC Currency Symbol'>
<CurrencySymbol
netChain='classic'
/>
</PlaygroundExample>
<PlaygroundExample name='EXP Currency Symbol'>
<CurrencySymbol
netChain='expanse'
/>
</PlaygroundExample>
</div>
);
}
<PlaygroundExample name='EXP Currency Symbol'>
<CurrencySymbol
netChain='expanse'
/>
</PlaygroundExample>
</div>
);
}

View File

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

View File

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

View File

@ -14,50 +14,48 @@
// 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 React from 'react';
import PlaygroundExample from '~/views/Playground/playgroundExample';
import QrCode from './';
export default class QrCodeExample extends Component {
render () {
return (
<div>
<PlaygroundExample name='Simple QRCode'>
<QrCode
value='this is a test'
/>
</PlaygroundExample>
export default function QrCodeExample () {
return (
<div>
<PlaygroundExample name='Simple QRCode'>
<QrCode
value='this is a test'
/>
</PlaygroundExample>
<PlaygroundExample name='Simple QRCode with margin'>
<QrCode
margin={ 10 }
value='this is a test'
/>
</PlaygroundExample>
<PlaygroundExample name='Simple QRCode with margin'>
<QrCode
margin={ 10 }
value='this is a test'
/>
</PlaygroundExample>
<PlaygroundExample name='Ethereum Address QRCode'>
<QrCode
margin={ 10 }
value='0x8c30393085C8C3fb4C1fB16165d9fBac5D86E1D9'
/>
</PlaygroundExample>
<PlaygroundExample name='Ethereum Address QRCode'>
<QrCode
margin={ 10 }
value='0x8c30393085C8C3fb4C1fB16165d9fBac5D86E1D9'
/>
</PlaygroundExample>
<PlaygroundExample name='Bitcoin Address QRCode'>
<QrCode
margin={ 10 }
value='3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy'
/>
</PlaygroundExample>
<PlaygroundExample name='Bitcoin Address QRCode'>
<QrCode
margin={ 10 }
value='3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy'
/>
</PlaygroundExample>
<PlaygroundExample name='Big QRCode'>
<QrCode
size={ 10 }
value='this is a test'
/>
</PlaygroundExample>
</div>
);
}
<PlaygroundExample name='Big QRCode'>
<QrCode
size={ 10 }
value='this is a test'
/>
</PlaygroundExample>
</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 './';
let component;
let instance;
function render (props = {}) {
component = shallow(
@ -33,7 +32,6 @@ function render (props = {}) {
{ ...props }
/>
);
instance = component.instance();
return component;
}
@ -46,45 +44,4 @@ describe('ui/Title', () => {
it('renders defaults', () => {
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 });
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', () => {
@ -107,7 +107,7 @@ describe('ui/TxList/TxRow', () => {
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', () => {
@ -124,7 +124,7 @@ describe('ui/TxList/TxRow', () => {
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;
beforeEach(() => {
icon = component.find('Connect(IdentityIcon)');
icon = component.find('IdentityIcon');
});
it('renders', () => {

View File

@ -22,7 +22,6 @@ import VaultCard from './';
const VAULT = { name: 'testing', isOpen: true };
let component;
let instance;
function render (props = {}) {
component = shallow(
@ -31,7 +30,6 @@ function render (props = {}) {
{ ...props }
/>
);
instance = component.instance();
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(() => {
render();
icon = component.find('Connect(IdentityIcon)');
icon = component.find('IdentityIcon');
});
it('renders', () => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,42 +14,32 @@
// 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, PropTypes } from 'react';
import React, { PropTypes } from 'react';
import reactElementToJSXString from 'react-element-to-jsx-string';
import styles from './playground.css';
export default class PlaygroundExample extends Component {
static propTypes = {
children: PropTypes.node,
name: PropTypes.string
};
render () {
const { children, name } = this.props;
return (
<div className={ styles.exampleContainer }>
{ this.renderName(name) }
<div className={ styles.example }>
<div className={ styles.code }>
<code>{ reactElementToJSXString(children) }</code>
</div>
<div className={ styles.component }>
{ children }
</div>
export default function PlaygroundExample ({ children, name }) {
return (
<div className={ styles.exampleContainer }>
{
name
? <p>{ name }</p>
: null
}
<div className={ styles.example }>
<div className={ styles.code }>
<code>{ reactElementToJSXString(children) }</code>
</div>
<div className={ styles.component }>
{ children }
</div>
</div>
);
}
renderName (name) {
if (!name) {
return null;
}
return (
<p>{ name }</p>
);
}
</div>
);
}
PlaygroundExample.propTypes = {
children: PropTypes.node,
name: PropTypes.string
};

View File

@ -14,12 +14,25 @@
// 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 } from 'mobx';
import { action, computed, observable } from 'mobx';
let instance = null;
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 () {
if (!instance) {
@ -32,9 +45,4 @@ export default class PlaygroundStore {
static register (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
// 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';
@observer
export default class Parity extends Component {
export default class Node extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
};
@ -71,7 +71,7 @@ export default class Parity extends Component {
return (
<Dropdown.Item
key={ name }
contenet={ label }
content={ label }
name={ name }
onClick={ func }
>
@ -139,10 +139,13 @@ export default class Parity extends Component {
/>
<Menu
vertical
className='parityModeSelect'
id='parityModeSelect'
value={ mode }
>
<Dropdown item text={ mode }>
<Dropdown
item
text={ mode }
>
<Dropdown.Menu>
{
this.renderItem('active', this.onChangeMode, (
@ -194,7 +197,7 @@ export default class Parity extends Component {
/>
<Menu
vertical
className='parityChainSelect'
id='parityChainSelect'
value={ chain }
>
<Dropdown item text={ chain }>

View File

@ -18,23 +18,24 @@ import { shallow } from 'enzyme';
import React from 'react';
import sinon from 'sinon';
import { createApi } from './parity.test.js';
import Parity from './';
import { createApi } from './node.test.js';
import Node from './';
let component;
let instance;
function render (props = {}) {
component = shallow(
<Parity { ...props } />,
<Node { ...props } />,
{ context: { api: createApi() } }
);
instance = component.instance();
// console.log(component.debug());
return component;
}
describe('views/Settings/Parity', () => {
describe('views/Settings/Node', () => {
beforeEach(() => {
render();
sinon.spy(instance.store, 'loadMode');
@ -83,7 +84,7 @@ describe('views/Settings/Parity', () => {
let select;
beforeEach(() => {
select = component.find('Select[id="parityModeSelect"]');
select = component.find('Menu[id="parityModeSelect"]');
sinon.spy(instance.store, 'changeMode');
});
@ -94,18 +95,13 @@ describe('views/Settings/Parity', () => {
it('renders a mode selector', () => {
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', () => {
let select;
beforeEach(() => {
select = component.find('Select[id="parityChainSelect"]');
select = component.find('Menu[id="parityChainSelect"]');
sinon.spy(instance.store, 'changeChain');
});
@ -116,11 +112,6 @@ describe('views/Settings/Parity', () => {
it('renders a chain selector', () => {
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 { createApi } from './parity.test.js';
import { createApi } from './node.test.js';
import Store from './store';
let api;

View File

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

View File

@ -16,7 +16,7 @@
import sinon from 'sinon';
import Vaults from './';
import Vaults from './vaults';
import ERRORS from '~/views/Accounts/CreateAccount/errors';
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 Vaults from './';
import Vaults from './vaults';
let api;
let component;

View File

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

View File

@ -15,5 +15,5 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
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/>.
import BigNumber from 'bignumber.js';
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';
const ZEROS = '000000000000000000000000000000000000000000000000000000000000';

View File

@ -16,6 +16,6 @@
module.exports = {
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'
};