Browse Source

test(nework): add and update unit tests for displaying node errors

feat/auto-update
jamaljsr 5 years ago
parent
commit
fba390c01c
  1. 17
      src/components/designer/bitcoind/BitcoindDetails.spec.tsx
  2. 17
      src/components/designer/lnd/LndDetails.spec.tsx
  3. 4
      src/components/network/NetworkView.spec.tsx
  4. 14
      src/lib/bitcoin/bitcoindService.spec.ts
  5. 16
      src/lib/lnd/lndService.spec.ts
  6. 6
      src/store/models/designer.spec.ts
  7. 12
      src/store/models/network.spec.ts
  8. 2
      src/utils/async.spec.ts
  9. 6
      src/utils/async.ts
  10. 7
      src/utils/files.spec.ts
  11. 10
      src/utils/files.ts

17
src/components/designer/bitcoind/BitcoindDetails.spec.tsx

@ -7,6 +7,9 @@ import BitcoindDetails from './BitcoindDetails';
describe('BitcoindDetails', () => {
const renderComponent = (status?: Status) => {
const network = getNetwork(1, 'test network', status);
if (status === Status.Error) {
network.nodes.bitcoin.forEach(n => (n.errorMsg = 'test-error'));
}
const initialState = {
network: {
networks: [network],
@ -118,4 +121,18 @@ describe('BitcoindDetails', () => {
expect(await findByText('1,000,000,000 sats')).toBeInTheDocument();
});
});
describe('with node Error', () => {
it('should display correct Status', async () => {
const { findByText, node } = renderComponent(Status.Error);
expect(await findByText('Status')).toBeInTheDocument();
expect(await findByText(Status[node.status])).toBeInTheDocument();
});
it('should display correct Status', async () => {
const { findByText } = renderComponent(Status.Error);
expect(await findByText('Unable to connect to bitcoin node')).toBeInTheDocument();
expect(await findByText('test-error')).toBeInTheDocument();
});
});
});

17
src/components/designer/lnd/LndDetails.spec.tsx

@ -16,6 +16,9 @@ jest.mock('utils/files');
describe('LndDetails', () => {
const renderComponent = (status?: Status) => {
const network = getNetwork(1, 'test network', status);
if (status === Status.Error) {
network.nodes.lightning.forEach(n => (n.errorMsg = 'test-error'));
}
const initialState = {
network: {
networks: [network],
@ -291,4 +294,18 @@ describe('LndDetails', () => {
});
});
});
describe('with node Error', () => {
it('should display correct Status', async () => {
const { findByText, node } = renderComponent(Status.Error);
expect(await findByText('Status')).toBeInTheDocument();
expect(await findByText(Status[node.status])).toBeInTheDocument();
});
it('should display correct Status', async () => {
const { findByText } = renderComponent(Status.Error);
expect(await findByText('Unable to connect to LND node')).toBeInTheDocument();
expect(await findByText('test-error')).toBeInTheDocument();
});
});
});

4
src/components/network/NetworkView.spec.tsx

