Browse Source

test(terminal): add and update unit tests for the Terminal

feat/auto-update
jamaljsr 5 years ago
parent
commit
d6b8e3306b
  1. 1
      src/components/common/index.ts
  2. 9
      src/components/designer/bitcoind/BitcoindDetails.tsx
  3. 2
      src/components/designer/lnd/ActionsTab.tsx
  4. 45
      src/components/terminal/OpenTerminalButton.spec.tsx
  5. 7
      src/components/terminal/OpenTerminalButton.tsx
  6. 1
      src/components/terminal/index.ts
  7. 35
      src/lib/docker/composeFile.spec.ts
  8. 18
      src/lib/docker/dockerService.spec.ts
  9. 15
      src/lib/docker/nodeTemplates.spec.ts
  10. 2
      src/store/index.ts
  11. 6
      src/store/models/app.ts
  12. 2
      src/types/index.ts
  13. 1
      src/utils/tests.tsx

1
src/components/common/index.ts

@ -4,4 +4,3 @@ export { default as Loader } from './Loader';
export { default as NavMenu } from './NavMenu';
export { default as StatusBadge } from './StatusBadge';
export { default as StatusTag } from './StatusTag';
export { default as OpenTerminalButton } from './OpenTerminalButton';

9
src/components/designer/bitcoind/BitcoindDetails.tsx

@ -6,14 +6,9 @@ import { BitcoinNode, Status } from 'shared/types';
import { useStoreActions, useStoreState } from 'store';
import { ellipseInner } from 'utils/strings';
import { toSats } from 'utils/units';
import {
CopyIcon,
DetailsList,
Loader,
OpenTerminalButton,
StatusBadge,
} from 'components/common';
import { CopyIcon, DetailsList, Loader, StatusBadge } from 'components/common';
import { DetailValues } from 'components/common/DetailsList';
import { OpenTerminalButton } from 'components/terminal';
import SidebarCard from '../SidebarCard';
import MineBlocksInput from './MineBlocksInput';

2
src/components/designer/lnd/ActionsTab.tsx

