Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View systems #18 #115

Merged
merged 18 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions cypress/e2e/system.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,52 @@ describe('System', () => {
cy.findByText('Giant laser').should('be.visible');
});

it('should be able to navigate through subsystems', () => {
cy.findByText('No system selected').should('be.visible');
cy.findByText('Please select a system').should('be.visible');

// Navigate deeper
cy.findByRole('link', { name: 'Giant laser' }).click();
cy.url().should('include', '/systems/65328f34a40ff5301575a4e3');
cy.findByText('No system selected').should('not.exist');
cy.findByText('Please select a system').should('not.exist');

cy.findByText('Smaller laser').should('be.visible');
cy.findByText('Description').should('be.visible');

// Navigate deeper again
cy.findByRole('link', { name: 'Smaller laser' }).click();
cy.url().should('include', '/systems/65328f34a40ff5301575a4e4');

cy.findByText('Pulse Laser').should('be.visible');
cy.findByText('Description').should('be.visible');
});

it('breadcrumbs should work correctly', () => {
cy.visit('/inventory-management-system/systems/65328f34a40ff5301575a4e9');

cy.findByRole('link', { name: 'Pulse Laser' }).should('be.visible');
cy.findByRole('link', { name: 'Giant laser' }).should('be.visible');
cy.findByRole('link', { name: 'Laser Star' }).should('be.visible');
cy.findByRole('link', { name: 'Smaller laser' }).should('be.visible');

// One in title, one in breadcrumbs
cy.findAllByText('Plasma Beam').should('have.length', 2);

// Check can navigate back with breadcrumbs
cy.findByRole('link', { name: 'Giant laser' }).click();
cy.url().should('include', '/systems/65328f34a40ff5301575a4e6');
cy.findAllByText('Giant laser').should('have.length', 2);

// Check can go back to root
cy.findByRole('button', { name: 'navigate to systems home' }).click();
cy.url().then((url) => {
expect(url.endsWith('/systems'));
});
cy.findByText('No system selected').should('be.visible');
cy.findByText('Please select a system').should('be.visible');
});