@ -46,8 +46,8 @@ describe('NetworkView Component', () => {
};
beforeEach(() => {
lndServiceMock.waitUntilOnline.mockResolvedValue(true);
bitcoindServiceMock.waitUntilOnline.mockResolvedValue(true);
lndServiceMock.waitUntilOnline.mockResolvedValue();
bitcoindServiceMock.waitUntilOnline.mockResolvedValue();
});
it('should not render if the network is not found', () => {

14
src/lib/bitcoin/bitcoindService.spec.ts

@ -67,16 +67,16 @@ describe('BitcoindService', () => {
});
describe('waitUntilOnline', () => {
it('should return true when successful', async () => {
const result = await bitcoindService.waitUntilOnline();
expect(result).toBe(true);
it('should wait successfully', async () => {
await expect(bitcoindService.waitUntilOnline()).resolves.not.toThrow();
expect(getInst().getBlockchainInfo).toBeCalledTimes(1);
});
it('should return false on failure', async () => {
mockProto.getBlockchainInfo = jest.fn().mockRejectedValue(new Error());
const result = await bitcoindService.waitUntilOnline(18443, 0.5, 1);
expect(result).toBe(false);
it('should throw error if waiting fails', async () => {
mockProto.getBlockchainInfo = jest.fn().mockRejectedValue(new Error('test-error'));
await expect(bitcoindService.waitUntilOnline(18443, 0.5, 1)).rejects.toThrow(
'test-error',
);
expect(getInst().getBlockchainInfo).toBeCalledTimes(1);
});
});

16
src/lib/lnd/lndService.spec.ts

@ -87,18 +87,18 @@ describe('LndService', () => {
});
describe('waitUntilOnline', () => {
it('should return true when successful', async () => {
it('should wait successfully', async () => {
lndProxyClient.getInfo = jest.fn().mockResolvedValue({});
const result = await lndService.waitUntilOnline(node);
expect(result).toBe(true);
await expect(lndService.waitUntilOnline(node)).resolves.not.toThrow();
expect(lndProxyClient.getInfo).toBeCalledTimes(1);
});
it('should return false on failure', async () => {
lndProxyClient.getInfo = jest.fn().mockRejectedValue(new Error());
const result = await lndService.waitUntilOnline(node, 0.5, 1);
expect(result).toBe(false);
expect(lndProxyClient.getInfo).toBeCalledTimes(5);
it('should throw error if waiting fails', async () => {
lndProxyClient.getInfo = jest.fn().mockRejectedValue(new Error('test-error'));
await expect(lndService.waitUntilOnline(node, 0.5, 1)).rejects.toThrow(
'test-error',
);
expect(lndProxyClient.getInfo).toBeCalledTimes(4);
});
});
});

6
src/store/models/designer.spec.ts

@ -1,6 +1,7 @@
import { wait } from '@testing-library/dom';
import { notification } from 'antd';
import { createStore } from 'easy-peasy';
import { Status } from 'shared/types';
import { BitcoindLibrary, DockerLibrary, LndLibrary } from 'types';
import { LOADING_NODE_ID } from 'utils/constants';
import { injections } from 'utils/tests';
@ -9,7 +10,6 @@ import bitcoindModel from './bitcoind';
import designerModel from './designer';
import modalsModel from './modals';
import networkModel from './network';
import { Status } from 'shared/types';
jest.mock('antd', () => ({
...jest.requireActual('antd'),
@ -288,8 +288,8 @@ describe('Designer model', () => {
});
it('should start the node if the network is running', async () => {
mockBitcoindService.waitUntilOnline.mockResolvedValue(true);
mockLndService.waitUntilOnline.mockResolvedValue(true);
mockBitcoindService.waitUntilOnline.mockResolvedValue();
mockLndService.waitUntilOnline.mockResolvedValue();
mockDockerService.start.mockReset();
const { setStatus } = store.getActions().network;
setStatus({ id: firstNetwork().id, status: Status.Started });

12
src/store/models/network.spec.ts

@ -43,9 +43,9 @@ describe('Network model', () => {
// reset the store before each test run
store = createStore(rootModel, { injections });
// always return true immediately
filesMock.waitForFile.mockResolvedValue(true);
lndServiceMock.waitUntilOnline.mockResolvedValue(true);
bitcoindServiceMock.waitUntilOnline.mockResolvedValue(true);
filesMock.waitForFile.mockResolvedValue();
lndServiceMock.waitUntilOnline.mockResolvedValue();
bitcoindServiceMock.waitUntilOnline.mockResolvedValue();
});
it('should have a valid initial state', () => {
@ -210,21 +210,23 @@ describe('Network model', () => {
});
it('should set LND node status to error if the node startup fails', async () => {
lndServiceMock.waitUntilOnline.mockResolvedValue(false);
lndServiceMock.waitUntilOnline.mockRejectedValue(new Error('test-error'));
const { start } = store.getActions().network;
const network = firstNetwork();
await start(network.id);
const { lightning } = firstNetwork().nodes;
lightning.forEach(node => expect(node.status).toBe(Status.Error));
lightning.forEach(node => expect(node.errorMsg).toBe('test-error'));
});
it('should set bitcoind node status to error if the node startup fails', async () => {
bitcoindServiceMock.waitUntilOnline.mockResolvedValue(false);
bitcoindServiceMock.waitUntilOnline.mockRejectedValue(new Error('test-error'));
const { start } = store.getActions().network;
const network = firstNetwork();
await start(network.id);
const { bitcoin } = firstNetwork().nodes;
bitcoin.forEach(node => expect(node.status).toBe(Status.Error));
bitcoin.forEach(node => expect(node.errorMsg).toBe('test-error'));
});
it('should not save compose file and networks if all ports are available', async () => {

2
src/utils/async.spec.ts

@ -26,7 +26,7 @@ describe('Async Util', () => {
it('should resolve once the condition becomes true', async () => {
// return false initially
const condition = jest.fn().mockResolvedValue(false);
const condition = jest.fn().mockRejectedValue(new Error('test-error'));
// chain the spy onto the promise so we can inspect if its been called
const spy = jest.fn(x => x);
const promise = waitFor(condition, 10, 100).then(spy);

6
src/utils/async.ts

@ -17,9 +17,9 @@ export const waitFor = async (
timeout = 5000,
): Promise<any> => {
try {
await conditionFunc();
const result = await conditionFunc();
// if the condition succeeds, then return immediately
return Promise.resolve();
return Promise.resolve(result);
} catch {
// do nothing if the condition fails the first time
}
@ -36,7 +36,7 @@ export const waitFor = async (
return resolve(result);
} catch (error) {
// only reject when the timeout expires, otherwise ignore the error
if (timesToCheck < 0) {
if (timesToCheck <= 0) {
clearInterval(timer);
return reject(error);
}

7
src/utils/files.spec.ts

@ -109,13 +109,12 @@ describe('Files util', () => {
describe('wait for files', () => {
it('should resolve immediately if the file already exists', async () => {
mockFs.pathExists.mockResolvedValue(true as never);
const result = await waitForFile('test.txt');
expect(result).toBe(true);
await expect(waitForFile('test.txt')).resolves.not.toThrow();
});
it('should timeout if the file never exists', async () => {
mockFs.pathExists.mockResolvedValue(false as never);
await expect(waitForFile('test.txt', 10, 30)).resolves.toBe(false);
await expect(waitForFile('test.txt', 10, 30)).rejects.toThrow();
});
it('should resolve once the file exists', async () => {
@ -129,7 +128,7 @@ describe('Files util', () => {
// make pathExists return true
mockFs.pathExists.mockResolvedValue(true as never);
// wait for the promise to be resolved
await expect(promise).resolves.toBe(true);
await expect(promise).resolves.not.toThrow();
// confirm the spy was called
expect(spy).toBeCalled();
});

10
src/utils/files.ts

@ -45,5 +45,13 @@ export const waitForFile = async (
timeout = 5000,
): Promise<void> => {
const path = abs(filePath);
return waitFor(async () => await exists(path), interval, timeout);
return waitFor(
async () => {
if (!(await exists(path))) {
throw new Error(`File does not exist: ${path}`);
}
},
interval,
timeout,
);
};

Loading…
Cancel
Save