@ -1,7 +1,7 @@
import React from 'react';
import { usePrefixedTranslation } from 'hooks';
import { LndNode, Status } from 'shared/types';
import { OpenTerminalButton } from 'components/common';
import { OpenTerminalButton } from 'components/terminal';
import { Deposit, OpenChannelButtons } from './actions';
interface Props {

45
src/components/terminal/OpenTerminalButton.spec.tsx

@ -0,0 +1,45 @@
import React from 'react';
import { fireEvent, wait } from '@testing-library/dom';
import { ipcChannels } from 'shared';
import { BitcoinNode, LndNode } from 'shared/types';
import { Network } from 'types';
import { getNetwork, injections, renderWithProviders } from 'utils/tests';
import OpenTerminalButton from './OpenTerminalButton';
describe('OpenTerminalButton', () => {
const renderComponent = (nodeSelector: (n: Network) => LndNode | BitcoinNode) => {
const network = getNetwork(1, 'test network');
return renderWithProviders(<OpenTerminalButton node={nodeSelector(network)} />);
};
it('should render label', () => {
const { getByText } = renderComponent(n => n.nodes.bitcoin[0]);
expect(getByText('Terminal')).toBeInTheDocument();
});
it('should render button', () => {
const { getByText } = renderComponent(n => n.nodes.bitcoin[0]);
expect(getByText('Launch')).toBeInTheDocument();
});
it('should render bitcoind help text', () => {
const { getByText } = renderComponent(n => n.nodes.bitcoin[0]);
const help = getByText("Run 'bitcoin-cli' commands directly on the node");
expect(help).toBeInTheDocument();
});
it('should render lnd help text', () => {
const { getByText } = renderComponent(n => n.nodes.lightning[0]);
const help = getByText("Run 'lncli' commands directly on the node");
expect(help).toBeInTheDocument();
});
it('should send an ipc message when the button is clicked', async () => {
const ipcMock = injections.ipc as jest.Mock;
ipcMock.mockResolvedValue(true);
const { getByText } = renderComponent(n => n.nodes.bitcoin[0]);
await wait(() => fireEvent.click(getByText('Launch')));
const url = '/terminal/bitcoind/polar-n1-bitcoind-1';
expect(ipcMock).toBeCalledWith(ipcChannels.openWindow, { url });
});
});

7
src/components/common/OpenTerminalButton.tsx → src/components/terminal/OpenTerminalButton.tsx

@ -1,4 +1,5 @@
import React from 'react';
import { useAsyncCallback } from 'react-async-hook';
import { Button, Form } from 'antd';
import { usePrefixedTranslation } from 'hooks';
import { BitcoinNode, LndNode } from 'shared/types';
@ -13,6 +14,7 @@ interface Props {
const OpenTerminalButton: React.FC<Props> = ({ node }) => {
const { l } = usePrefixedTranslation('cmps.common.OpenTerminalButton');
const { openWindow } = useStoreActions(s => s.app);
const openAsync = useAsyncCallback(openWindow);
let cmd = '';
switch (node.implementation) {
@ -29,7 +31,10 @@ const OpenTerminalButton: React.FC<Props> = ({ node }) => {
type="primary"
icon="code"
block
onClick={() => openWindow(TERMINAL(node.implementation, getContainerName(node)))}
loading={openAsync.loading}
onClick={() =>
openAsync.execute(TERMINAL(node.implementation, getContainerName(node)))
}
>
{l('btn')}
</Button>

1
src/components/terminal/index.ts

@ -1 +1,2 @@
export { default as DockerTerminal } from './DockerTerminal';
export { default as OpenTerminalButton } from './OpenTerminalButton';

35
src/lib/docker/composeFile.spec.ts

@ -1,8 +1,11 @@
import { LndVersion } from 'shared/types';
import { getNetwork } from 'utils/tests';
import ComposeFile from './composeFile';
describe('ComposeFile', () => {
let composeFile = new ComposeFile();
const network = getNetwork();
const btcNode = network.nodes.bitcoin[0];
const lndNode = network.nodes.lightning[0];
beforeEach(() => {
composeFile = new ComposeFile();
@ -17,35 +20,35 @@ describe('ComposeFile', () => {
});
it('should add multiple services', () => {
composeFile.addBitcoind('bitcoind1', '0.18.1', 18443);
composeFile.addLnd('lnd1', LndVersion.latest, 'bitcoind1', 8080, 10009);
composeFile.addBitcoind(btcNode);
composeFile.addLnd(lndNode, btcNode);
expect(Object.keys(composeFile.content.services).length).toEqual(2);
});
it('should add a bitcoind config', () => {
composeFile.addBitcoind('bitcoind1', '0.18.1', 18443);
expect(composeFile.content.services.bitcoind1).not.toBeUndefined();
composeFile.addBitcoind(btcNode);
expect(composeFile.content.services['bitcoind-1']).not.toBeUndefined();
});
it('should create the correct bitcoind docker compose values', () => {
composeFile.addBitcoind('bitcoind1', '0.18.1', 18443);
const service = composeFile.content.services.bitcoind1;
composeFile.addBitcoind(btcNode);
const service = composeFile.content.services['bitcoind-1'];
expect(service.image).toContain('bitcoind');
expect(service.container_name).toEqual('bitcoind1');
expect(service.volumes[0]).toContain('bitcoind1');
expect(service.container_name).toEqual('polar-n1-bitcoind-1');
expect(service.volumes[0]).toContain('/bitcoind-1:');
});
it('should add an lnd config', () => {
composeFile.addLnd('lnd1', LndVersion.latest, 'bitcoind1', 8080, 10009);
expect(composeFile.content.services.lnd1).not.toBeUndefined();
composeFile.addLnd(lndNode, btcNode);
expect(composeFile.content.services['lnd-1']).not.toBeUndefined();
});
it('should create the correct lnd docker compose values', () => {
composeFile.addLnd('lnd1', LndVersion.latest, 'bitcoind1', 8080, 10009);
const service = composeFile.content.services.lnd1;
composeFile.addLnd(lndNode, btcNode);
const service = composeFile.content.services['lnd-1'];
expect(service.image).toContain('lnd');
expect(service.container_name).toEqual('lnd1');
expect(service.command).toContain('bitcoind1');
expect(service.volumes[0]).toContain('lnd1');
expect(service.container_name).toEqual('polar-n1-lnd-1');
expect(service.command).toContain('bitcoind-1');
expect(service.volumes[0]).toContain('/lnd-1:');
});
});

18
src/lib/docker/dockerService.spec.ts

@ -6,6 +6,7 @@ import { dockerService } from 'lib/docker';
import { Network } from 'types';
import { DOCKER_REPO } from 'utils/constants';
import * as files from 'utils/files';
import { createNetwork } from 'utils/network';
import { getNetwork } from 'utils/tests';
jest.mock('dockerode');
@ -134,6 +135,23 @@ describe('DockerService', () => {
);
});
it('should save the lnd node with the first bitcoin node as backend', () => {
const net = createNetwork({
id: 1,
name: 'my network',
lndNodes: 1,
bitcoindNodes: 1,
});
net.nodes.lightning[0].backendName = 'invalid';
dockerService.saveComposeFile(net);
expect(filesMock.write).toBeCalledWith(
expect.stringContaining('docker-compose.yml'),
expect.stringContaining(
`container_name: polar-n1-${network.nodes.lightning[0].name}`,
),
);
});
it('should not save unknown lightning implementation', () => {
network.nodes.lightning[0].implementation = 'c-lightning';
dockerService.saveComposeFile(network);

15
src/lib/docker/nodeTemplates.spec.ts

@ -3,16 +3,23 @@ import { bitcoind, lnd } from './nodeTemplates';
describe('nodeTemplates', () => {
it('should create a valid bitcoind config', () => {
const node = bitcoind('mynode', '0.18.1', 18443);
const node = bitcoind('mynode', 'polar-mynode', '0.18.1', 18443);
expect(node.image).toContain('bitcoind');
expect(node.container_name).toEqual('mynode');
expect(node.container_name).toEqual('polar-mynode');
expect(node.volumes[0]).toContain('mynode');
});
it('should create a valid lnd config', () => {
const node = lnd('mynode', LndVersion.latest, 'btcnode1', 8080, 10009);
const node = lnd(
'mynode',
'polar-mynode',
LndVersion.latest,
'btcnode1',
8080,
10009,
);
expect(node.image).toContain('lnd');
expect(node.container_name).toEqual('mynode');
expect(node.container_name).toEqual('polar-mynode');
expect(node.command).toContain('btcnode1');
expect(node.volumes[0]).toContain('mynode');
});

2
src/store/index.ts

@ -4,6 +4,7 @@ import { createHashHistory, History } from 'history';
import { createLogger } from 'redux-logger';
import { bitcoindService } from 'lib/bitcoin';
import { dockerService } from 'lib/docker';
import { createIpcSender } from 'lib/ipc/ipcService';
import { lndService } from 'lib/lnd';
import { createModel, RootModel } from 'store/models';
import { StoreInjections } from 'types';
@ -48,6 +49,7 @@ export const createReduxStore = (options?: {
// using injections allows for more easily mocking of dependencies in store actions
// see https://easy-peasy.now.sh/docs/testing/testing-components.html#mocking-calls-to-services
const injections: StoreInjections = {
ipc: createIpcSender('AppModel', 'app'),
dockerService,
bitcoindService,
lndService,

6
src/store/models/app.ts

@ -4,7 +4,6 @@ import { ArgsProps } from 'antd/lib/notification';
import { push } from 'connected-react-router';
import { Action, action, Thunk, thunk } from 'easy-peasy';
import { ipcChannels } from 'shared';
import { createIpcSender } from 'lib/ipc/ipcService';
import { DockerVersions, StoreInjections } from 'types';
import { RootModel } from './';
@ -83,9 +82,8 @@ const appModel: AppModel = {
openInBrowser: action((state, url) => {
shell.openExternal(url);
}),
openWindow: thunk(async (actions, url) => {
const ipc = createIpcSender('AppModel', 'app');
await ipc(ipcChannels.openWindow, { url });
openWindow: thunk(async (actions, url, { injections }) => {
await injections.ipc(ipcChannels.openWindow, { url });
}),
};

2
src/types/index.ts

@ -2,6 +2,7 @@ import { IChart } from '@mrblenny/react-flow-chart';
import * as LND from '@radar/lnrpc';
import { ChainInfo, WalletInfo } from 'bitcoin-core';
import { BitcoinNode, LndNode, Status } from 'shared/types';
import { IpcSender } from 'lib/ipc/ipcService';
export interface LocaleConfig {
fallbackLng: string;
@ -57,6 +58,7 @@ export interface LndLibrary {
}
export interface StoreInjections {
ipc: IpcSender;
dockerService: DockerLibrary;
bitcoindService: BitcoindLibrary;
lndService: LndLibrary;

1
src/utils/tests.tsx

@ -27,6 +27,7 @@ export const mockProperty = <T extends {}, K extends keyof T>(
};
// injections allow you to mock the dependencies of redux store actions
export const injections: StoreInjections = {
ipc: jest.fn(),
dockerService: {
getVersions: jest.fn(),
getImages: jest.fn(),

Loading…
Cancel
Save