datajunction-ui
Version:
DataJunction Metrics Platform UI
297 lines (269 loc) • 8.69 kB
JSX
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import DJClientContext from '../../../providers/djclient';
import { NamespacePage } from '../index';
import React from 'react';
import userEvent from '@testing-library/user-event';
const mockDjClient = {
namespaces: jest.fn(),
namespace: jest.fn(),
listNodesForLanding: jest.fn(),
addNamespace: jest.fn(),
whoami: jest.fn(),
users: jest.fn(),
listTags: jest.fn(),
};
describe('NamespacePage', () => {
const original = window.location;
const reloadFn = () => {
window.location.reload();
};
beforeAll(() => {
Object.defineProperty(window, 'location', {
configurable: true,
value: { reload: jest.fn() },
});
});
afterAll(() => {
Object.defineProperty(window, 'location', {
configurable: true,
value: original,
});
});
beforeEach(() => {
fetch.resetMocks();
mockDjClient.whoami.mockResolvedValue({ username: 'dj' });
mockDjClient.users.mockResolvedValue([
{ username: 'dj' },
{ username: 'user1' },
]);
mockDjClient.listTags.mockResolvedValue([
{ name: 'tag1' },
{ name: 'tag2' },
]);
mockDjClient.namespaces.mockResolvedValue([
{
namespace: 'common.one',
num_nodes: 3,
},
{
namespace: 'common.one.a',
num_nodes: 6,
},
{
namespace: 'common.one.b',
num_nodes: 17,
},
{
namespace: 'common.one.c',
num_nodes: 64,
},
{
namespace: 'default',
num_nodes: 41,
},
{
namespace: 'default.fruits',
num_nodes: 1,
},
{
namespace: 'default.fruits.citrus.lemons',
num_nodes: 1,
},
{
namespace: 'default.vegetables',
num_nodes: 2,
},
]);
mockDjClient.namespace.mockResolvedValue([
{
name: 'testNode',
display_name: 'Test Node',
type: 'transform',
mode: 'active',
updated_at: new Date(),
tags: [{ name: 'tag1' }],
edited_by: ['dj'],
},
]);
mockDjClient.listNodesForLanding.mockResolvedValue({
data: {
findNodesPaginated: {
pageInfo: {
hasNextPage: true,
endCursor:
'eyJjcmVhdGVkX2F0IjogIjIwMjQtMDQtMTZUMjM6MjI6MjIuNDQxNjg2KzAwOjAwIiwgImlkIjogNjE0fQ==',
hasPrevPage: true,
startCursor:
'eyJjcmVhdGVkX2F0IjogIjIwMjQtMTAtMTZUMTY6MDM6MTcuMDgzMjY3KzAwOjAwIiwgImlkIjogMjQwOX0=',
},
edges: [
{
node: {
name: 'default.test_node',
type: 'DIMENSION',
currentVersion: 'v4.0',
tags: [],
editedBy: ['dj'],
current: {
displayName: 'Test Node',
status: 'VALID',
updatedAt: '2024-10-18T15:15:33.532949+00:00',
},
createdBy: {
username: 'dj',
},
},
},
],
},
},
});
});
afterEach(() => {
jest.clearAllMocks();
});
it('displays namespaces and renders nodes', async () => {
reloadFn();
const element = (
<DJClientContext.Provider value={{ DataJunctionAPI: mockDjClient }}>
<NamespacePage />
</DJClientContext.Provider>
);
render(
<MemoryRouter initialEntries={['/namespaces/test.namespace']}>
<Routes>
<Route path="namespaces/:namespace" element={element} />
</Routes>
</MemoryRouter>,
);
await waitFor(
() => {
expect(mockDjClient.listNodesForLanding).toHaveBeenCalled();
expect(screen.getByText('Namespaces')).toBeInTheDocument();
// check that it displays namespaces
expect(screen.getByText('common')).toBeInTheDocument();
expect(screen.getByText('one')).toBeInTheDocument();
expect(screen.getByText('fruits')).toBeInTheDocument();
expect(screen.getByText('vegetables')).toBeInTheDocument();
// check that it renders nodes
expect(screen.getByText('Test Node')).toBeInTheDocument();
// check that it sorts nodes
fireEvent.click(screen.getByText('name'));
fireEvent.click(screen.getByText('name'));
fireEvent.click(screen.getByText('display Name'));
// paginate
const previousButton = screen.getByText('← Previous');
expect(previousButton).toBeDefined();
fireEvent.click(previousButton);
const nextButton = screen.getByText('Next →');
expect(nextButton).toBeDefined();
fireEvent.click(nextButton);
// check that we can filter by node type
const selectNodeType = screen.getAllByTestId('select-node-type')[0];
expect(selectNodeType).toBeDefined();
expect(selectNodeType).not.toBeNull();
fireEvent.keyDown(selectNodeType.firstChild, { key: 'ArrowDown' });
fireEvent.click(screen.getByText('Source'));
// check that we can filter by tag
const selectTag = screen.getAllByTestId('select-tag')[0];
expect(selectTag).toBeDefined();
expect(selectTag).not.toBeNull();
fireEvent.keyDown(selectTag.firstChild, { key: 'ArrowDown' });
// check that we can filter by user
const selectUser = screen.getAllByTestId('select-user')[0];
expect(selectUser).toBeDefined();
expect(selectUser).not.toBeNull();
fireEvent.keyDown(selectUser.firstChild, { key: 'ArrowDown' });
// click to open and close tab
fireEvent.click(screen.getByText('common'));
fireEvent.click(screen.getByText('common'));
},
{ timeout: 3000 },
);
}, 60000);
it('can add new namespace via add namespace popover', async () => {
mockDjClient.addNamespace.mockReturnValue({
status: 201,
json: {},
});
const element = (
<DJClientContext.Provider value={{ DataJunctionAPI: mockDjClient }}>
<NamespacePage />
</DJClientContext.Provider>
);
render(
<MemoryRouter initialEntries={['/namespaces/test.namespace']}>
<Routes>
<Route path="namespaces/:namespace" element={element} />
</Routes>
</MemoryRouter>,
);
// Find the button to toggle the add namespace popover
const addNamespaceToggle = screen.getByRole('button', {
name: 'AddNamespaceTogglePopover',
});
expect(addNamespaceToggle).toBeInTheDocument();
// Click the toggle and verify that the popover displays
fireEvent.click(addNamespaceToggle);
const addNamespacePopover = screen.getByRole('dialog', {
name: 'AddNamespacePopover',
});
expect(addNamespacePopover).toBeInTheDocument();
// Type in the new namespace
await userEvent.type(
screen.getByLabelText('Namespace'),
'some.random.namespace',
);
// Save
const saveNamespace = screen.getByRole('button', {
name: 'SaveNamespace',
});
await waitFor(() => {
fireEvent.click(saveNamespace);
});
expect(mockDjClient.addNamespace).toHaveBeenCalled();
expect(mockDjClient.addNamespace).toHaveBeenCalledWith(
'test.namespace.some.random.namespace',
);
expect(screen.getByText('Saved')).toBeInTheDocument();
expect(window.location.reload).toHaveBeenCalled();
});
it('can fail to add namespace', async () => {
mockDjClient.addNamespace.mockReturnValue({
status: 500,
json: { message: 'you failed' },
});
const element = (
<DJClientContext.Provider value={{ DataJunctionAPI: mockDjClient }}>
<NamespacePage />
</DJClientContext.Provider>
);
render(
<MemoryRouter initialEntries={['/namespaces/test.namespace']}>
<Routes>
<Route path="namespaces/:namespace" element={element} />
</Routes>
</MemoryRouter>,
);
// Open the add namespace popover
const addNamespaceToggle = screen.getByRole('button', {
name: 'AddNamespaceTogglePopover',
});
fireEvent.click(addNamespaceToggle);
// Type in the new namespace
await userEvent.type(
screen.getByLabelText('Namespace'),
'some.random.namespace',
);
// Save
const saveNamespace = screen.getByRole('button', {
name: 'SaveNamespace',
});
await waitFor(() => {
fireEvent.click(saveNamespace);
});
// Should display failure alert
expect(screen.getByText('you failed')).toBeInTheDocument();
});
});