Skip to content

Commit

Permalink
Merge pull request #101 from CDLUC3/feature/86-build-changelog-histor…
Browse files Browse the repository at this point in the history
…y-page

[Feature] - Built template history page
  • Loading branch information
jupiter007 authored Aug 29, 2024
2 parents 53ee372 + febfe80 commit 377176d
Show file tree
Hide file tree
Showing 20 changed files with 1,059 additions and 100 deletions.
17 changes: 11 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
## [1.0.0]

### Added
- Added the Template History page [#86]
- Added more documentation to README.md [#91]
- Added existing header and footer from production to app [#89]
- Added two new TypeAhead/Autosuggest components, one with and one without the "Other" option [#10]
- Added the use of graphql-codegen to generate types for graphql requests [#10]

### Updates
- Updated endpoints for 'signin' and 'signup' to be 'apollo-signin' and 'apollo-signup' [#99]

### Fixed
- Fixed an issue with docker-compose not starting the app [#93]

## v0.0.1

### Added
- Added logout api and link [#65]
- Added loading state and velocity controls to the login and signup forms [#66]
- Added placeholders for /signup and /login pages and added a new api endpoint for setting the access token in a cookie [#19]
- Added .editorconfig file to help maintain consistent coding styles [#37]
- Added buildspec.yaml file for CI/CD pipeline [#81]
- Added graphql file structure and client creation. [#36]
- Added Styleguide Page, as well as custom components and css that are only to
be used on the Styleguide. [#51]
- Added some default CSS variables that we can hook into when we start doing the
Expand All @@ -34,5 +41,3 @@
outline in the styleguide. [#51]
- Updated some CSS classes to remove verbose naming. [#51]

### Fixed
- Fixed an issue with docker-compose not starting the app [#93]
2 changes: 2 additions & 0 deletions app/login/__tests__/page.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const mockFocus = jest.fn();
import { useRouter } from 'next/navigation';

const mockUseRouter = useRouter as jest.Mock;
// Assign fetch to global object in Node.js environment
global.fetch = global.fetch || require('node-fetch');

describe('LoginPage', () => {
beforeEach(() => {
Expand Down
1 change: 1 addition & 0 deletions app/signup/__tests__/page.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const mockFocus = jest.fn();
import { useRouter } from 'next/navigation';

const mockUseRouter = useRouter as jest.Mock;
global.fetch = global.fetch || require('node-fetch');

describe('SignUpPage', () => {

Expand Down
39 changes: 38 additions & 1 deletion app/styleguide/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import {
OverlayArrow,
Dialog,
Switch,
Table,
TableHeader,
TableBody,
Column,
Row,
Cell,
} from "react-aria-components";
import "./styleguide.scss";

Expand All @@ -43,6 +49,7 @@ function Page() {
<a href="#_layout">Layout</a>
<a href="#_forms">Forms</a>
<a href="#_fields">Form Fields</a>
<a href="#_table">Table</a>
<a href="#_widgets">Custom Widget</a>
</div>

Expand Down Expand Up @@ -407,6 +414,36 @@ function Page() {
</Example>
</div>

<div id="_table">
<h2>Table</h2>
<p>
A table displays data in rows and columns and enables a user to navigate its contents via directional navigation keys, and optionally supports row selection and sorting.
</p>

<p>
This is a <em>core component</em>, see
the <a href="https://react-spectrum.adobe.com/react-aria/Table.html">component docs here.</a>
</p>

<Example>
<Table>
<TableHeader>
<Column isRowHeader={true}>One</Column>
<Column isRowHeader={true}>Two</Column>
<Column isRowHeader={true}>Three</Column>
</TableHeader>
<TableBody>
<Row>
<Cell>Item One</Cell>
<Cell>Item Two</Cell>
<Cell>Item Three</Cell>
</Row>
</TableBody>
</Table>
</Example>
</div>


<div id="_widgets">
<h2>Widgets</h2>
<p>TBD (Custom Components, etc…)</p>
Expand Down Expand Up @@ -474,7 +511,7 @@ function Page() {
</Example>
</div>
</div>
</div>
</div >

</>
)
Expand Down
94 changes: 94 additions & 0 deletions app/template/[templateId]/history/__tests__/mockedResponse.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"templateVersions": [
{
"name": "NIH-GDS: Genomic Data Sharing",
"version": "v3.1",
"created": "2024-08-02T02:03:01.000Z",
"comment": "Added some additional requirements to Preservation section!",
"versionedBy": {
"givenName": "Severus",
"surName": "Snape",
"affiliation": {
"name": "National Institutes of Health"
},
"modified": "2024-08-21T18:05:57.000Z",
"modifiedById": 459
}
},
{
"name": "NIH-GDS: Genomic Data Sharing",
"version": "v3",
"created": "2024-04-01T02:03:00.000Z",
"comment": "This is the initial version of our template!",
"versionedBy": {
"givenName": "Severus",
"surName": "Snape",
"affiliation": {
"name": "National Institutes of Health"
},
"modified": "2024-08-21T18:05:57.000Z",
"modifiedById": 320
}
},
{
"name": "NIH-GDS: Genomic Data Sharing",
"version": "v2.2",
"created": "2024-03-21T22:23:20.000Z",
"comment": "Added some additional requirements to Preservation section!",
"versionedBy": {
"givenName": "Severus",
"surName": "Snape",
"affiliation": {
"name": "National Institutes of Health"
},
"modified": "2024-08-21T18:05:57.000Z",
"modifiedById": 779
}
},
{
"name": "NIH-GDS: Genomic Data Sharing",
"version": "v2.1",
"created": "2024-03-19T19:20:18.000Z",
"comment": "Added some additional requirements to Preservation section!",
"versionedBy": {
"givenName": "Severus",
"surName": "Snape",
"affiliation": {
"name": "National Institutes of Health"
},
"modified": "2024-08-21T18:05:57.000Z",
"modifiedById": 822
}
},
{
"name": "NIH-GDS: Genomic Data Sharing",
"version": "v2",
"created": "2024-02-18T16:17:15.000Z",
"comment": "This is the initial version of our template!",
"versionedBy": {
"givenName": "Severus",
"surName": "Snape",
"affiliation": {
"name": "National Institutes of Health"
},
"modified": "2024-08-21T18:05:57.000Z",
"modifiedById": 89
}
},
{
"name": "NIH-GDS: Genomic Data Sharing",
"version": "v1",
"created": "2024-01-17T13:14:15.000Z",
"comment": "This is the initial version of our template!",
"versionedBy": {
"givenName": "Severus",
"surName": "Snape",
"affiliation": {
"name": "National Institutes of Health"
},
"modified": "2024-08-21T18:05:57.000Z",
"modifiedById": 551
}
}
]
}
160 changes: 160 additions & 0 deletions app/template/[templateId]/history/__tests__/page.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React, { ReactNode } from 'react';
import { render, screen } from '@testing-library/react';
import TemplateHistory from '../page';
import { useTemplateVersionsQuery } from '@/generated/graphql';
import { MockedProvider } from '@apollo/client/testing';
import { useParams } from 'next/navigation';
import { axe, toHaveNoViolations } from 'jest-axe';
import mockData from './mockedResponse.json'

expect.extend(toHaveNoViolations);

jest.mock('@/generated/graphql', () => ({
useTemplateVersionsQuery: jest.fn(),
}));

jest.mock('next/navigation', () => ({
useParams: jest.fn(),
}))

jest.mock('@/components/BackButton', () => {
return {
__esModule: true,
default: () => <div>Mocked Back Button</div>,
};
});

jest.mock('@/components/PageWrapper', () => {
const mockPageWrapper = jest.fn(({ children }: { children: ReactNode, title: string }) => (
<div data-testid="mock-page-wrapper">{children}</div>
));
return {
__esModule: true,
default: mockPageWrapper
}
});

describe('TemplateHistory', () => {
beforeEach(() => {
const mockTemplateId = 123;
const mockUseParams = useParams as jest.Mock;

// Mock the return value of useParams
mockUseParams.mockReturnValue({ templateId: `${mockTemplateId}` });
});

it('should render the component with PageWrapper', async () => {
const titleProp = 'Template History';
const pageWrapper = await import('@/components/PageWrapper');
const mockPageWrapper = pageWrapper.default;

(useTemplateVersionsQuery as jest.Mock).mockReturnValue(mockData);

const { getByTestId } = render(<TemplateHistory />);

expect(getByTestId('mock-page-wrapper')).toBeInTheDocument();
expect(mockPageWrapper).toHaveBeenCalledWith(expect.objectContaining({ title: titleProp, }), {})
})

it('should use the templateId from the param in the call to useTemplateVersionsQuery', () => {

(useTemplateVersionsQuery as jest.Mock).mockReturnValue({
data: mockData,
loading: false,
error: null,
});

render(
<MockedProvider>
<TemplateHistory />
</MockedProvider>
);

expect(useTemplateVersionsQuery).toHaveBeenCalledWith({ "variables": { "templateId": 123 } })
});

it('should render loading state correctly', () => {
(useTemplateVersionsQuery as jest.Mock).mockReturnValue({ loading: true });

render(<TemplateHistory />);
expect(screen.getByText('Loading publication history...')).toBeInTheDocument();
});

it('should render error state correctly', () => {
(useTemplateVersionsQuery as jest.Mock).mockReturnValue({ loading: false, error: new Error('Test Error') });

render(<TemplateHistory />);
expect(screen.getByText('There was a problem.')).toBeInTheDocument();
});

it('should render page heading and subheader correctly, which includes the title, by, version and date of latest publication', async () => {
(useTemplateVersionsQuery as jest.Mock).mockReturnValue({
loading: false,
data: mockData,
});

const { getByTestId } = render(<TemplateHistory />);
const h1Element = await screen.findByRole('heading', { level: 1 });
expect(h1Element).toHaveTextContent('NIH-GDS: Genomic Data Sharing');
expect(getByTestId('author')).toHaveTextContent('by National Institutes of Health')
expect(getByTestId('latest-version')).toHaveTextContent('3.1')
expect(getByTestId('publication-date')).toHaveTextContent('Published: Aug 1, 2024')
});

it('should render correct headers for table', async () => {
(useTemplateVersionsQuery as jest.Mock).mockReturnValue({
loading: false,
data: mockData,
});

render(<TemplateHistory />);

// Check h2 header above table
const h2Element = await screen.findByRole('heading', { level: 2 });
expect(h2Element).toHaveTextContent('History');

// Check table column headers
const headers = screen.getAllByRole('columnheader');
expect(headers[0]).toHaveTextContent('Action');
expect(headers[1]).toHaveTextContent('User');
expect(headers[2]).toHaveTextContent('Time and Date');
})

it('should render correct content in table', async () => {
(useTemplateVersionsQuery as jest.Mock).mockReturnValue({
loading: false,
data: mockData,
});

render(<TemplateHistory />);
const table = screen.getByRole('grid');
// Get all rows in table body
const rows = table.querySelectorAll('tbody tr');

// Second row in table
const targetRow1 = rows[1];

const row1Cells = targetRow1.querySelectorAll('td');
expect(row1Cells[0].textContent).toBe('Published v3Change log:This is the initial version of our template!');
expect(row1Cells[1].textContent).toBe('Severus Snape');
expect(row1Cells[2].textContent).toBe('19:03 on Mar 31, 2024');
})

it('should render "No template history available" when no data is available', () => {
(useTemplateVersionsQuery as jest.Mock).mockReturnValue({
loading: false,
data: { templateVersions: [] },
});

render(<TemplateHistory />);
expect(screen.getByText('No template history available.')).toBeInTheDocument();
});

it('should pass axe accessibility test', async () => {
const { container } = render(
<TemplateHistory />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
})
});
10 changes: 10 additions & 0 deletions app/template/[templateId]/history/history.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@


.historyVersion {
margin-right: 10px;
}

.changeLog {
color: var(--gray-500);
font-size: 0.75rem;
}
Loading

0 comments on commit 377176d

Please sign in to comment.