Skip to content

Commit

Permalink
Merge pull request #200 from adhocteam/kw-add-pagination
Browse files Browse the repository at this point in the history
Add sorting and pagination to the main reports table
  • Loading branch information
kryswisnaskas authored Mar 10, 2021
2 parents 280bf8f + eb6cbf7 commit bd830f9
Show file tree
Hide file tree
Showing 18 changed files with 1,111 additions and 99 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"react-hook-form": "^6.15.0",
"react-idle-timer": "^4.4.2",
"react-input-autosize": "^3.0.0",
"react-js-pagination": "^3.0.3",
"react-responsive": "^8.1.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
Expand Down
2 changes: 2 additions & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/logo64.png" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/fetchers/activityReports.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ export const getReport = async (reportId) => {
return report.json();
};

export const getReports = async () => {
const reports = await get(activityReportUrl);
export const getReports = async (sortBy = 'updatedAt', sortDir = 'desc', offset = 0, limit = 10) => {
const reports = await get(`${activityReportUrl}?sortBy=${sortBy}&sortDir=${sortDir}&offset=${offset}&limit=${limit}`);
return reports.json();
};

Expand Down
Binary file added frontend/src/images/blue-circle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
235 changes: 226 additions & 9 deletions frontend/src/pages/Landing/__tests__/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import '@testing-library/jest-dom';
import React from 'react';
import {
render, screen,
render, screen, fireEvent, waitFor,
} from '@testing-library/react';
import { MemoryRouter } from 'react-router';
import fetchMock from 'fetch-mock';

import UserContext from '../../../UserContext';
import Landing from '../index';
import activityReports from '../mocks';
import activityReports, { activityReportsSorted, generateXFakeReports } from '../mocks';

const renderLanding = (user) => {
render(
Expand All @@ -22,7 +22,10 @@ const renderLanding = (user) => {

describe('Landing Page', () => {
beforeEach(() => {
fetchMock.get('/api/activity-reports', activityReports);
fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10',
{ count: 2, rows: activityReports },
);
fetchMock.get('/api/activity-reports/alerts', []);
const user = {
name: '[email protected]',
Expand Down Expand Up @@ -133,7 +136,7 @@ describe('Landing Page', () => {
test('displays the correct last saved dates', async () => {
const lastSavedDates = await screen.findAllByText(/02\/04\/2021/i);

expect(lastSavedDates.length).toBe(2);
expect(lastSavedDates.length).toBe(1);
});

test('displays the correct statuses', async () => {
Expand All @@ -145,9 +148,11 @@ describe('Landing Page', () => {
});

test('displays the options buttons', async () => {
const optionButtons = await screen.findAllByRole('button', /.../i);
const optionButtons = await screen.findAllByRole('button', {
name: /edit activity report r14-ar-2/i,
});

expect(optionButtons.length).toBe(2);
expect(optionButtons.length).toBe(1);
});

test('displays the new activity report button', async () => {
Expand All @@ -157,6 +162,212 @@ describe('Landing Page', () => {
});
});

describe('Landing Page sorting', () => {
afterEach(() => fetchMock.restore());

beforeEach(() => {
fetchMock.get('/api/activity-reports/alerts', []);
fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10',
{ count: 2, rows: activityReports },
);
const user = {
name: '[email protected]',
permissions: [
{
scopeId: 3,
regionId: 1,
},
],
};

renderLanding(user);
});

it('clicking status column header will sort by status', async () => {
const statusColumnHeader = await screen.findByText(/status/i);
fetchMock.reset();
fetchMock.get('/api/activity-reports/alerts', []);
fetchMock.get(
'/api/activity-reports?sortBy=status&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(statusColumnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[6]).toHaveTextContent(/needs action/i));
await waitFor(() => expect(screen.getAllByRole('cell')[14]).toHaveTextContent(/draft/i));

fetchMock.get(
'/api/activity-reports?sortBy=status&sortDir=desc&offset=0&limit=10',
{ count: 2, rows: activityReports },
);

fireEvent.click(statusColumnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[6]).toHaveTextContent(/draft/i));
await waitFor(() => expect(screen.getAllByRole('cell')[14]).toHaveTextContent(/needs action/i));
});

it('clicking Last saved column header will sort by updatedAt', async () => {
const columnHeader = await screen.findByText(/last saved/i);

fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[5]).toHaveTextContent(/02\/04\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[13]).toHaveTextContent(/02\/05\/2021/i));
});

it('clicking Collaborators column header will sort by collaborators', async () => {
const columnHeader = await screen.findByText(/collaborator\(s\)/i);

fetchMock.get(
'/api/activity-reports?sortBy=collaborators&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[4]).toHaveTextContent('Cucumber User, GSHermione Granger, SS'));
await waitFor(() => expect(screen.getAllByRole('cell')[12]).toHaveTextContent('Orange, GSHermione Granger, SS'));
});

it('clicking Topics column header will sort by topics', async () => {
const columnHeader = await screen.findByText(/topic\(s\)/i);

fetchMock.get(
'/api/activity-reports?sortBy=topics&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[3]).toHaveTextContent(''));
await waitFor(() => expect(screen.getAllByRole('cell')[11]).toHaveTextContent('Behavioral / Mental HealthCLASS: Instructional Support'));
});

it('clicking Creator column header will sort by author', async () => {
const columnHeader = await screen.findByText(/creator/i);

fetchMock.get(
'/api/activity-reports?sortBy=author&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[2]).toHaveTextContent('Kiwi, GS'));
await waitFor(() => expect(screen.getAllByRole('cell')[10]).toHaveTextContent('Kiwi, TTAC'));
});

it('clicking Start date column header will sort by start date', async () => {
const columnHeader = await screen.findByText(/start date/i);

fetchMock.get(
'/api/activity-reports?sortBy=startDate&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[1]).toHaveTextContent('02/01/2021'));
await waitFor(() => expect(screen.getAllByRole('cell')[9]).toHaveTextContent('02/08/2021'));
});

it('clicking Grantee column header will sort by grantee', async () => {
const columnHeader = await screen.findByRole('button', {
name: /grantee\. activate to sort ascending/i,
});

fetchMock.get(
'/api/activity-reports?sortBy=activityRecipients&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('cell')[0]).toHaveTextContent('Johnston-RomagueraJohnston-RomagueraGrantee Name'));
});

it('clicking Report id column header will sort by region and id', async () => {
const columnHeader = await screen.findByText(/report id/i);

fetchMock.get(
'/api/activity-reports?sortBy=regionId&sortDir=asc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(columnHeader);
await waitFor(() => expect(screen.getAllByRole('link')[4]).toHaveTextContent('R14-AR-2'));
await waitFor(() => expect(screen.getAllByRole('link')[5]).toHaveTextContent('R14-AR-1'));
});

it('Pagination links are visible', async () => {
const prevLink = await screen.findByRole('link', {
name: /go to previous page/i,
});
const pageOne = await screen.findByRole('link', {
name: /go to page number 1/i,
});
const nextLink = await screen.findByRole('link', {
name: /go to next page/i,
});

expect(prevLink).toBeVisible();
expect(pageOne).toBeVisible();
expect(nextLink).toBeVisible();
});

it('clicking on pagination page works', async () => {
const pageOne = await screen.findByRole('link', {
name: /go to page number 1/i,
});
fetchMock.reset();
fetchMock.get('/api/activity-reports/alerts', []);
fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10',
{ count: 2, rows: activityReportsSorted },
);

fireEvent.click(pageOne);
await waitFor(() => expect(screen.getAllByRole('cell')[5]).toHaveTextContent(/02\/05\/2021/i));
await waitFor(() => expect(screen.getAllByRole('cell')[13]).toHaveTextContent(/02\/04\/2021/i));
});

it('clicking on the second page updates to, from and total', async () => {
expect(generateXFakeReports(10).length).toBe(10);
await screen.findByRole('link', {
name: /go to page number 1/i,
});
fetchMock.reset();
fetchMock.get('/api/activity-reports/alerts', []);
fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10',
{ count: 17, rows: generateXFakeReports(10) },
);
const user = {
name: '[email protected]',
permissions: [
{
scopeId: 3,
regionId: 1,
},
],
};

renderLanding(user);

const pageTwo = await screen.findByRole('link', {
name: /go to page number 2/i,
});

fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=10&limit=10',
{ count: 17, rows: generateXFakeReports(10) },
);

fireEvent.click(pageTwo);
await waitFor(() => expect(screen.getByText(/11-17 of 17/i)).toBeVisible());
});
});

describe('Landing Page error', () => {
afterEach(() => fetchMock.restore());

Expand All @@ -165,7 +376,7 @@ describe('Landing Page error', () => {
});

it('handles errors by displaying an error message', async () => {
fetchMock.get('/api/activity-reports', 500);
fetchMock.get('/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10', 500);
const user = {
name: '[email protected]',
permissions: [
Expand All @@ -182,7 +393,10 @@ describe('Landing Page error', () => {
});

it('displays an empty row if there are no reports', async () => {
fetchMock.get('/api/activity-reports', []);
fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10',
{ count: 0, rows: [] },
);
const user = {
name: '[email protected]',
permissions: [
Expand All @@ -200,7 +414,10 @@ describe('Landing Page error', () => {
});

it('does not displays new activity report button without permission', async () => {
fetchMock.get('/api/activity-reports', activityReports);
fetchMock.get(
'/api/activity-reports?sortBy=updatedAt&sortDir=desc&offset=0&limit=10',
{ count: 2, rows: activityReports },
);
const user = {
name: '[email protected]',
permissions: [
Expand Down
Loading

0 comments on commit bd830f9

Please sign in to comment.