mirror of https://github.com/lukechilds/polar.git
jamaljsr
5 years ago
9 changed files with 545 additions and 12 deletions
@ -0,0 +1,120 @@ |
|||
import React from 'react'; |
|||
import { fireEvent, wait, waitForElementToBeRemoved } from '@testing-library/react'; |
|||
import { CustomImage } from 'types'; |
|||
import { DOCKER_REPO, dockerConfigs } from 'utils/constants'; |
|||
import { injections, renderWithProviders, testCustomImages } from 'utils/tests'; |
|||
import CustomImageModal from './CustomImageModal'; |
|||
|
|||
const dockerServiceMock = injections.dockerService as jest.Mocked< |
|||
typeof injections.dockerService |
|||
>; |
|||
|
|||
describe('CustomImageModal Component', () => { |
|||
const onClose = jest.fn(); |
|||
const newImage: CustomImage = { |
|||
id: '', |
|||
name: '', |
|||
implementation: 'LND', |
|||
dockerImage: '', |
|||
command: dockerConfigs.LND.command, |
|||
}; |
|||
|
|||
const renderComponent = async (customImage?: CustomImage) => { |
|||
const nodeImages = { |
|||
custom: testCustomImages, |
|||
}; |
|||
const initialState = { |
|||
app: { |
|||
settings: { |
|||
nodeImages, |
|||
}, |
|||
}, |
|||
}; |
|||
|
|||
const image = customImage || nodeImages.custom[0]; |
|||
const result = renderWithProviders( |
|||
<CustomImageModal image={image} onClose={onClose} />, |
|||
{ initialState }, |
|||
); |
|||
// wait for the loader to go away
|
|||
await waitForElementToBeRemoved(() => result.getByLabelText('loading')); |
|||
return { |
|||
...result, |
|||
image, |
|||
}; |
|||
}; |
|||
|
|||
beforeEach(() => { |
|||
dockerServiceMock.getImages.mockResolvedValue(['aaa', 'bbb', `${DOCKER_REPO}/lnd`]); |
|||
}); |
|||
|
|||
it('should display title and notice', async () => { |
|||
const { getByText } = await renderComponent(); |
|||
expect(getByText('Custom Node Details')).toBeInTheDocument(); |
|||
expect( |
|||
getByText( |
|||
'Editing this information will not modify any nodes in existing networks', |
|||
), |
|||
).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display form fields', async () => { |
|||
const { getByText } = await renderComponent(); |
|||
expect(getByText('Name')).toBeInTheDocument(); |
|||
expect(getByText('Docker Image')).toBeInTheDocument(); |
|||
expect(getByText('Command')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display the command variables', async () => { |
|||
const { getByText, image } = await renderComponent(); |
|||
expect(getByText('Command Variable Substitutions')).toBeInTheDocument(); |
|||
fireEvent.click(getByText('Command Variable Substitutions')); |
|||
const vars = dockerConfigs[image.implementation].variables; |
|||
vars.forEach(v => { |
|||
expect(getByText(v)).toBeInTheDocument(); |
|||
}); |
|||
}); |
|||
|
|||
it('should have form fields populated', async () => { |
|||
const { getByDisplayValue, image } = await renderComponent(); |
|||
expect(getByDisplayValue(image.dockerImage)).toBeInTheDocument(); |
|||
expect(getByDisplayValue(image.command)).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should update the command field when the implementation is changed', async () => { |
|||
const { getByLabelText, changeSelect } = await renderComponent(newImage); |
|||
const impl = getByLabelText('Command') as HTMLTextAreaElement; |
|||
expect(impl.value).toContain('lnd'); |
|||
changeSelect('Implementation', 'c-lightning'); |
|||
expect(impl.value).toContain('lightningd'); |
|||
}); |
|||
|
|||
it('should display an error notification if fetching docker images fails', async () => { |
|||
dockerServiceMock.getImages.mockRejectedValue(new Error('test-error')); |
|||
const { findByText } = await renderComponent(); |
|||
expect( |
|||
await findByText('Failed to fetch the list of docker images'), |
|||
).toBeInTheDocument(); |
|||
expect(await findByText('test-error')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should save the managed image', async () => { |
|||
const { getByText, getByLabelText, store } = await renderComponent(); |
|||
fireEvent.change(getByLabelText('Command'), { target: { value: 'a' } }); |
|||
fireEvent.click(getByText('Save')); |
|||
await wait(() => { |
|||
expect(store.getState().app.settings.nodeImages.custom[0].command).toBe('a'); |
|||
}); |
|||
expect(onClose).toHaveBeenCalled(); |
|||
}); |
|||
|
|||
it('should display an error notification if saving fails', async () => { |
|||
onClose.mockImplementation(() => { |
|||
throw new Error('test-error'); |
|||
}); |
|||
const { getByText, findByText } = await renderComponent(); |
|||
fireEvent.click(getByText('Save')); |
|||
expect(await findByText('Failed to update the Node Image')).toBeInTheDocument(); |
|||
expect(await findByText('test-error')).toBeInTheDocument(); |
|||
}); |
|||
}); |
@ -0,0 +1,127 @@ |
|||
import React from 'react'; |
|||
import { fireEvent } from '@testing-library/react'; |
|||
import os from 'os'; |
|||
import { CustomImage } from 'types'; |
|||
import { DOCKER_REPO } from 'utils/constants'; |
|||
import { |
|||
injections, |
|||
renderWithProviders, |
|||
suppressConsoleErrors, |
|||
testCustomImages, |
|||
} from 'utils/tests'; |
|||
import CustomImagesTable from './CustomImagesTable'; |
|||
|
|||
jest.mock('os'); |
|||
|
|||
const mockOS = os as jest.Mocked<typeof os>; |
|||
const dockerServiceMock = injections.dockerService as jest.Mocked< |
|||
typeof injections.dockerService |
|||
>; |
|||
const settingsServiceMock = injections.settingsService as jest.Mocked< |
|||
typeof injections.settingsService |
|||
>; |
|||
|
|||
describe('CustomImagesTable Component', () => { |
|||
const renderComponent = (images?: CustomImage[]) => { |
|||
const nodeImages = { |
|||
custom: images || testCustomImages, |
|||
}; |
|||
const initialState = { |
|||
app: { |
|||
settings: { |
|||
nodeImages, |
|||
}, |
|||
}, |
|||
}; |
|||
|
|||
const result = renderWithProviders(<CustomImagesTable images={nodeImages.custom} />, { |
|||
initialState, |
|||
}); |
|||
return { |
|||
...result, |
|||
nodeImages, |
|||
}; |
|||
}; |
|||
|
|||
beforeEach(() => { |
|||
mockOS.platform.mockReturnValue('darwin'); |
|||
dockerServiceMock.getImages.mockResolvedValue(['aaa', 'bbb', `${DOCKER_REPO}/lnd`]); |
|||
}); |
|||
|
|||
it('should display title', () => { |
|||
const { getByText } = renderComponent(); |
|||
expect(getByText('Custom Nodes')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display all custom images', () => { |
|||
const { getByText, nodeImages } = renderComponent(); |
|||
nodeImages.custom.forEach(i => { |
|||
expect(getByText(i.name)).toBeInTheDocument(); |
|||
expect(getByText(i.dockerImage)).toBeInTheDocument(); |
|||
}); |
|||
}); |
|||
|
|||
it('should not render anything if there are no custom nodes', () => { |
|||
const { queryByText } = renderComponent([]); |
|||
expect(queryByText('Custom Nodes')).not.toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should not display incompatible custom images', () => { |
|||
mockOS.platform.mockReturnValueOnce('win32'); |
|||
const { queryByText, nodeImages } = renderComponent(); |
|||
expect(queryByText(nodeImages.custom[1].name)).not.toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should show the Custom Node Details modal', async () => { |
|||
const { getAllByText, findByText } = renderComponent(); |
|||
// click on the first Edit link
|
|||
fireEvent.click(getAllByText('Edit')[0]); |
|||
expect(await findByText('Custom Node Details')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should hide the Custom Node Details modal', async () => { |
|||
const { getAllByText, getByLabelText, queryByText, findByText } = renderComponent(); |
|||
// click on the first Edit link
|
|||
fireEvent.click(getAllByText('Edit')[0]); |
|||
expect(await findByText('Custom Node Details')).toBeInTheDocument(); |
|||
fireEvent.click(getByLabelText('close')); |
|||
expect(queryByText('Custom Node Details')).not.toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should remove a custom node', async () => { |
|||
const { |
|||
getByText, |
|||
getAllByLabelText, |
|||
findByText, |
|||
nodeImages, |
|||
store, |
|||
} = renderComponent(); |
|||
const { name } = nodeImages.custom[0]; |
|||
expect(getByText(name)).toBeInTheDocument(); |
|||
// click on the first Delete icon
|
|||
fireEvent.click(getAllByLabelText('delete')[0]); |
|||
const title = `Are you sure you want to remove the custom image '${nodeImages.custom[0].name}'?`; |
|||
expect(await findByText(title)).toBeInTheDocument(); |
|||
fireEvent.click(getByText('Yes')); |
|||
expect( |
|||
await findByText(`The custom image '${name}' has been removed`), |
|||
).toBeInTheDocument(); |
|||
expect(store.getState().app.settings.nodeImages.custom.length).toBe(1); |
|||
}); |
|||
|
|||
it('should display an error if removing a custom node fails', async () => { |
|||
settingsServiceMock.save.mockRejectedValue(new Error('test-error')); |
|||
await suppressConsoleErrors(async () => { |
|||
const { getByText, getAllByLabelText, findByText, nodeImages } = renderComponent(); |
|||
const { name } = nodeImages.custom[0]; |
|||
expect(getByText(name)).toBeInTheDocument(); |
|||
// click on the first Delete icon
|
|||
fireEvent.click(getAllByLabelText('delete')[0]); |
|||
const title = `Are you sure you want to remove the custom image '${nodeImages.custom[0].name}'?`; |
|||
expect(await findByText(title)).toBeInTheDocument(); |
|||
fireEvent.click(getByText('Yes')); |
|||
expect(await findByText('Unable to remove the custom node')).toBeInTheDocument(); |
|||
expect(await findByText('test-error')).toBeInTheDocument(); |
|||
}); |
|||
}); |
|||
}); |
@ -0,0 +1,97 @@ |
|||
import React from 'react'; |
|||
import { fireEvent, wait } from '@testing-library/react'; |
|||
import { dockerConfigs } from 'utils/constants'; |
|||
import { renderWithProviders, testManagedImages } from 'utils/tests'; |
|||
import ManagedImageModal from './ManagedImageModal'; |
|||
|
|||
describe('ManagedImageModal Component', () => { |
|||
const onClose = jest.fn(); |
|||
|
|||
const renderComponent = () => { |
|||
const nodeImages = { |
|||
managed: testManagedImages, |
|||
}; |
|||
const initialState = { |
|||
app: { |
|||
settings: { |
|||
nodeImages, |
|||
}, |
|||
}, |
|||
}; |
|||
|
|||
const image = nodeImages.managed[2]; |
|||
const result = renderWithProviders( |
|||
<ManagedImageModal image={image} onClose={onClose} />, |
|||
{ initialState }, |
|||
); |
|||
return { |
|||
...result, |
|||
image, |
|||
}; |
|||
}; |
|||
|
|||
it('should display title', () => { |
|||
const { getByText } = renderComponent(); |
|||
expect(getByText(/Customize Managed Node - */)).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display form fields', () => { |
|||
const { getByText } = renderComponent(); |
|||
expect(getByText('Docker Image')).toBeInTheDocument(); |
|||
expect(getByText('Command')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display footer buttons', () => { |
|||
const { getByText } = renderComponent(); |
|||
expect(getByText('Reset to Default')).toBeInTheDocument(); |
|||
expect(getByText('Cancel')).toBeInTheDocument(); |
|||
expect(getByText('Save')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display the command variables', () => { |
|||
const { getByText, image } = renderComponent(); |
|||
expect(getByText('Command Variable Substitutions')).toBeInTheDocument(); |
|||
fireEvent.click(getByText('Command Variable Substitutions')); |
|||
const vars = dockerConfigs[image.implementation].variables; |
|||
vars.forEach(v => { |
|||
expect(getByText(v)).toBeInTheDocument(); |
|||
}); |
|||
}); |
|||
|
|||
it('should have form fields populated', () => { |
|||
const { getByDisplayValue, image } = renderComponent(); |
|||
const { implementation, version } = image; |
|||
const { imageName } = dockerConfigs[implementation]; |
|||
expect(getByDisplayValue(`${imageName}:${version}`)).toBeInTheDocument(); |
|||
expect(getByDisplayValue(image.command)).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should save the managed image', async () => { |
|||
const { getByText, getByLabelText, store } = renderComponent(); |
|||
fireEvent.change(getByLabelText('Command'), { target: { value: 'a' } }); |
|||
fireEvent.click(getByText('Save')); |
|||
await wait(() => { |
|||
expect(store.getState().app.settings.nodeImages.managed[2].command).toBe('a'); |
|||
}); |
|||
expect(onClose).toHaveBeenCalled(); |
|||
}); |
|||
|
|||
it('should reset the managed image to default', async () => { |
|||
const { getByText, store } = renderComponent(); |
|||
fireEvent.click(getByText('Reset to Default')); |
|||
await wait(() => { |
|||
expect(store.getState().app.settings.nodeImages.managed[2]).toBeUndefined(); |
|||
}); |
|||
expect(onClose).toHaveBeenCalled(); |
|||
}); |
|||
|
|||
it('should display an error notification if saving fails', async () => { |
|||
onClose.mockImplementation(() => { |
|||
throw new Error('test-error'); |
|||
}); |
|||
const { getByText, findByText } = renderComponent(); |
|||
fireEvent.click(getByText('Save')); |
|||
expect(await findByText('Failed to update the Node Image')).toBeInTheDocument(); |
|||
expect(await findByText('test-error')).toBeInTheDocument(); |
|||
}); |
|||
}); |
@ -0,0 +1,80 @@ |
|||
import React from 'react'; |
|||
import { fireEvent } from '@testing-library/react'; |
|||
import os from 'os'; |
|||
import { DOCKER_REPO } from 'utils/constants'; |
|||
import { injections, renderWithProviders, testManagedImages } from 'utils/tests'; |
|||
import ManagedImagesTable from './ManagedImagesTable'; |
|||
|
|||
jest.mock('os'); |
|||
|
|||
const mockOS = os as jest.Mocked<typeof os>; |
|||
const dockerServiceMock = injections.dockerService as jest.Mocked< |
|||
typeof injections.dockerService |
|||
>; |
|||
|
|||
describe('ManagedImagesTable Component', () => { |
|||
const renderComponent = () => { |
|||
const nodeImages = { |
|||
managed: testManagedImages, |
|||
}; |
|||
const initialState = { |
|||
app: { |
|||
settings: { |
|||
nodeImages, |
|||
}, |
|||
}, |
|||
}; |
|||
|
|||
const result = renderWithProviders( |
|||
<ManagedImagesTable images={nodeImages.managed} />, |
|||
{ initialState }, |
|||
); |
|||
return { |
|||
...result, |
|||
nodeImages, |
|||
}; |
|||
}; |
|||
|
|||
beforeEach(() => { |
|||
mockOS.platform.mockReturnValue('darwin'); |
|||
dockerServiceMock.getImages.mockResolvedValue(['aaa', 'bbb', `${DOCKER_REPO}/lnd`]); |
|||
}); |
|||
|
|||
it('should display title', () => { |
|||
const { getByText } = renderComponent(); |
|||
expect(getByText('Nodes Managed by Polar')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display all managed images', () => { |
|||
const { getAllByText } = renderComponent(); |
|||
// 1 is the number of each implementation in testManagedImages
|
|||
expect(getAllByText('polarlightning/lnd')).toHaveLength(1); |
|||
expect(getAllByText('polarlightning/clightning')).toHaveLength(1); |
|||
expect(getAllByText('polarlightning/bitcoind')).toHaveLength(1); |
|||
}); |
|||
|
|||
it('should not display incompatible managed images', () => { |
|||
mockOS.platform.mockReturnValueOnce('win32'); |
|||
const { queryAllByText } = renderComponent(); |
|||
// 1 is the number of each implementation in testManagedImages
|
|||
expect(queryAllByText('polarlightning/lnd')).toHaveLength(1); |
|||
expect(queryAllByText('polarlightning/clightning')).toHaveLength(0); |
|||
expect(queryAllByText('polarlightning/bitcoind')).toHaveLength(1); |
|||
}); |
|||
|
|||
it('should show the Customize Managed Node modal', async () => { |
|||
const { getAllByText, findByText } = renderComponent(); |
|||
// click on the first Edit link
|
|||
fireEvent.click(getAllByText('Edit')[0]); |
|||
expect(await findByText(/Customize Managed Node - */)).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should hide the Customize Managed Node modal', async () => { |
|||
const { getAllByText, getByLabelText, queryByText, findByText } = renderComponent(); |
|||
// click on the first Edit link
|
|||
fireEvent.click(getAllByText('Edit')[0]); |
|||
expect(await findByText(/Customize Managed Node - */)).toBeInTheDocument(); |
|||
fireEvent.click(getByLabelText('close')); |
|||
expect(queryByText(/Customize Managed Node - */)).not.toBeInTheDocument(); |
|||
}); |
|||
}); |
@ -0,0 +1,91 @@ |
|||
import React from 'react'; |
|||
import { fireEvent } from '@testing-library/react'; |
|||
import { defaultRepoState, DOCKER_REPO } from 'utils/constants'; |
|||
import { |
|||
injections, |
|||
renderWithProviders, |
|||
testCustomImages, |
|||
testManagedImages, |
|||
} from 'utils/tests'; |
|||
import NodeImagesView from './NodeImagesView'; |
|||
|
|||
const dockerServiceMock = injections.dockerService as jest.Mocked< |
|||
typeof injections.dockerService |
|||
>; |
|||
|
|||
describe('NodeImagesView Component', () => { |
|||
const renderComponent = () => { |
|||
const nodeImages = { |
|||
managed: testManagedImages, |
|||
custom: testCustomImages, |
|||
}; |
|||
const initialState = { |
|||
app: { |
|||
settings: { |
|||
nodeImages, |
|||
}, |
|||
}, |
|||
}; |
|||
|
|||
const result = renderWithProviders(<NodeImagesView />, { |
|||
initialState, |
|||
}); |
|||
return { |
|||
...result, |
|||
nodeImages, |
|||
}; |
|||
}; |
|||
|
|||
beforeEach(() => { |
|||
dockerServiceMock.getImages.mockResolvedValue(['aaa', 'bbb', `${DOCKER_REPO}/lnd`]); |
|||
}); |
|||
|
|||
it('should display titles', () => { |
|||
const { getByText } = renderComponent(); |
|||
expect(getByText('Customize Node Docker Images')).toBeInTheDocument(); |
|||
expect(getByText('Custom Nodes')).toBeInTheDocument(); |
|||
expect(getByText('Nodes Managed by Polar')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should display all managed images', () => { |
|||
const { getAllByText } = renderComponent(); |
|||
expect(getAllByText('polarlightning/lnd')).toHaveLength( |
|||
defaultRepoState.images.LND.versions.length, |
|||
); |
|||
expect(getAllByText('polarlightning/clightning')).toHaveLength( |
|||
defaultRepoState.images['c-lightning'].versions.length, |
|||
); |
|||
expect(getAllByText('polarlightning/bitcoind')).toHaveLength( |
|||
defaultRepoState.images.bitcoind.versions.length, |
|||
); |
|||
}); |
|||
|
|||
it('should display custom images', () => { |
|||
const { getByText, nodeImages } = renderComponent(); |
|||
const custom = nodeImages.custom[0]; |
|||
expect(getByText(custom.name)).toBeInTheDocument(); |
|||
expect(getByText(custom.dockerImage)).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should navigate home when back button clicked', () => { |
|||
const { getByLabelText, history } = renderComponent(); |
|||
const backBtn = getByLabelText('Back'); |
|||
expect(backBtn).toBeInTheDocument(); |
|||
fireEvent.click(backBtn); |
|||
expect(history.location.pathname).toEqual('/'); |
|||
}); |
|||
|
|||
it('should open the Add Custom Image modal', async () => { |
|||
const { getByText, findByText } = renderComponent(); |
|||
fireEvent.click(getByText('Add a Custom Node')); |
|||
expect(await findByText('Custom Node Details')).toBeInTheDocument(); |
|||
}); |
|||
|
|||
it('should close the Add Custom Image modal', async () => { |
|||
const { getByText, getByLabelText, queryByText, findByText } = renderComponent(); |
|||
fireEvent.click(getByText('Add a Custom Node')); |
|||
expect(await findByText('Custom Node Details')).toBeInTheDocument(); |
|||
fireEvent.click(getByLabelText('close')); |
|||
expect(queryByText('Custom Node Details')).not.toBeInTheDocument(); |
|||
}); |
|||
}); |
Loading…
Reference in new issue