fix(test-components): merge conflicts
This commit is contained in:
commit
59cf51a8fd
|
@ -0,0 +1,48 @@
|
|||
version: 2
|
||||
|
||||
jobs:
|
||||
test:
|
||||
docker:
|
||||
- image: electronuserland/builder:wine-chrome
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt-get -y update
|
||||
- run: apt install -y software-properties-common
|
||||
- run: add-apt-repository ppa:jonathonf/ffmpeg-4
|
||||
- run: apt-get -y update
|
||||
- run: apt-get -y install libusb-1.0-0-dev graphicsmagick libudev-dev
|
||||
- run: apt-get -y install tmux xvfb libxtst6 libxss1 libgtk2.0-0 libnss3 libasound2 libgconf-2-4 ffmpeg frei0r-plugins
|
||||
# TODO: Just a quick try
|
||||
- run: rm yarn.lock
|
||||
- run: yarn install
|
||||
- run:
|
||||
name: Run Webpack
|
||||
command: yarn dev
|
||||
background: true
|
||||
- run:
|
||||
name: Run Mock RPC API
|
||||
command: yarn e2e:serve
|
||||
background: true
|
||||
- run: yarn wait-on http://localhost:8080 && yarn wait-on http://localhost:18232
|
||||
- run:
|
||||
command: Xvfb :44 -auth /tmp/xvfb.auth -ac -screen 0 1024x768x24 -listen tcp
|
||||
background: true
|
||||
- run:
|
||||
command: ffmpeg -y -f x11grab -video_size 1024x768 -i :44 -codec:v libx264 -r 12 /tmp/e2e-record.mp4
|
||||
background: true
|
||||
- run: DISPLAY=:44 yarn e2e:run
|
||||
- run: |
|
||||
kill -s SIGINT $(pgrep ffmpeg)
|
||||
sleep 10
|
||||
kill -s SIGTERM $(pgrep Xvfb)
|
||||
- store_artifacts:
|
||||
path: /tmp/e2e-record.mp4
|
||||
destination: e2e-record.mp4
|
||||
workflows:
|
||||
version: 2
|
||||
test:
|
||||
jobs:
|
||||
- test:
|
||||
filters:
|
||||
branches:
|
||||
only: develop
|
|
@ -34,7 +34,7 @@
|
|||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 80,
|
||||
"code": 100,
|
||||
"tabWidth": 2,
|
||||
"ignoreUrls": true,
|
||||
"ignoreComments": true,
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<SidebarComponent /> render() should render correctly 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="sc-bdVaJa igFjJZ"
|
||||
>
|
||||
<a
|
||||
class="sc-bwzfXH kBVjXq"
|
||||
href="/"
|
||||
>
|
||||
<img
|
||||
alt="/"
|
||||
class="sc-htpNat kwYHDD"
|
||||
src="[object Object]"
|
||||
/>
|
||||
Dashboard
|
||||
</a>
|
||||
<a
|
||||
class="sc-bwzfXH cYKDCP"
|
||||
href="/send"
|
||||
>
|
||||
<img
|
||||
alt="/send"
|
||||
class="sc-htpNat eZYlLl"
|
||||
src="[object Object]"
|
||||
/>
|
||||
Send
|
||||
</a>
|
||||
<a
|
||||
class="sc-bwzfXH cYKDCP"
|
||||
href="/receive"
|
||||
>
|
||||
<img
|
||||
alt="/receive"
|
||||
class="sc-htpNat eZYlLl"
|
||||
src="[object Object]"
|
||||
/>
|
||||
Receive
|
||||
</a>
|
||||
<a
|
||||
class="sc-bwzfXH cYKDCP"
|
||||
href="/transactions"
|
||||
>
|
||||
<img
|
||||
alt="/transactions"
|
||||
class="sc-htpNat eZYlLl"
|
||||
src="[object Object]"
|
||||
/>
|
||||
Transactions
|
||||
</a>
|
||||
<a
|
||||
class="sc-bwzfXH cYKDCP"
|
||||
href="/settings"
|
||||
>
|
||||
<img
|
||||
alt="/settings"
|
||||
class="sc-htpNat eZYlLl"
|
||||
src="[object Object]"
|
||||
/>
|
||||
Settings
|
||||
</a>
|
||||
<a
|
||||
class="sc-bwzfXH cYKDCP"
|
||||
href="/console"
|
||||
>
|
||||
<img
|
||||
alt="/console"
|
||||
class="sc-htpNat eZYlLl"
|
||||
src="[object Object]"
|
||||
/>
|
||||
Console
|
||||
</a>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
|
@ -0,0 +1,23 @@
|
|||
// @flow
|
||||
import { getApp } from '../setup/utils';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
beforeAll(async () => {
|
||||
await app.start();
|
||||
await app.client.waitUntilWindowLoaded();
|
||||
await app.client.waitUntilTextExists('#sidebar', 'Console');
|
||||
});
|
||||
afterAll(() => app.stop());
|
||||
|
||||
describe('Console', () => {
|
||||
test('should load "Console Page"', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(6)').click();
|
||||
|
||||
expect(app.client.getText('#header p:first-child')).resolves.toEqual('Console');
|
||||
|
||||
expect(app.client.element('#console-wrapper img').getAttribute('src')).resolves.toEqual(
|
||||
expect.stringContaining('/assets/console_zcash.png'),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,157 @@
|
|||
// @flow
|
||||
import { getApp } from '../setup/utils';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
beforeEach(async () => {
|
||||
await app.start();
|
||||
await app.client.waitUntilWindowLoaded();
|
||||
await app.client.waitUntilTextExists('#sidebar', 'Send');
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
});
|
||||
afterEach(() => app.stop());
|
||||
|
||||
describe('Send', () => {
|
||||
test('should load "Send Page"', async () => {
|
||||
expect(app.client.element('#send-wrapper').isVisible()).resolves.toEqual(true);
|
||||
});
|
||||
|
||||
test('should show Additional Options click', async () => {
|
||||
expect(app.client.element('#send-wrapper #send-fee-wrapper').isVisible()).resolves.toEqual(
|
||||
false,
|
||||
);
|
||||
|
||||
await app.client.element('#send-show-additional-options-button').click();
|
||||
|
||||
expect(app.client.element('#send-wrapper #send-fee-wrapper').isVisible()).resolves.toEqual(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test('should disable send button if required fields are empty', async () => {
|
||||
expect(app.client.element('#send-submit-button').getAttribute('disabled')).resolves.toEqual(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test('should enable send button if required fields are filled', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
await app.client.element('#send-wrapper #select-component').click();
|
||||
await app.client
|
||||
.element('#send-wrapper #select-component #t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW')
|
||||
.click();
|
||||
await app.client.element('#send-wrapper input[name=amount]').setValue('0.484');
|
||||
await app.client
|
||||
.element('#send-wrapper input[name=to]')
|
||||
.setValue('t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1');
|
||||
|
||||
expect(
|
||||
expect(app.client.element('#send-submit-button').getAttribute('disabled')).resolves.toEqual(
|
||||
false,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('should show confirm transaction modal', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
|
||||
await app.client.element('#send-wrapper #select-component').click();
|
||||
await app.client
|
||||
.element('#send-wrapper #select-component #t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW')
|
||||
.click();
|
||||
await app.client.element('#send-wrapper input[name=amount]').setValue('0.484');
|
||||
await app.client
|
||||
.element('#send-wrapper input[name=to]')
|
||||
.setValue('tmMEBdrnRRRMKSUUC9SWdSova7V8NmHBqET');
|
||||
|
||||
await app.client.element('#send-submit-button').click();
|
||||
|
||||
expect(app.client.element('#send-confirm-transaction-modal').isVisible()).resolves.toEqual(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test('should display a load indicator while the transaction is processed', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
|
||||
await app.client.element('#send-wrapper #select-component').click();
|
||||
await app.client
|
||||
.element('#send-wrapper #select-component #t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW')
|
||||
.click();
|
||||
await app.client.element('#send-wrapper input[name=amount]').setValue('0.484');
|
||||
await app.client
|
||||
.element('#send-wrapper input[name=to]')
|
||||
.setValue('tmMEBdrnRRRMKSUUC9SWdSova7V8NmHBqET');
|
||||
|
||||
await app.client.element('#send-submit-button').click();
|
||||
await app.client.element('#confirm-modal-button').click();
|
||||
expect(app.client.getAttribute('#send-confirm-transaction-modal img', 'src')).resolves.toEqual(
|
||||
expect.stringContaining('/assets/sync_icon.png'),
|
||||
);
|
||||
expect(app.client.getText('#send-confirm-transaction-modal p')).resolves.toEqual(
|
||||
'Processing transaction...',
|
||||
);
|
||||
expect(app.client.element('#confirm-modal-button').isVisible()).resolves.toEqual(false);
|
||||
});
|
||||
|
||||
test('should show an error in invalid transaction', async () => {
|
||||
expect(app.client.element('#send-error-text').isVisible()).resolves.toEqual(false);
|
||||
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
await app.client.element('#send-wrapper #select-component').click();
|
||||
await app.client
|
||||
.element('#send-wrapper #select-component #t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW')
|
||||
.click();
|
||||
await app.client.element('#send-wrapper input[name=amount]').setValue('-500');
|
||||
await app.client
|
||||
.element('#send-wrapper input[name=to]')
|
||||
.setValue('tmMEBdrnRRRMKSUUC9SWdSova7V8NmHBqET');
|
||||
|
||||
await app.client.element('#send-submit-button').click();
|
||||
await app.client.element('#confirm-modal-button').click();
|
||||
|
||||
expect(
|
||||
app.client
|
||||
.element('#send-error-message')
|
||||
.waitForVisible()
|
||||
.isVisible(),
|
||||
).resolves.toEqual(true);
|
||||
});
|
||||
|
||||
test('should show a success screen after transaction and show a transaction item', async () => {
|
||||
expect(app.client.element('#send-success-wrapper').isVisible()).resolves.toEqual(false);
|
||||
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
await app.client.element('#send-wrapper #select-component').click();
|
||||
await app.client
|
||||
.element('#send-wrapper #select-component #t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW')
|
||||
.click();
|
||||
await app.client.element('#send-wrapper input[name=amount]').setValue('0.484');
|
||||
await app.client
|
||||
.element('#send-wrapper input[name=to]')
|
||||
.setValue('t3Pnbg7XjP7FGasduz75HadsdzphHgkadW');
|
||||
|
||||
await app.client.element('#send-submit-button').click();
|
||||
await app.client.element('#confirm-modal-button').click();
|
||||
|
||||
await app.client
|
||||
.waitForVisible('#send-success-wrapper')
|
||||
.element('#send-confirm-transaction-modal button')
|
||||
.click();
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
|
||||
await app.client.waitUntilTextExists('#transaction-item-operation-id-1', 'Send');
|
||||
|
||||
expect(await app.client.element('#transaction-item-operation-id-1 img').isVisible()).toEqual(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
await app.client.element('#transaction-item-operation-id-1 img').getAttribute('src'),
|
||||
).toEndWith('/assets/transaction_sent_icon.svg');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,98 @@
|
|||
// @flow
|
||||
|
||||
import { getApp } from '../setup/utils';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
beforeAll(async () => {
|
||||
await app.start();
|
||||
await app.client.waitUntilWindowLoaded();
|
||||
await app.client.waitUntilTextExists('#sidebar', 'Dashboard');
|
||||
});
|
||||
afterAll(() => app.stop());
|
||||
|
||||
describe('Sidebar', () => {
|
||||
test('should see the active dashboard route', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(1)').click();
|
||||
|
||||
expect(await app.client.getUrl()).toEndWith('/');
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(1)').getHTML()).toEqual(
|
||||
expect.stringContaining('Dashboard'),
|
||||
);
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(1) img').getAttribute('src')).toEqual(
|
||||
expect.stringContaining('/assets/dashboard_icon_active.svg'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should see the active send route', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(2)').click();
|
||||
|
||||
expect(await app.client.getUrl()).toEndWith('/send');
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(2)').getHTML()).toEqual(
|
||||
expect.stringContaining('Send'),
|
||||
);
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(2) img').getAttribute('src')).toEqual(
|
||||
expect.stringContaining('/assets/send_icon_active.svg'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should see the active receive route', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(3)').click();
|
||||
|
||||
expect(await app.client.getUrl()).toEndWith('/receive');
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(3)').getHTML()).toEqual(
|
||||
expect.stringContaining('Receive'),
|
||||
);
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(3) img').getAttribute('src')).toEqual(
|
||||
expect.stringContaining('/assets/receive_icon_active.svg'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should see the active transactions route', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(4)').click();
|
||||
|
||||
expect(await app.client.getUrl()).toEndWith('/transactions');
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(4)').getHTML()).toEqual(
|
||||
expect.stringContaining('Transactions'),
|
||||
);
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(4) img').getAttribute('src')).toEqual(
|
||||
expect.stringContaining('/assets/transactions_icon_active.svg'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should see the active settings route', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(5)').click();
|
||||
|
||||
expect(await app.client.getUrl()).toEndWith('/settings');
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(5)').getHTML()).toEqual(
|
||||
expect.stringContaining('Settings'),
|
||||
);
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(5) img').getAttribute('src')).toEqual(
|
||||
expect.stringContaining('/assets/settings_icon_active.svg'),
|
||||
);
|
||||
});
|
||||
|
||||
test('should see the active console route', async () => {
|
||||
await app.client.element('#sidebar a:nth-child(6)').click();
|
||||
|
||||
expect(await app.client.getUrl()).toEndWith('/console');
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(6)').getHTML()).toEqual(
|
||||
expect.stringContaining('Console'),
|
||||
);
|
||||
|
||||
expect(await app.client.element('#sidebar a:nth-child(6) img').getAttribute('src')).toEqual(
|
||||
expect.stringContaining('/assets/console_icon_active.svg'),
|
||||
);
|
||||
});
|
||||
});
|
|
@ -2,17 +2,30 @@
|
|||
|
||||
import { getApp } from '../setup/utils';
|
||||
|
||||
describe('Zcash', () => {
|
||||
const app = getApp();
|
||||
const app = getApp();
|
||||
|
||||
beforeEach(() => app.start());
|
||||
afterEach(() => {
|
||||
app.stop();
|
||||
beforeAll(async () => {
|
||||
await app.start();
|
||||
await app.client.waitUntilWindowLoaded();
|
||||
});
|
||||
afterAll(() => app.stop());
|
||||
|
||||
describe('Startup', () => {
|
||||
test('should open the window', () => expect(app.client.getWindowCount()).resolves.toEqual(1));
|
||||
|
||||
test('should have the right title', () => {
|
||||
expect(app.client.getTitle()).resolves.toEqual('ZEC Wallet');
|
||||
});
|
||||
|
||||
test('should open the window', () => {
|
||||
app.client
|
||||
.getWindowCount()
|
||||
.then((count: number) => expect(count).toEqual(1));
|
||||
test('should show the text "ZEC Wallet Starting" in loading screen', async () => expect(app.client.element('#loading-screen:first-child p').getHTML()).resolves.toEqual(
|
||||
expect.stringContaining('ZEC Wallet Starting'),
|
||||
));
|
||||
|
||||
test('should show the zcash logo in loading screen', () => expect(app.client.getAttribute('#loading-screen:first-child img', 'src')).resolves.toEqual(
|
||||
expect.stringContaining('/assets/zcash-simple-icon.svg'),
|
||||
));
|
||||
|
||||
test('should show the loading circle in loading screen', () => {
|
||||
expect(app.client.element('#loading-screen svg').isExisting()).resolves.toEqual(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
// @flow
|
||||
import { getApp } from '../setup/utils';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
beforeAll(async () => {
|
||||
await app.start();
|
||||
await app.client.waitUntilWindowLoaded();
|
||||
await app.client.waitUntilTextExists('#sidebar', 'Dashboard');
|
||||
});
|
||||
|
||||
afterAll(() => app.stop());
|
||||
|
||||
describe('Status Pill', () => {
|
||||
test('should show status pill in the header', async () => expect(
|
||||
app.client.waitUntilTextExists('#status-pill', '50.00%').getText('#status-pill'),
|
||||
).resolves.toEqual(expect.stringContaining('50.00%')));
|
||||
});
|
|
@ -1,5 +1,7 @@
|
|||
// @flow
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
require('jest-extended');
|
||||
|
||||
// $FlowFixMe
|
||||
jest.DEFAULT_TIMEOUT_INTERVAL = 20000;
|
||||
jest.setTimeout(20000);
|
||||
jest.DEFAULT_TIMEOUT_INTERVAL = 120000;
|
||||
jest.setTimeout(120000);
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// @flow
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import 'babel-polyfill';
|
||||
|
||||
import createTestServer from 'create-test-server';
|
||||
|
||||
const transactions = [];
|
||||
|
||||
const sleep = (time: number) => new Promise(resolve => setTimeout(resolve, time));
|
||||
|
||||
createTestServer({
|
||||
httpPort: '18232',
|
||||
}).then(async (server) => {
|
||||
console.log('[MOCK RPC API]', server.url);
|
||||
|
||||
server.get('/', (req, res) => {
|
||||
res.send('Zcash RPC');
|
||||
});
|
||||
|
||||
server.post('/', async (req, res) => {
|
||||
const { method } = req.body;
|
||||
|
||||
switch (method) {
|
||||
case 'getinfo':
|
||||
sleep(1500).then(() => res.send({ result: { version: 1.0 } }));
|
||||
break;
|
||||
case 'getblockchaininfo':
|
||||
return res.send({ result: { verificationprogress: 0.5 } });
|
||||
case 'z_gettotalbalance':
|
||||
return res.send({
|
||||
result: { transparent: 2.5, private: 3.5, total: 6 },
|
||||
});
|
||||
case 'z_listaddresses':
|
||||
return res.send({
|
||||
result: ['zs1z7rejlpsa98s2rrrfkwmaxu53e4ue0ulcrw0h4x5g8jl04tak0d3mm47vdtahatqrlkngh9sly'],
|
||||
});
|
||||
case 'getaddressesbyaccount':
|
||||
return res.send({
|
||||
result: ['t3Pnbg7XjP7FGPBUuz75H65aczphHgkpoJW'],
|
||||
});
|
||||
case 'listtransactions':
|
||||
return res.send({
|
||||
result: transactions,
|
||||
});
|
||||
case 'z_sendmany':
|
||||
// eslint-disable-next-line
|
||||
sleep(2000).then(() => {
|
||||
const [, [obj], amount, fee] = req.body.params;
|
||||
|
||||
if ((obj.address[0] === 'z' || obj.address[0] === 't') && amount > 0) {
|
||||
transactions.push({
|
||||
account: '',
|
||||
address: obj.address,
|
||||
category: 'send',
|
||||
amount: obj.amount,
|
||||
vout: 0,
|
||||
fee,
|
||||
confirmations: 10,
|
||||
blockhash: 20,
|
||||
blockindex: 10,
|
||||
txid: `operation-id-${transactions.length + 1}`,
|
||||
time: Date.now(),
|
||||
timereceived: Date.now(),
|
||||
comment: '',
|
||||
otheraccount: '',
|
||||
size: 10,
|
||||
});
|
||||
|
||||
return res.send({ result: 'operation-id-1' });
|
||||
}
|
||||
|
||||
return res.status(500).send({ error: { message: 'Invalid address!' } });
|
||||
});
|
||||
break;
|
||||
case 'z_validateaddress':
|
||||
// eslint-disable-next-line
|
||||
const [zAd] = req.body.params;
|
||||
|
||||
if (zAd[0] === 'z' || zAd[0] === 't') {
|
||||
return res.send({ result: { isvalid: true } });
|
||||
}
|
||||
|
||||
return res.send({ result: { isvalid: false } });
|
||||
case 'validateaddress':
|
||||
// eslint-disable-next-line
|
||||
const [tAd] = req.body.params;
|
||||
|
||||
if (tAd[0] === 'z' || tAd[0] === 't') {
|
||||
return res.send({ result: { isvalid: true } });
|
||||
}
|
||||
|
||||
return res.send({ result: { isvalid: false } });
|
||||
case 'z_getoperationstatus':
|
||||
return res.send({
|
||||
result: [{ id: 'operation-id-1', status: 'success', result: { txid: 'txid-1' } }],
|
||||
});
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,13 +1,17 @@
|
|||
// @flow
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import electron from 'electron';
|
||||
import { Application } from 'spectron';
|
||||
|
||||
export const TIMEOUT = 10000;
|
||||
export const TIMEOUT = 20000;
|
||||
|
||||
export const getApp = () => new Application({
|
||||
path: electron,
|
||||
args: ['.'],
|
||||
startTimeout: TIMEOUT,
|
||||
waitTimeout: TIMEOUT,
|
||||
quitTimeout: TIMEOUT,
|
||||
env: {
|
||||
NODE_ENV: 'test',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Link } from 'react-router-dom';
|
|||
/* eslint-disable max-len */
|
||||
// $FlowFixMe
|
||||
import { darken } from 'polished';
|
||||
import type { ElementProps } from 'react';
|
||||
|
||||
const DefaultButton = styled.button`
|
||||
align-items: center;
|
||||
|
@ -20,8 +21,7 @@ const DefaultButton = styled.button`
|
|||
outline: none;
|
||||
min-width: 100px;
|
||||
border-radius: 100px;
|
||||
transition: background-color 0.1s
|
||||
${props => props.theme.colors.transitionEase};
|
||||
transition: background-color 0.1s ${props => props.theme.colors.transitionEase};
|
||||
`;
|
||||
|
||||
const Primary = styled(DefaultButton)`
|
||||
|
@ -67,6 +67,7 @@ const Icon = styled.img`
|
|||
`;
|
||||
|
||||
type Props = {
|
||||
...ElementProps<'button'>,
|
||||
label: string,
|
||||
onClick?: () => void,
|
||||
to?: ?string,
|
||||
|
@ -86,6 +87,7 @@ export const Button = ({
|
|||
icon,
|
||||
className,
|
||||
isLoading,
|
||||
id,
|
||||
}: Props) => {
|
||||
if (to && onClick) throw new Error('Should define either "to" or "onClick"');
|
||||
|
||||
|
@ -94,6 +96,7 @@ export const Button = ({
|
|||
disabled: disabled || isLoading,
|
||||
icon: null,
|
||||
className,
|
||||
id,
|
||||
};
|
||||
const buttonLabel = isLoading ? 'Loading...' : label;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import type { Node } from 'react';
|
||||
import type { Node, ElementProps } from 'react';
|
||||
|
||||
const Flex = styled.div`
|
||||
display: flex;
|
||||
|
@ -13,6 +13,7 @@ const Flex = styled.div`
|
|||
`;
|
||||
|
||||
type Props = {
|
||||
...ElementProps<'div'>,
|
||||
alignItems?: string,
|
||||
justifyContent?: string,
|
||||
className?: string,
|
||||
|
|
|
@ -74,6 +74,7 @@ export const ConfirmDialogComponent = ({
|
|||
|
||||
return (
|
||||
<ModalComponent
|
||||
id='confirm-dialog-modal-wrapper'
|
||||
renderTrigger={renderTrigger}
|
||||
closeOnBackdropClick={false}
|
||||
closeOnEsc={false}
|
||||
|
@ -90,7 +91,12 @@ export const ConfirmDialogComponent = ({
|
|||
{children(handleClose(toggle))}
|
||||
{showButtons && (
|
||||
<>
|
||||
<Btn label='Confirm' onClick={onConfirm} isLoading={isLoading} />
|
||||
<Btn
|
||||
id='confirm-modal-button'
|
||||
label='Confirm'
|
||||
onClick={onConfirm}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<Btn
|
||||
label='Cancel'
|
||||
onClick={handleClose(toggle)}
|
||||
|
|
|
@ -66,7 +66,7 @@ const Status = withSyncStatus(StatusPill);
|
|||
export const HeaderComponent = ({ title }: Props) => {
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Wrapper id='header'>
|
||||
<LogoWrapper>
|
||||
<ZcashLogo />
|
||||
</LogoWrapper>
|
||||
|
|
|
@ -4,6 +4,6 @@ import styled from 'styled-components';
|
|||
import { TextComponent } from './text';
|
||||
|
||||
export const InputLabelComponent = styled(TextComponent)`
|
||||
margin: 20px 0 8.5px 0;
|
||||
margin: ${props => props.marginTop || '20px'} 0 8.5px 0;
|
||||
font-weight: ${props => props.theme.fontWeight.bold};
|
||||
`;
|
||||
|
|
|
@ -7,8 +7,7 @@ import theme from '../theme';
|
|||
const getDefaultStyles = t => styled[t]`
|
||||
border-radius: ${props => props.theme.boxBorderRadius};
|
||||
border: none;
|
||||
background-color: ${
|
||||
props => props.bgColor || props.theme.colors.inputBackground};
|
||||
background-color: ${props => props.bgColor || props.theme.colors.inputBackground};
|
||||
color: ${props => props.theme.colors.text};
|
||||
padding: 15px;
|
||||
padding-right: ${props => (props.withRightElement ? '85px' : '15px')};
|
||||
|
@ -43,6 +42,7 @@ type Props = {
|
|||
disabled?: boolean,
|
||||
type?: string,
|
||||
step?: number,
|
||||
name?: string,
|
||||
renderRight?: () => Element<*> | null,
|
||||
bgColor?: string,
|
||||
};
|
||||
|
@ -66,11 +66,7 @@ export const InputComponent = ({
|
|||
/>
|
||||
),
|
||||
textarea: () => (
|
||||
<Textarea
|
||||
onChange={evt => onChange(evt.target.value)}
|
||||
bgColor={bgColor}
|
||||
{...props}
|
||||
/>
|
||||
<Textarea onChange={evt => onChange(evt.target.value)} bgColor={bgColor} {...props} />
|
||||
),
|
||||
};
|
||||
|
||||
|
@ -91,6 +87,7 @@ InputComponent.defaultProps = {
|
|||
rows: 4,
|
||||
disabled: false,
|
||||
type: 'text',
|
||||
name: '',
|
||||
renderRight: () => null,
|
||||
onChange: () => {},
|
||||
onFocus: () => {},
|
||||
|
|
|
@ -21,5 +21,5 @@ export const LayoutComponent = (props: Props) => {
|
|||
// $FlowFixMe
|
||||
const { children } = props; // eslint-disable-line
|
||||
|
||||
return <Layout>{children}</Layout>;
|
||||
return <Layout id='layout'>{children}</Layout>;
|
||||
};
|
||||
|
|
|
@ -38,11 +38,11 @@ const Logo = styled.img`
|
|||
|
||||
type Props = {
|
||||
progress: number,
|
||||
}
|
||||
};
|
||||
|
||||
type State = {
|
||||
start: boolean,
|
||||
}
|
||||
};
|
||||
|
||||
const TIME_DELAY_ANIM = 100;
|
||||
|
||||
|
@ -64,16 +64,17 @@ export class LoadingScreen extends PureComponent<Props, State> {
|
|||
<Transition
|
||||
native
|
||||
items={start}
|
||||
enter={[{ height: 'auto' }]}
|
||||
leave={{ height: 0 }}
|
||||
enter={[{ height: 'auto', opacity: 1 }]}
|
||||
leave={{ height: 0, opacity: 0 }}
|
||||
from={{
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
}}
|
||||
>
|
||||
{() => props => (
|
||||
<animated.div style={props}>
|
||||
<animated.div style={props} id='loading-screen'>
|
||||
<CircleWrapper>
|
||||
<Logo src={zcashLogo} alt='Zcash logo' />
|
||||
<CircleProgressComponent
|
||||
|
|
|
@ -13,7 +13,7 @@ const ModalWrapper = styled.div`
|
|||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
`;
|
||||
|
||||
const ChildrenWrapper = styled.div`
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import type { Node } from 'react';
|
||||
import type { Node, ElementProps } from 'react';
|
||||
|
||||
const Flex = styled.div`
|
||||
display: flex;
|
||||
|
@ -12,6 +12,7 @@ const Flex = styled.div`
|
|||
`;
|
||||
|
||||
type Props = {
|
||||
...ElementProps<'div'>,
|
||||
alignItems?: string,
|
||||
justifyContent?: string,
|
||||
className?: string,
|
||||
|
|
|
@ -24,9 +24,7 @@ const SelectWrapper = styled.div`
|
|||
position: relative;
|
||||
|
||||
${props => props.isOpen
|
||||
&& `border-${props.placement}-left-radius: 0; border-${
|
||||
props.placement
|
||||
}-right-radius: 0;`}
|
||||
&& `border-${props.placement}-left-radius: 0; border-${props.placement}-right-radius: 0;`}
|
||||
`;
|
||||
/* eslint-enable max-len */
|
||||
|
||||
|
@ -156,6 +154,7 @@ export class SelectComponent extends PureComponent<Props, State> {
|
|||
|
||||
return (
|
||||
<SelectWrapper
|
||||
id='select-component'
|
||||
isOpen={isOpen}
|
||||
placement={placement}
|
||||
onClick={() => this.setState(() => ({ isOpen: !isOpen }))}
|
||||
|
@ -177,6 +176,7 @@ export class SelectComponent extends PureComponent<Props, State> {
|
|||
>
|
||||
{options.map(({ label, value: optionValue }) => (
|
||||
<Option
|
||||
id={optionValue}
|
||||
key={label + optionValue}
|
||||
onClick={() => this.onSelect(optionValue)}
|
||||
bgColor={bgColor}
|
||||
|
|
|
@ -40,10 +40,10 @@ const StyledLink = styled(Link)`
|
|||
transition: all 0.03s ${props => props.theme.colors.transitionEase};
|
||||
|
||||
&:hover {
|
||||
color: ${/* eslint-disable-next-line max-len */
|
||||
props => (props.isActive
|
||||
? props.theme.colors.sidebarItemActive
|
||||
: '#ddd')}
|
||||
color: ${
|
||||
/* eslint-disable-next-line max-len */
|
||||
props => (props.isActive ? props.theme.colors.sidebarItemActive : '#ddd')
|
||||
}
|
||||
background-color: ${props => props.theme.colors.sidebarHoveredItem};
|
||||
}
|
||||
`;
|
||||
|
@ -70,16 +70,12 @@ type Props = {
|
|||
};
|
||||
|
||||
export const SidebarComponent = ({ options, location }: Props) => (
|
||||
<Wrapper>
|
||||
<Wrapper id='sidebar'>
|
||||
{(options || []).map((item) => {
|
||||
const isActive = location.pathname === item.route;
|
||||
|
||||
return (
|
||||
<StyledLink
|
||||
isActive={isActive}
|
||||
key={item.route}
|
||||
to={item.route}
|
||||
>
|
||||
<StyledLink isActive={isActive} key={item.route} to={item.route}>
|
||||
<Icon
|
||||
isActive={isActive}
|
||||
src={item.icon(isActive)}
|
||||
|
|
|
@ -63,4 +63,4 @@ export const StatusPill = ({ type, progress }: State) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default StatusPill;
|
||||
export default StatusPill;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// @flow
|
||||
/* eslint-disable max-len */
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import type { ElementProps } from 'react';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
|
@ -10,13 +12,12 @@ const Text = styled.p`
|
|||
color: ${props => props.color || props.theme.colors.text};
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: ${props => (props.isBold
|
||||
? props.theme.fontWeight.bold
|
||||
: props.theme.fontWeight.default)};
|
||||
font-weight: ${props => (props.isBold ? props.theme.fontWeight.bold : props.theme.fontWeight.default)};
|
||||
text-align: ${props => props.align};
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
...ElementProps<'p'>,
|
||||
value: string,
|
||||
isBold?: boolean,
|
||||
color?: string,
|
||||
|
@ -26,14 +27,10 @@ type Props = {
|
|||
};
|
||||
|
||||
export const TextComponent = ({
|
||||
value,
|
||||
isBold,
|
||||
color,
|
||||
className,
|
||||
size,
|
||||
align,
|
||||
value, isBold, color, className, size, align, id,
|
||||
}: Props) => (
|
||||
<Text
|
||||
id={id}
|
||||
className={className}
|
||||
isBold={isBold}
|
||||
color={color}
|
||||
|
|
|
@ -90,6 +90,7 @@ export const TransactionItemComponent = ({
|
|||
<ModalComponent
|
||||
renderTrigger={toggleVisibility => (
|
||||
<Wrapper
|
||||
id={`transaction-item-${transactionId}`}
|
||||
alignItems='center'
|
||||
justifyContent='space-between'
|
||||
onClick={toggleVisibility}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Transition, animated } from 'react-spring';
|
||||
|
||||
import { ColumnComponent } from './column';
|
||||
import { Button } from './button';
|
||||
|
@ -36,16 +37,16 @@ const Input = styled.input`
|
|||
|
||||
const Btn = styled(Button)`
|
||||
border-width: 1px;
|
||||
font-weight: ${props => props.theme.fontWeight.light};
|
||||
font-weight: ${props => props.theme.fontWeight.regular};
|
||||
border-color: ${props => (props.isVisible
|
||||
? props.theme.colors.primary : props.theme.colors.buttonBorderColor
|
||||
)};
|
||||
padding: 6px 10px;
|
||||
width: 50%;
|
||||
padding: 8px 10px;
|
||||
min-width: 260px;
|
||||
|
||||
img {
|
||||
height: 12px;
|
||||
width: 16px;
|
||||
width: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -59,36 +60,52 @@ const QRCodeWrapper = styled.div`
|
|||
width: 100%;
|
||||
`;
|
||||
|
||||
const RevealsMain = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
height: ${props => (props.isVisible ? '178px' : 0)}
|
||||
transition: all 0.25s ease-in-out;
|
||||
|
||||
& > div {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
address: string,
|
||||
isVisible?: boolean,
|
||||
};
|
||||
|
||||
type State = {
|
||||
isVisible: boolean,
|
||||
};
|
||||
|
||||
export class WalletAddress extends Component<Props, State> {
|
||||
state = {
|
||||
export class WalletAddress extends PureComponent<Props, State> {
|
||||
static defaultProps = {
|
||||
isVisible: false,
|
||||
};
|
||||
}
|
||||
|
||||
show = () => {
|
||||
this.setState(
|
||||
() => ({ isVisible: true }),
|
||||
);
|
||||
};
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
hide = () => {
|
||||
this.setState(
|
||||
() => ({ isVisible: false }),
|
||||
);
|
||||
};
|
||||
this.state = { isVisible: Boolean(props.isVisible) };
|
||||
}
|
||||
|
||||
show = () => this.setState(() => ({ isVisible: true }));
|
||||
|
||||
hide = () => this.setState(() => ({ isVisible: false }));
|
||||
|
||||
render() {
|
||||
const { address } = this.props;
|
||||
const { isVisible } = this.state;
|
||||
const toggleVisibility = isVisible ? this.hide : this.show;
|
||||
const buttonLabel = `${isVisible ? 'Hide' : 'Show'} details and QR Code`;
|
||||
|
||||
return (
|
||||
<ColumnComponent width='100%'>
|
||||
|
@ -100,19 +117,37 @@ export class WalletAddress extends Component<Props, State> {
|
|||
/>
|
||||
<Btn
|
||||
icon={eyeIcon}
|
||||
label={`${isVisible ? 'Hide' : 'Show'} full address and QR Code`}
|
||||
label={buttonLabel}
|
||||
onClick={toggleVisibility}
|
||||
variant='secondary'
|
||||
isVisible={isVisible}
|
||||
/>
|
||||
</AddressWrapper>
|
||||
{isVisible
|
||||
? (
|
||||
<QRCodeWrapper>
|
||||
<QRCode value={address} />
|
||||
</QRCodeWrapper>
|
||||
)
|
||||
: null}
|
||||
<RevealsMain isVisible={isVisible}>
|
||||
<Transition
|
||||
native
|
||||
items={isVisible}
|
||||
enter={[{
|
||||
height: 'auto',
|
||||
opacity: 1,
|
||||
}]}
|
||||
leave={{ height: 0, opacity: 0 }}
|
||||
from={{
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
}}
|
||||
>
|
||||
{show => show && (props => (
|
||||
<animated.div style={props}>
|
||||
<QRCodeWrapper>
|
||||
<QRCode value={address} />
|
||||
</QRCodeWrapper>
|
||||
</animated.div>
|
||||
))}
|
||||
</Transition>
|
||||
</RevealsMain>
|
||||
</ColumnComponent>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -22,10 +22,7 @@ import filterObjectNullKeys from '../utils/filterObjectNullKeys';
|
|||
import type { AppState } from '../types/app-state';
|
||||
import type { Dispatch } from '../types/redux';
|
||||
|
||||
import {
|
||||
loadAddressesSuccess,
|
||||
loadAddressesError,
|
||||
} from '../redux/modules/receive';
|
||||
import { loadAddressesSuccess, loadAddressesError } from '../redux/modules/receive';
|
||||
|
||||
export type SendTransactionInput = {
|
||||
from: string,
|
||||
|
@ -47,11 +44,7 @@ const mapStateToProps = ({ walletSummary, sendStatus, receive }: AppState) => ({
|
|||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||
sendTransaction: async ({
|
||||
from,
|
||||
to,
|
||||
amount,
|
||||
fee,
|
||||
memo,
|
||||
from, to, amount, fee, memo,
|
||||
}: SendTransactionInput) => {
|
||||
dispatch(sendTransaction());
|
||||
|
||||
|
@ -95,16 +88,12 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
|
|||
|
||||
if (operationStatus && operationStatus.status === 'success') {
|
||||
clearInterval(interval);
|
||||
dispatch(
|
||||
sendTransactionSuccess({ operationId: operationStatus.result.txid }),
|
||||
);
|
||||
dispatch(sendTransactionSuccess({ operationId: operationStatus.result.txid }));
|
||||
}
|
||||
|
||||
if (operationStatus && operationStatus.status === 'failed') {
|
||||
clearInterval(interval);
|
||||
dispatch(
|
||||
sendTransactionError({ error: operationStatus.error.message }),
|
||||
);
|
||||
dispatch(sendTransactionError({ error: operationStatus.error.message }));
|
||||
}
|
||||
}, 2000);
|
||||
},
|
||||
|
@ -135,9 +124,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
|
|||
loadAddresses: async () => {
|
||||
const [zAddressesErr, zAddresses] = await eres(rpc.z_listaddresses());
|
||||
|
||||
const [tAddressesErr, transparentAddresses] = await eres(
|
||||
rpc.getaddressesbyaccount(''),
|
||||
);
|
||||
const [tAddressesErr, transparentAddresses] = await eres(rpc.getaddressesbyaccount(''));
|
||||
|
||||
if (zAddressesErr || tAddressesErr) return dispatch(loadAddressesError({ error: 'Something went wrong!' }));
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ export class ConsoleView extends Component<Props, State> {
|
|||
const { log } = this.state;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Wrapper id='console-wrapper'>
|
||||
<Fragment>
|
||||
<ConsoleImg src={ConsoleSymbol} alt='Zcashd' />
|
||||
{log.split('\n').map((item, idx) => (
|
||||
|
|
|
@ -1,50 +1,165 @@
|
|||
// @flow
|
||||
import React, { PureComponent } from 'react';
|
||||
import React, { Fragment, PureComponent } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Transition, animated } from 'react-spring';
|
||||
|
||||
import { InputLabelComponent } from '../components/input-label';
|
||||
import { RowComponent } from '../components/row';
|
||||
import { TextComponent } from '../components/text';
|
||||
import { WalletAddress } from '../components/wallet-address';
|
||||
|
||||
type Props = {
|
||||
addresses: Array<string>,
|
||||
loadAddresses: () => void,
|
||||
};
|
||||
|
||||
const Wrapper = styled.div`
|
||||
margin-top: ${props => props.theme.layoutContentPaddingTop};
|
||||
`;
|
||||
import MenuIcon from '../assets/images/menu_icon.svg';
|
||||
|
||||
const Row = styled(RowComponent)`
|
||||
margin-bottom: 10px;
|
||||
`;
|
||||
|
||||
const Label = styled(InputLabelComponent)`
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 10px;
|
||||
text-transform: uppercase;
|
||||
color: ${props => props.theme.colors.transactionsDate};
|
||||
font-size: ${props => `${props.theme.fontSize.regular * 0.9}em`};
|
||||
font-weight: ${props => props.theme.fontWeight.bold};
|
||||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
export class ReceiveView extends PureComponent<Props> {
|
||||
const ShowMoreButton = styled.button`
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
color: ${props => props.theme.colors.text};
|
||||
outline: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const ShowMoreIcon = styled.img`
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border: 1px solid ${props => props.theme.colors.text};
|
||||
border-radius: 100%;
|
||||
margin-right: 11.5px;
|
||||
`;
|
||||
|
||||
const RevealsMain = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
|
||||
& > div {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
addresses: Array<string>,
|
||||
loadAddresses: () => void,
|
||||
};
|
||||
|
||||
type State = {
|
||||
showAdditionalOptions: boolean,
|
||||
}
|
||||
|
||||
export class ReceiveView extends PureComponent<Props, State> {
|
||||
state = {
|
||||
showAdditionalOptions: false,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { loadAddresses } = this.props;
|
||||
|
||||
loadAddresses();
|
||||
}
|
||||
|
||||
toggleAdditionalOptions = () => this.setState((prevState: State) => ({
|
||||
showAdditionalOptions: !prevState.showAdditionalOptions,
|
||||
}));
|
||||
|
||||
renderShieldedAddresses = (address: string) => {
|
||||
const { showAdditionalOptions } = this.state;
|
||||
const buttonText = `${showAdditionalOptions ? 'Hide' : 'Show'} Other Address Types`;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Label value='Shielded Address' />
|
||||
<Row
|
||||
alignItems='center'
|
||||
justifyContent='space-between'
|
||||
>
|
||||
<WalletAddress address={address} />
|
||||
</Row>
|
||||
<Row>
|
||||
<ShowMoreButton
|
||||
onClick={this.toggleAdditionalOptions}
|
||||
isActive={showAdditionalOptions}
|
||||
>
|
||||
<ShowMoreIcon
|
||||
isActive={showAdditionalOptions}
|
||||
src={MenuIcon}
|
||||
alt='More Options'
|
||||
/>
|
||||
<TextComponent value={buttonText} />
|
||||
</ShowMoreButton>
|
||||
</Row>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
renderTransparentAddresses = (address: string) => {
|
||||
const { showAdditionalOptions } = this.state;
|
||||
|
||||
return (
|
||||
<RevealsMain>
|
||||
<Transition
|
||||
native
|
||||
items={showAdditionalOptions}
|
||||
enter={[{ height: 'auto', opacity: 1 }]}
|
||||
leave={{ height: 0, opacity: 0 }}
|
||||
from={{
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
}}
|
||||
>
|
||||
{show => show && (props => (
|
||||
<animated.div style={props}>
|
||||
<Label value='Transparent Address (not private)' />
|
||||
<Row
|
||||
key={address}
|
||||
alignItems='center'
|
||||
justifyContent='space-between'
|
||||
>
|
||||
<WalletAddress address={address} />
|
||||
</Row>
|
||||
</animated.div>
|
||||
))}
|
||||
</Transition>
|
||||
</RevealsMain>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { addresses } = this.props;
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Label value='Addresses: ' />
|
||||
{(addresses || []).map(address => (
|
||||
<Row key={address} alignItems='center' justifyContent='space-between'>
|
||||
<WalletAddress address={address} />
|
||||
</Row>
|
||||
))}
|
||||
</Wrapper>
|
||||
<div>
|
||||
{(addresses || []).map((address, index) => {
|
||||
if (index === 0) return this.renderShieldedAddresses(address);
|
||||
return this.renderTransparentAddresses(address);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// @flow
|
||||
import React, { PureComponent } from 'react';
|
||||
import React, { Fragment, PureComponent } from 'react';
|
||||
import styled, { keyframes } from 'styled-components';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import { Transition, animated } from 'react-spring';
|
||||
|
||||
import FEES from '../constants/fees';
|
||||
|
||||
|
@ -58,6 +59,7 @@ const SendWrapper = styled(ColumnComponent)`
|
|||
|
||||
const AmountWrapper = styled.div`
|
||||
width: 100%;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: 'ZEC';
|
||||
|
@ -67,14 +69,14 @@ const AmountWrapper = styled.div`
|
|||
margin-left: 15px;
|
||||
display: block;
|
||||
transition: all 0.05s ease-in-out;
|
||||
opacity: ${props => (props.isEmpty ? 0.25 : 1)};
|
||||
opacity: ${props => (props.isEmpty ? '0' : '1')};
|
||||
color: #fff;
|
||||
z-index: 20;
|
||||
z-index: 10;
|
||||
}
|
||||
`;
|
||||
|
||||
const AmountInput = styled(InputComponent)`
|
||||
padding-left: 50px;
|
||||
padding-left: ${props => (props.isEmpty ? '15' : '50')}px;
|
||||
`;
|
||||
|
||||
const ShowFeeButton = styled.button`
|
||||
|
@ -86,7 +88,7 @@ const ShowFeeButton = styled.button`
|
|||
outline: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 30px;
|
||||
margin: 30px 0;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
|
@ -104,7 +106,7 @@ const SeeMoreIcon = styled.img`
|
|||
|
||||
const FeeWrapper = styled.div`
|
||||
background-color: #000;
|
||||
border-radius: 6px;
|
||||
border-radius: 4px;
|
||||
padding: 13px 19px;
|
||||
margin-bottom: 20px;
|
||||
`;
|
||||
|
@ -132,18 +134,6 @@ const InfoCardUSD = styled(TextComponent)`
|
|||
const FormButton = styled(Button)`
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
border-color: ${props => (props.focused
|
||||
? props.theme.colors.activeItem
|
||||
: props.theme.colors.inactiveItem)};
|
||||
|
||||
&:hover {
|
||||
border-color: ${props => (props.focused
|
||||
? props.theme.colors.activeItem
|
||||
: props.theme.colors.inactiveItem)};
|
||||
background-color: ${props => (props.focused
|
||||
? props.theme.colors.activeItem
|
||||
: props.theme.colors.inactiveItem)};
|
||||
}
|
||||
`;
|
||||
|
||||
const ModalContent = styled(ColumnComponent)`
|
||||
|
@ -192,12 +182,28 @@ const ValidateStatusIcon = styled.img`
|
|||
margin-right: 7px;
|
||||
`;
|
||||
|
||||
const RevealsMain = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
|
||||
& > div {
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
...SendState,
|
||||
balance: number,
|
||||
zecPrice: number,
|
||||
addresses: string[],
|
||||
sendTransaction: SendTransactionInput => void,
|
||||
loadAddresses: () => void,
|
||||
resetSendView: () => void,
|
||||
validateAddress: ({ address: string }) => void,
|
||||
loadAddresses: () => void,
|
||||
|
@ -240,7 +246,8 @@ export class SendView extends PureComponent<Props, State> {
|
|||
|
||||
if (field === 'to') {
|
||||
// eslint-disable-next-line max-len
|
||||
this.setState({ [field]: value }, () => validateAddress({ address: value }));
|
||||
this.setState(() => ({ [field]: value }),
|
||||
() => validateAddress({ address: value }));
|
||||
} else {
|
||||
this.setState(() => ({ [field]: value }));
|
||||
}
|
||||
|
@ -248,17 +255,17 @@ export class SendView extends PureComponent<Props, State> {
|
|||
|
||||
handleChangeFeeType = (value: string) => {
|
||||
if (value === FEES.CUSTOM) {
|
||||
this.setState({
|
||||
this.setState(() => ({
|
||||
feeType: FEES.CUSTOM,
|
||||
fee: null,
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
const fee = new BigNumber(value);
|
||||
|
||||
this.setState({
|
||||
this.setState(() => ({
|
||||
feeType: fee.toString(),
|
||||
fee: fee.toNumber(),
|
||||
});
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -316,12 +323,18 @@ export class SendView extends PureComponent<Props, State> {
|
|||
return isToAddressValid ? (
|
||||
<RowComponent alignItems='center'>
|
||||
<ValidateStatusIcon src={ValidIcon} />
|
||||
<ItemLabel value='VALID' color={theme.colors.transactionReceived} />
|
||||
<ItemLabel
|
||||
value='VALID'
|
||||
color={theme.colors.transactionReceived}
|
||||
/>
|
||||
</RowComponent>
|
||||
) : (
|
||||
<RowComponent alignItems='center'>
|
||||
<ValidateStatusIcon src={InvalidIcon} />
|
||||
<ItemLabel value='INVALID' color={theme.colors.transactionSent} />
|
||||
<ItemLabel
|
||||
value='INVALID'
|
||||
color={theme.colors.transactionSent}
|
||||
/>
|
||||
</RowComponent>
|
||||
);
|
||||
};
|
||||
|
@ -343,16 +356,19 @@ export class SendView extends PureComponent<Props, State> {
|
|||
|
||||
if (isSending) {
|
||||
return (
|
||||
<>
|
||||
<Fragment>
|
||||
<Loader src={LoadingIcon} />
|
||||
<TextComponent value='Processing transaction...' />
|
||||
</>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
if (operationId) {
|
||||
return (
|
||||
<>
|
||||
<ColumnComponent
|
||||
width='100%'
|
||||
id='send-success-wrapper'
|
||||
>
|
||||
<TextComponent
|
||||
value={`Transaction ID: ${operationId}`}
|
||||
align='center'
|
||||
|
@ -366,11 +382,11 @@ export class SendView extends PureComponent<Props, State> {
|
|||
>
|
||||
Send again!
|
||||
</button>
|
||||
</>
|
||||
</ColumnComponent>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) return <TextComponent value={error} />;
|
||||
if (error) return <TextComponent id='send-error-message' value={error} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -412,12 +428,7 @@ export class SendView extends PureComponent<Props, State> {
|
|||
|
||||
render() {
|
||||
const {
|
||||
addresses,
|
||||
balance,
|
||||
zecPrice,
|
||||
isSending,
|
||||
error,
|
||||
operationId,
|
||||
addresses, balance, zecPrice, isSending, error, operationId,
|
||||
} = this.props;
|
||||
const {
|
||||
showFee, from, amount, to, memo, fee, feeType,
|
||||
|
@ -442,7 +453,7 @@ export class SendView extends PureComponent<Props, State> {
|
|||
});
|
||||
|
||||
return (
|
||||
<RowComponent justifyContent='space-between'>
|
||||
<RowComponent id='send-wrapper' justifyContent='space-between'>
|
||||
<FormWrapper>
|
||||
<InputLabelComponent value='From' />
|
||||
<SelectComponent
|
||||
|
@ -458,8 +469,9 @@ export class SendView extends PureComponent<Props, State> {
|
|||
type='number'
|
||||
onChange={this.handleChange('amount')}
|
||||
value={String(amount)}
|
||||
placeholder='0.0'
|
||||
placeholder='ZEC 0.0'
|
||||
min={0.01}
|
||||
name='amount'
|
||||
/>
|
||||
</AmountWrapper>
|
||||
<InputLabelComponent value='To' />
|
||||
|
@ -468,6 +480,7 @@ export class SendView extends PureComponent<Props, State> {
|
|||
value={to}
|
||||
placeholder='Enter Address'
|
||||
renderRight={to ? this.renderValidationStatus : () => null}
|
||||
name='to'
|
||||
/>
|
||||
<InputLabelComponent value='Memo' />
|
||||
<InputComponent
|
||||
|
@ -475,47 +488,75 @@ export class SendView extends PureComponent<Props, State> {
|
|||
value={memo}
|
||||
inputType='textarea'
|
||||
placeholder='Enter a text here'
|
||||
name='memo'
|
||||
/>
|
||||
<ShowFeeButton
|
||||
onClick={() => this.setState(state => ({ showFee: !state.showFee }))
|
||||
}
|
||||
id='send-show-additional-options-button'
|
||||
onClick={() => this.setState(state => ({
|
||||
showFee: !state.showFee,
|
||||
}))}
|
||||
>
|
||||
<SeeMoreIcon src={MenuIcon} alt='Show more icon' />
|
||||
<SeeMoreIcon
|
||||
src={MenuIcon}
|
||||
alt='Show more icon'
|
||||
/>
|
||||
<TextComponent
|
||||
value={`${showFee ? 'Hide' : 'Show'} Additional Options`}
|
||||
/>
|
||||
</ShowFeeButton>
|
||||
{showFee && (
|
||||
<FeeWrapper>
|
||||
<RowComponent
|
||||
alignItems='flex-end'
|
||||
justifyContent='space-between'
|
||||
>
|
||||
<ColumnComponent width='74%'>
|
||||
<InputLabelComponent value='Fee' />
|
||||
<InputComponent
|
||||
type='number'
|
||||
onChange={this.handleChange('fee')}
|
||||
value={String(fee)}
|
||||
disabled={feeType !== FEES.CUSTOM}
|
||||
bgColor={theme.colors.blackTwo}
|
||||
/>
|
||||
</ColumnComponent>
|
||||
<ColumnComponent width='25%'>
|
||||
<SelectComponent
|
||||
onChange={this.handleChangeFeeType}
|
||||
value={String(feeType)}
|
||||
options={Object.keys(FEES).map(cur => ({
|
||||
label: cur.toLowerCase(),
|
||||
value: String(FEES[cur]),
|
||||
}))}
|
||||
placement='top'
|
||||
bgColor={theme.colors.blackTwo}
|
||||
/>
|
||||
</ColumnComponent>
|
||||
</RowComponent>
|
||||
</FeeWrapper>
|
||||
)}
|
||||
<RevealsMain>
|
||||
<Transition
|
||||
native
|
||||
items={showFee}
|
||||
enter={[{
|
||||
height: 'auto',
|
||||
opacity: 1,
|
||||
overflow: 'visible',
|
||||
}]}
|
||||
leave={{ height: 0, opacity: 0 }}
|
||||
from={{
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
}}
|
||||
>
|
||||
{show => show && (props => (
|
||||
<animated.div style={props}>
|
||||
<FeeWrapper id='send-fee-wrapper'>
|
||||
<RowComponent
|
||||
alignItems='flex-end'
|
||||
justifyContent='space-between'
|
||||
>
|
||||
<ColumnComponent width='74%'>
|
||||
<InputLabelComponent value='Fee' />
|
||||
<InputComponent
|
||||
type='number'
|
||||
onChange={this.handleChange('fee')}
|
||||
value={String(fee)}
|
||||
disabled={feeType !== FEES.CUSTOM}
|
||||
bgColor={theme.colors.blackTwo}
|
||||
name='fee'
|
||||
/>
|
||||
</ColumnComponent>
|
||||
<ColumnComponent width='25%'>
|
||||
<SelectComponent
|
||||
placement='top'
|
||||
value={String(feeType)}
|
||||
bgColor={theme.colors.blackTwo}
|
||||
onChange={this.handleChangeFeeType}
|
||||
options={Object.keys(FEES).map(cur => ({
|
||||
label: cur.toLowerCase(),
|
||||
value: String(FEES[cur]),
|
||||
}))}
|
||||
/>
|
||||
</ColumnComponent>
|
||||
</RowComponent>
|
||||
</FeeWrapper>
|
||||
</animated.div>
|
||||
))}
|
||||
</Transition>
|
||||
</RevealsMain>
|
||||
{feeType === FEES.CUSTOM && (
|
||||
<TextComponent value='Custom fees may compromise your privacy since fees are transparent' />
|
||||
)}
|
||||
|
@ -537,24 +578,34 @@ export class SendView extends PureComponent<Props, State> {
|
|||
<ConfirmDialogComponent
|
||||
title='Please Confirm Transaction Details'
|
||||
onConfirm={this.handleSubmit}
|
||||
showButtons={!isSending && !error && !operationId}
|
||||
onClose={this.reset}
|
||||
renderTrigger={toggle => (
|
||||
<FormButton
|
||||
onClick={() => this.showModal(toggle)}
|
||||
id='send-submit-button'
|
||||
label='Send'
|
||||
variant='secondary'
|
||||
focused
|
||||
onClick={() => this.showModal(toggle)}
|
||||
isFluid
|
||||
disabled={!from || !amount || !to || !fee}
|
||||
/>
|
||||
)}
|
||||
showButtons={!isSending && !error && !operationId}
|
||||
onClose={this.reset}
|
||||
>
|
||||
{toggle => (
|
||||
<ModalContent>
|
||||
{this.renderModalContent({ valueSent, valueSentInUsd, toggle })}
|
||||
<ModalContent id='send-confirm-transaction-modal'>
|
||||
{this.renderModalContent({
|
||||
valueSent,
|
||||
valueSentInUsd,
|
||||
toggle,
|
||||
})}
|
||||
</ModalContent>
|
||||
)}
|
||||
</ConfirmDialogComponent>
|
||||
<FormButton label='Cancel' variant='secondary' />
|
||||
<FormButton
|
||||
label='Cancel'
|
||||
variant='secondary'
|
||||
/>
|
||||
</SendWrapper>
|
||||
</RowComponent>
|
||||
);
|
||||
|
|
|
@ -53,7 +53,7 @@ const createWindow = () => {
|
|||
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1000,
|
||||
height: 600,
|
||||
height: 660,
|
||||
transparent: false,
|
||||
frame: true,
|
||||
resizable: true,
|
||||
|
@ -83,6 +83,12 @@ const createWindow = () => {
|
|||
/* eslint-disable-next-line consistent-return */
|
||||
app.on('ready', async () => {
|
||||
createWindow();
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
zcashLog('Not running daemon, please run the mock API');
|
||||
return;
|
||||
}
|
||||
|
||||
const [err, proc] = await eres(runDaemon());
|
||||
|
||||
if (err || !proc) return zcashLog(err);
|
||||
|
|
12
package.json
12
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "zec-react-wallet",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"description": "Zcash Reference Wallet",
|
||||
"main": "config/main.js",
|
||||
"license": "MIT",
|
||||
|
@ -21,8 +21,10 @@
|
|||
"docz:dev": "docz dev",
|
||||
"docz:build": "docz build",
|
||||
"docz:deploy": "yarn docz:build && cd ./.docz/dist && now && now alias zec-docz.now.sh",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch"
|
||||
"test": "jest --runInBand",
|
||||
"test:watch": "jest --watch",
|
||||
"e2e:serve": "node -r @babel/register ./__tests__/setup/mockAPI.js",
|
||||
"e2e:run": "yarn test e2e"
|
||||
},
|
||||
"author": {
|
||||
"name": "André Neves",
|
||||
|
@ -43,12 +45,13 @@
|
|||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"concurrently": "^4.1.0",
|
||||
"create-test-server": "georgelima/create-test-server",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^1.0.1",
|
||||
"docz": "0.13.4",
|
||||
"docz-plugin-css": "^0.11.0",
|
||||
"docz-theme-default": "0.13.4",
|
||||
"electron": "^4.0.0",
|
||||
"electron": "^4.0.1",
|
||||
"electron-builder": "^20.38.4",
|
||||
"electron-compilers": "^5.9.0",
|
||||
"electron-icon-maker": "^0.0.4",
|
||||
|
@ -69,6 +72,7 @@
|
|||
"html-webpack-plugin": "^3.1.0",
|
||||
"jest": "^23.6.0",
|
||||
"jest-dom": "^2.1.1",
|
||||
"jest-extended": "^0.11.0",
|
||||
"node-sass": "^4.8.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
|
|
|
@ -20,7 +20,6 @@ const client = got.extend({
|
|||
auth: `${RPC.user}:${RPC.password}`,
|
||||
});
|
||||
|
||||
// $FlowFixMe
|
||||
const api: APIMethods = METHODS.reduce(
|
||||
(obj, method) => ({
|
||||
...obj,
|
||||
|
|
96
yarn.lock
96
yarn.lock
|
@ -1580,16 +1580,16 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.15.tgz#20e85651b62fd86656e57c9c9bc771ab1570bc59"
|
||||
integrity sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==
|
||||
|
||||
"@types/node@^10.12.18":
|
||||
version "10.12.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
|
||||
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
|
||||
|
||||
"@types/node@^7.0.12":
|
||||
version "7.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.10.2.tgz#a98845168012d7a63a84d50e738829da43bdb0de"
|
||||
integrity sha512-RO4ig5taKmcrU4Rex8ojG1gpwFkjddzug9iPQSDvbewHN9vDpcFewevkaOK+KT+w1LeZnxbgOyfXwV4pxsQ4GQ==
|
||||
|
||||
"@types/node@^8.0.24":
|
||||
version "8.10.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.39.tgz#e7e87ad00364dd7bc485c940926345b8ec1a26ca"
|
||||
integrity sha512-rE7fktr02J8ybFf6eysife+WF+L4sAHWzw09DgdCebEu+qDwMvv4zl6Bc+825ttGZP73kCKxa3dhJOoGJ8+5mA==
|
||||
|
||||
"@types/q@^1.5.1":
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18"
|
||||
|
@ -3246,7 +3246,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
|
|||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
||||
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
|
||||
|
||||
body-parser@1.18.3:
|
||||
body-parser@1.18.3, body-parser@^1.18.2:
|
||||
version "1.18.3"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
|
||||
integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
|
||||
|
@ -4724,6 +4724,14 @@ crc@^3.4.4:
|
|||
dependencies:
|
||||
buffer "^5.1.0"
|
||||
|
||||
create-cert@^1.0.2:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/create-cert/-/create-cert-1.0.6.tgz#7ed01fff7f9f0cea500aba5eff119af4c8de84f6"
|
||||
integrity sha1-ftAf/3+fDOpQCrpe/xGa9MjehPY=
|
||||
dependencies:
|
||||
pem "^1.9.7"
|
||||
pify "^3.0.0"
|
||||
|
||||
create-ecdh@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
|
||||
|
@ -4770,6 +4778,15 @@ create-react-context@^0.2.2, create-react-context@^0.2.3:
|
|||
fbjs "^0.8.0"
|
||||
gud "^1.0.0"
|
||||
|
||||
create-test-server@georgelima/create-test-server:
|
||||
version "2.4.0"
|
||||
resolved "https://codeload.github.com/georgelima/create-test-server/tar.gz/0f4133ca2d53f7084f34e77ca72536890614c96a"
|
||||
dependencies:
|
||||
body-parser "^1.18.2"
|
||||
create-cert "^1.0.2"
|
||||
express "^4.15.3"
|
||||
pify "^3.0.0"
|
||||
|
||||
cross-env@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.0.tgz#6ecd4c015d5773e614039ee529076669b9d126f2"
|
||||
|
@ -6284,12 +6301,12 @@ electron-updater@^4.0.4:
|
|||
semver "^5.6.0"
|
||||
source-map-support "^0.5.9"
|
||||
|
||||
electron@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-4.0.0.tgz#6ccb40cc8bf2d49954dcea73b97ae7ad12ee04b3"
|
||||
integrity sha512-3XPG/3IXlvnT1oe1K6zEushoD0SKbP8xwdrL10EWGe6k2iOV4hSHqJ8vWnR8yZ7VbSXmBRfomEFDNAo/q/cwKw==
|
||||
electron@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-4.0.1.tgz#c41eaee9e081c2e5e4a4a4a761b7577a77d2eb18"
|
||||
integrity sha512-kBWDLn1Vq8Tm6+/HpQc8gkjX7wJyQI8v/lf2kAirfi0Q4cXh6vBjozFvV1U/9gGCbyKnIDM+m8/wpyJIjg4w7g==
|
||||
dependencies:
|
||||
"@types/node" "^8.0.24"
|
||||
"@types/node" "^10.12.18"
|
||||
electron-download "^4.1.0"
|
||||
extract-zip "^1.0.3"
|
||||
|
||||
|
@ -6486,6 +6503,11 @@ es6-promisify@^5.0.0:
|
|||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
es6-promisify@^6.0.0:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6"
|
||||
integrity sha512-J3ZkwbEnnO+fGAKrjVpeUAnZshAdfZvbhQpqfIH9kSAspReRC4nJnu8ewm55b4y9ElyeuhCTzJD0XiH8Tsbhlw==
|
||||
|
||||
es6-symbol@^3.1.1, es6-symbol@~3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
|
||||
|
@ -6906,7 +6928,7 @@ expect@^23.6.0:
|
|||
jest-message-util "^23.4.0"
|
||||
jest-regex-util "^23.3.0"
|
||||
|
||||
express@^4.16.2, express@^4.16.3:
|
||||
express@^4.15.3, express@^4.16.2, express@^4.16.3:
|
||||
version "4.16.4"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
|
||||
integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
|
||||
|
@ -9555,7 +9577,16 @@ jest-environment-node@^23.4.0:
|
|||
jest-mock "^23.2.0"
|
||||
jest-util "^23.4.0"
|
||||
|
||||
jest-get-type@^22.1.0:
|
||||
jest-extended@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-extended/-/jest-extended-0.11.0.tgz#621a0f07c828166657416e590607eab8c3c3eeda"
|
||||
integrity sha512-7VJQDyObjKRqaiaRvzSbWchwTvk7mQYPaEzPcK2Nwrna6ZSPe/AB9aPDjgH2oT0QONtF6FvM3GIvDdJhttJeaA==
|
||||
dependencies:
|
||||
expect "^23.6.0"
|
||||
jest-get-type "^22.4.3"
|
||||
jest-matcher-utils "^22.0.0"
|
||||
|
||||
jest-get-type@^22.1.0, jest-get-type@^22.4.3:
|
||||
version "22.4.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4"
|
||||
integrity sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==
|
||||
|
@ -9599,6 +9630,15 @@ jest-leak-detector@^23.6.0:
|
|||
dependencies:
|
||||
pretty-format "^23.6.0"
|
||||
|
||||
jest-matcher-utils@^22.0.0:
|
||||
version "22.4.3"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz#4632fe428ebc73ebc194d3c7b65d37b161f710ff"
|
||||
integrity sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA==
|
||||
dependencies:
|
||||
chalk "^2.0.1"
|
||||
jest-get-type "^22.4.3"
|
||||
pretty-format "^22.4.3"
|
||||
|
||||
jest-matcher-utils@^23.6.0:
|
||||
version "23.6.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz#726bcea0c5294261a7417afb6da3186b4b8cac80"
|
||||
|
@ -10739,7 +10779,7 @@ md5.js@^1.3.4:
|
|||
inherits "^2.0.1"
|
||||
safe-buffer "^5.1.2"
|
||||
|
||||
md5@^2.1.0:
|
||||
md5@^2.1.0, md5@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
|
||||
integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
|
||||
|
@ -11904,7 +11944,7 @@ os-shim@^0.1.2:
|
|||
resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
|
||||
integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=
|
||||
|
||||
os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
|
||||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||
|
@ -12279,6 +12319,16 @@ pbkdf2@^3.0.3:
|
|||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
pem@^1.9.7:
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/pem/-/pem-1.13.2.tgz#7b68acbb590fdc13772bca487983cb84cd7b443e"
|
||||
integrity sha512-MPJWuEb/r6AG+GpZi2JnfNtGAZDeL/8+ERKwXEWRuST5i+4lq/Uy36B352OWIUSPQGH+HR1HEDcIDi+8cKxXNg==
|
||||
dependencies:
|
||||
es6-promisify "^6.0.0"
|
||||
md5 "^2.2.1"
|
||||
os-tmpdir "^1.0.1"
|
||||
which "^1.3.1"
|
||||
|
||||
pend@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
|
@ -13075,6 +13125,14 @@ pretty-error@^2.0.2:
|
|||
renderkid "^2.0.1"
|
||||
utila "~0.4"
|
||||
|
||||
pretty-format@^22.4.3:
|
||||
version "22.4.3"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f"
|
||||
integrity sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==
|
||||
dependencies:
|
||||
ansi-regex "^3.0.0"
|
||||
ansi-styles "^3.2.0"
|
||||
|
||||
pretty-format@^23.6.0:
|
||||
version "23.6.0"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760"
|
||||
|
@ -17013,9 +17071,9 @@ web-namespaces@^1.1.2:
|
|||
integrity sha512-II+n2ms4mPxK+RnIxRPOw3zwF2jRscdJIUE9BfkKHm4FYEg9+biIoTMnaZF5MpemE3T+VhMLrhbyD4ilkPCSbg==
|
||||
|
||||
webdriverio@^4.13.0:
|
||||
version "4.14.0"
|
||||
resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.14.0.tgz#f8a48d03abc70c87d7d17b59bd3f45a322927e0c"
|
||||
integrity sha512-642Iqp9en2hvuVINkTfQvWoQCaLb6zJyLHgQFUFLx7s+8l8GnrHzMjkv5DbecZHwnBkhybpphbTW7k0B2ARH5A==
|
||||
version "4.14.2"
|
||||
resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.14.2.tgz#335038214272675b409bdfc8276a9345a88bc83e"
|
||||
integrity sha512-eZXiu0ST6KBi6Pz8tDArw5bNgGu6aohrkA8GFADk1HzClSyf+3arcS16Q7n7SaUPz/ZemsLIw5nQO8eb6v8L3g==
|
||||
dependencies:
|
||||
archiver "~2.1.0"
|
||||
babel-runtime "^6.26.0"
|
||||
|
@ -17420,7 +17478,7 @@ which-module@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
|
||||
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
|
||||
|
||||
which@1, which@^1.1.1, which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0:
|
||||
which@1, which@^1.1.1, which@^1.2.10, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
|
||||
|
|
Loading…
Reference in New Issue