it('adds a root system with only required parameters', () => {
cy.findByRole('button', { name: 'add system' }).click();

Expand Down
39 changes: 37 additions & 2 deletions src/api/systems.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { renderHook, waitFor } from '@testing-library/react';
import { AddSystem, SystemImportanceType } from '../app.types';
import SystemBreadcrumbsJSON from '../mocks/SystemBreadcrumbs.json';
import SystemsJSON from '../mocks/Systems.json';
import { hooksWrapperWithProviders } from '../setupTests';
import { useAddSystem, useSystems, useSystemsBreadcrumbs } from './systems';
import { SystemImportanceType, AddSystem } from '../app.types';
import {
useAddSystem,
useSystem,
useSystems,
useSystemsBreadcrumbs,
} from './systems';

describe('System api functions', () => {
afterEach(() => {
Expand Down Expand Up @@ -59,6 +64,36 @@ describe('System api functions', () => {
});
});

describe('useSystem', () => {
it('does not send a request when given an id of null', async () => {
const { result } = renderHook(() => useSystem(null), {
wrapper: hooksWrapperWithProviders(),
});

expect(result.current.isFetching).toBeFalsy();
expect(result.current.data).toEqual(undefined);
});

it('sends request to fetch a system and returns successful response', async () => {
const { result } = renderHook(
() => useSystem('65328f34a40ff5301575a4e3'),
{
wrapper: hooksWrapperWithProviders(),
}
);

await waitFor(() => {
expect(result.current.isSuccess).toBeTruthy();
});

expect(result.current.data).toEqual(
SystemsJSON.filter(
(system) => system.id === '65328f34a40ff5301575a4e3'
)[0]
);
});
});

describe('useSystemsBreadcrumbs', () => {
it('does not send a request to fetch breadcrumbs data for a system when its id is null', async () => {
const { result } = renderHook(() => useSystemsBreadcrumbs(null), {
Expand Down
52 changes: 51 additions & 1 deletion src/api/systems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,28 @@
useQueryClient,
} from '@tanstack/react-query';
import axios, { AxiosError } from 'axios';
import { BreadcrumbsInfo, System, AddSystem } from '../app.types';
import {
AddSystem,
BreadcrumbsInfo,
System,
SystemImportanceType,
} from '../app.types';
import { settings } from '../settings';

/** Utility for turning an importance into an MUI palette colour to display */
export const getSystemImportanceColour = (
importance: SystemImportanceType
): 'success' | 'warning' | 'error' => {
switch (importance) {
case SystemImportanceType.LOW:
return 'success';
case SystemImportanceType.MEDIUM:
return 'warning';
case SystemImportanceType.HIGH:
return 'error';
}
};

const fetchSystems = async (parent_id?: string): Promise<System[]> => {
let apiUrl: string;
apiUrl = '';
Expand Down Expand Up @@ -43,6 +62,37 @@
);
};

const fetchSystem = async (id: string): Promise<System> => {
let apiUrl: string;
apiUrl = '';
const settingsResult = await settings;
if (settingsResult) {
apiUrl = settingsResult['apiUrl'];

Check warning on line 70 in src/api/systems.tsx

View check run for this annotation

Codecov / codecov/patch

src/api/systems.tsx#L70

Added line #L70 was not covered by tests
}

return axios.get(`${apiUrl}/v1/systems/${id}`).then((response) => {
return response.data;
});
};

// Allows a value of null to disable
export const useSystem = (
id: string | null
): UseQueryResult<System, AxiosError> => {
return useQuery<System, AxiosError>(
['System', id],
() => {
return fetchSystem(id ?? '');
},
{
enabled: id !== null,
onError: (error) => {
console.log('Got error ' + error.message);
},
}
);
};

const fetchSystemsBreadcrumbs = async (
id: string
): Promise<BreadcrumbsInfo> => {
Expand Down
10 changes: 5 additions & 5 deletions src/mocks/Systems.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[
{
"name": "Giant laser",
"location": "80371 Alvarado Drive Apt. 272\nHeatherhaven, MP 33307",
"location": "80371 Alvarado Drive Apt. 272, Heatherhaven, MP 33307",
"owner": "Juan Horton",
"importance": "high",
"description": "Take Democrat early money some. Tree meet fly her likely.",
"description": "Take Democrat early money some.\nTree meet fly her likely.",
"parent_id": null,
"id": "65328f34a40ff5301575a4e3",
"code": "laser-tech"
Expand All @@ -21,10 +21,10 @@
},
{
"name": "Pulse Laser",
"location": "8988 Richard Mews\nCatherinemouth, IL 68034",
"owner": "Sarah Parker",
"location": null,
"owner": null,
"importance": "medium",
"description": "State still last to think.",
"description": null,
"parent_id": "65328f34a40ff5301575a4e4",
"id": "65328f34a40ff5301575a4e5",
"code": "pulse-laser"
Expand Down
11 changes: 11 additions & 0 deletions src/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,17 @@ export const handlers = [
return res(ctx.status(200), ctx.json(data));
}),

rest.get('/v1/systems/:id', (req, res, ctx) => {
const { id } = req.params;
const data = SystemsJSON.filter((system) => system.id === id);
if (data.length > 0) return res(ctx.status(200), ctx.json(data[0]));
else
return res(
ctx.status(404),
ctx.json({ detail: 'A System with such ID was not found' })
);
}),

rest.get('/v1/systems/:id/breadcrumbs', (req, res, ctx) => {
const { id } = req.params;
const data = SystemBreadcrumbsJSON.find(
Expand Down
10 changes: 9 additions & 1 deletion src/systems/__snapshots__/systemDialog.component.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,15 @@ exports[`Systems Dialog renders correctly when adding 1`] = `
role="button"
tabindex="0"
>
medium
<div
class="MuiChip-root MuiChip-filled MuiChip-sizeMedium MuiChip-colorWarning MuiChip-filledWarning css-1mtfbl3-MuiChip-root"
>
<span
class="MuiChip-label MuiChip-labelMedium css-6od3lo-MuiChip-label"
>
medium
</span>
</div>
</div>
<input
aria-hidden="true"
Expand Down
79 changes: 79 additions & 0 deletions src/systems/systemDetails.component.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { screen, waitFor } from '@testing-library/react';
import React from 'react';
import { System } from '../app.types';
import { renderComponentWithBrowserRouter } from '../setupTests';
import SystemsJSON from '../mocks/Systems.json';
import SystemDetails, { SystemDetailsProps } from './systemDetails.component';

describe('SystemDetails', () => {
let props: SystemDetailsProps;
let mockSystemDetails: System;

const createView = () => {
if (props.id)
mockSystemDetails = SystemsJSON.filter(
(system) => system.id === props.id
)[0];
return renderComponentWithBrowserRouter(<SystemDetails {...props} />);
};

beforeEach(() => {
props = {
id: '65328f34a40ff5301575a4e3',
};
});

it('renders correctly when no system is selected', async () => {
props.id = null;

createView();

expect(screen.getByText('No system selected')).toBeInTheDocument();
expect(screen.getByText('Please select a system')).toBeInTheDocument();
});

it('renders correctly when a system is selected', async () => {
createView();

await waitFor(() => {
expect(screen.getByText(mockSystemDetails.name)).toBeInTheDocument();
});
expect(screen.queryByText('Please select a system')).toBeFalsy();
expect(
screen.getByText(mockSystemDetails.location ?? '')
).toBeInTheDocument();
expect(screen.getByText(mockSystemDetails.owner ?? '')).toBeInTheDocument();
expect(
screen.getByText(mockSystemDetails.importance ?? '')
).toBeInTheDocument();
// Can have new line character which breaks normal matching
expect(
screen.getByText(
(_, element) => element?.textContent === mockSystemDetails.description
)
).toBeInTheDocument();
});

it('renders correctly when a system with only required values is selected', async () => {
props.id = '65328f34a40ff5301575a4e5';
createView();

await waitFor(() => {
expect(screen.getByText(mockSystemDetails.name)).toBeInTheDocument();
});
expect(screen.queryByText('Please select a system')).toBeFalsy();
// One for each of location, owner and description
expect(await screen.findAllByText('None')).toHaveLength(3);
});

it('renders correctly when the system is not found', async () => {
props.id = 'invalid_id';

createView();

await waitFor(() => {
expect(screen.getByText('No system selected')).toBeInTheDocument();
});
expect(screen.getByText('Please select a system')).toBeInTheDocument();
});
});
Loading
Loading