Skip to content

Commit 0698ec6

Browse files
committed
Tests (and adjustments)
1 parent ff02d38 commit 0698ec6

File tree

7 files changed

+136
-74
lines changed

7 files changed

+136
-74
lines changed

src/app/helpers/errata.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ export function approvedStatuses(created: string, corrected: string | null) {
5050
};
5151
}
5252

53+
export type DisplayStatusValue = 'Reviewed' | 'In Review' | 'Duplicate' | 'No Correction' | 'Will Correct';
54+
5355
export function getDisplayStatus(data?: Errata) {
5456
const result = {
55-
status: 'Reviewed',
57+
status: 'Reviewed' as DisplayStatusValue,
5658
barStatus: ''
5759
};
5860

src/app/pages/errata-summary/errata-summary.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const radioItems = [
1919
];
2020

2121
function ErrataSummary({data, book}: ErrataSummaryProps) {
22-
const initialValue: string = window.location.hash.replace('#', '');
22+
const initialValue = window.location.hash.replace('#', '');
2323
const [selectedFilter, setselectedFilter] = useState<string>(initialValue);
2424
const onChange = React.useCallback(
2525
(newlySelectedValue: string) => {
@@ -54,14 +54,18 @@ function ErrataSummary({data, book}: ErrataSummaryProps) {
5454
}
5555

5656
export default function ErrataSummaryLoader() {
57-
const book: string | null = new window.URLSearchParams(window.location.search).get('book');
58-
const slug: string = `errata/?book_title=${book}` +
57+
const book = new window.URLSearchParams(window.location.search).get('book');
58+
59+
if (!book) {
60+
return <div>No book or errata ID selected</div>;
61+
}
62+
const slug = `errata/?book_title=${book}` +
5963
'&is_assessment_errata__not=Yes&archived=False&status__not=New' +
6064
'&status__not=OpenStax%20Editorial%20Review';
6165

6266
return (
6367
<main className="errata-summary page">
64-
<LoaderPage slug={slug} Child={ErrataSummary} props={{book: book || ''}} />
68+
<LoaderPage slug={slug} Child={ErrataSummary} props={{book}} />
6569
</main>
6670
);
6771
}

src/app/pages/errata-summary/hero/hero.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, {useState, useEffect} from 'react';
22
import RawHTML from '~/components/jsx-helpers/raw-html';
3+
import {assertNotNull} from '~/helpers/data';
34
import LoaderPage from '~/components/jsx-helpers/loader-page';
45
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
56
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle';
@@ -49,37 +50,38 @@ function useBookInfo(book: string): [string, string] {
4950
return info;
5051
}
5152

52-
const middle: string = '-135';
53-
const margin: number = 3;
53+
const middle = -135;
54+
const margin = 3;
5455

5556
function shiftIntoView(
5657
ref: React.RefObject<HTMLDivElement>,
57-
leftOffset: number | string,
58-
setLeftOffset: (value: number | string) => void
58+
leftOffset: number,
59+
setLeftOffset: (value: number) => void
5960
) {
60-
if (!ref.current) {return;}
61+
const poptipEl = assertNotNull(ref.current);
6162

62-
const {left, right} = ref.current.getBoundingClientRect();
63-
const pageElement = ref.current.closest('.page');
64-
65-
if (!pageElement) {return;}
63+
const {left, right} = poptipEl.getBoundingClientRect();
64+
const pageElement = assertNotNull(poptipEl.closest('.page'));
6665

6766
const {right: pageRight} = pageElement.getBoundingClientRect();
6867
const overRight = right - pageRight + margin;
6968
const overLeft = margin - left;
70-
const leftOffsetNum = typeof leftOffset === 'string' ? parseInt(leftOffset, 10) : leftOffset;
71-
const rightWants = Math.min(parseInt(middle, 10), leftOffsetNum - overRight);
72-
const leftWants = Math.max(rightWants, leftOffsetNum + overLeft);
69+
const rightWants = Math.min(middle, leftOffset - overRight);
70+
const leftWants = Math.max(rightWants, leftOffset + overLeft);
7371

7472
setLeftOffset(leftWants);
7573
}
7674

7775
function usePopTipStyle(isOpen: boolean) {
7876
const ref = React.useRef<HTMLDivElement>(null);
79-
const [leftOffset, setLeftOffset] = React.useState<number | string>(middle);
77+
const [leftOffset, setLeftOffset] = React.useState<number>(middle);
8078

8179
useEffect(
82-
() => shiftIntoView(ref, leftOffset, setLeftOffset),
80+
() => {
81+
if (isOpen) {
82+
shiftIntoView(ref, leftOffset, setLeftOffset);
83+
}
84+
},
8385
[isOpen, leftOffset]
8486
);
8587

@@ -103,12 +105,10 @@ function PopTip({html, isOpen}: PopTipProps) {
103105

104106
function usePopTipState() {
105107
const [isOpen, setIsOpen] = React.useState<boolean>(false);
108+
const activate = React.useCallback(() => setIsOpen(true), []);
109+
const deactivate = React.useCallback(() => setIsOpen(false), []);
106110

107-
return {
108-
isOpen,
109-
activate(): void {setIsOpen(true);},
110-
deactivate(): void {setIsOpen(false);}
111-
};
111+
return {isOpen, activate, deactivate};
112112
}
113113

114114
function HeroContent({data}: HeroContentProps) {
@@ -137,15 +137,15 @@ function HeroContent({data}: HeroContentProps) {
137137
export default function Hero({book}: HeroProps) {
138138
const [slug, title] = useBookInfo(book);
139139

140-
if (!slug) {
141-
return null;
142-
}
143140
return (
144141
<div className="hero">
145-
<div className="text-area">
146-
<h1>{title} Errata</h1>
147-
<LoaderPage slug="pages/errata" Child={HeroContent} />
148-
</div>
142+
{slug ?
143+
<div className="text-area">
144+
<h1>{title} Errata</h1>
145+
<LoaderPage slug="pages/errata" Child={HeroContent} />
146+
</div> :
147+
null
148+
}
149149
</div>
150150
);
151151
}

src/app/pages/errata-summary/table/table.tsx

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, {useState} from 'react';
22
import {treatSpaceOrEnterAsClick} from '~/helpers/events';
3-
import {getDisplayStatus, Errata} from '~/helpers/errata';
3+
import {getDisplayStatus, Errata, DisplayStatusValue} from '~/helpers/errata';
44
import './table.scss';
55

66
type ProcessedErrataItem = {
@@ -114,36 +114,29 @@ const statusSortOrder: {[key: string]: number} = {
114114
const sortFunctions = {
115115
sortDate: (a: string, b: string): number => new Date(a).getTime() - new Date(b).getTime(),
116116
sort: (a: string | null, b: string | null): number => {
117-
const as = a === null ? '' : a;
118-
const bs = b === null ? '' : b;
117+
const as = a ?? '';
118+
const bs = b ?? '';
119119

120120
return as.localeCompare(bs, 'en', {sensitivity: 'base'});
121121
},
122122
sortNumber: (a: number | string, b: number | string): number => Number(a) - Number(b),
123-
sortDecision: (a: ProcessedErrataItem, b: ProcessedErrataItem): number => {
124-
const ar = statusSortOrder[a.displayStatus.substr(0, 2)] || 6;
125-
const br = statusSortOrder[b.displayStatus.substr(0, 2)] || 6;
123+
sortDecision: (a: DisplayStatusValue, b: DisplayStatusValue): number => {
124+
const ar = statusSortOrder[a.substring(0, 2)];
125+
const br = statusSortOrder[b.substring(0, 2)];
126126

127-
if (ar !== br) {
128-
return br - ar;
129-
}
130-
const ad = new Date(a.modified).valueOf();
131-
const bd = new Date(b.modified).valueOf();
132-
133-
return bd - ad;
127+
return br - ar;
134128
}
135129
};
136130

137131
function DesktopHeaderColumn({colSpec, sortController}: DesktopHeaderColumnProps): React.ReactElement {
138132
const {sortKey, sortDir, setSortFn, setSortDir, setSortKey} = sortController;
139133
const sortable = 'sortFn' in colSpec;
140-
const onClick = (): void => {
134+
const onClick = () => {
141135
if (sortKey === colSpec.id) {
142136
setSortDir(-sortDir);
143137
} else {
144-
if (sortable) {
145-
setSortFn(colSpec.sortFn);
146-
}
138+
// @ts-expect-error onClick is only used when sortable
139+
setSortFn(colSpec.sortFn);
147140
setSortKey(colSpec.id);
148141
setSortDir(1);
149142
}
@@ -189,14 +182,14 @@ function DesktopDataColumn({colSpec, entry}: DesktopDataColumnProps): React.Reac
189182
<div className={colSpec.cssClass}>
190183
{
191184
colSpec.id === 'id' ?
192-
<a href={entry[colSpec.id as keyof ProcessedErrataItem] as string}>
193-
{entry[colSpec.id as keyof ProcessedErrataItem] || ''}
185+
<a href={entry[colSpec.id]}>
186+
{entry[colSpec.id]}
194187
</a> :
195188
<React.Fragment>
196-
{entry[colSpec.id as keyof ProcessedErrataItem]}{' '}
189+
{entry[colSpec.id]}{' '}
197190
{
198191
colSpec.id === 'displayStatus' &&
199-
entry[colSpec.id as keyof ProcessedErrataItem] === 'No Correction' &&
192+
entry[colSpec.id] === 'No Correction' &&
200193
<a href={`/errata/${entry.id}`}>Details</a>
201194
}
202195
</React.Fragment>
@@ -228,10 +221,10 @@ function DesktopTable({data}: DesktopTableProps): React.ReactElement {
228221
const sortController = useSortController();
229222
const {sortFn, sortKey, sortDir} = sortController;
230223

231-
const sortedData = [...data] as Array<string & ProcessedErrataItem>;
224+
const sortedData = [...data];
232225

233226
sortedData.sort((a, b) =>
234-
// @ts-expect-error sortKey and sortFn are guaranteed compatible
227+
// @ts-expect-error sortKey is guaranteed compatible with sortFn
235228
sortFunctions[sortFn](a[sortKey], b[sortKey])
236229
);
237230
if (sortDir < 0) {
@@ -258,8 +251,8 @@ function MobileRow({entry, label, columnId}: MobileRowProps): React.ReactElement
258251
<div>
259252
{
260253
columnId === 'id' ?
261-
<a href={entry[columnId as keyof ProcessedErrataItem] as string}>
262-
{entry[columnId as keyof ProcessedErrataItem] || ''}
254+
<a href={entry[columnId]}>
255+
{entry[columnId]}
263256
</a> :
264257
(entry[columnId as keyof ProcessedErrataItem] || '')
265258
}
@@ -297,7 +290,7 @@ function MobileTables({data}: MobileTablesProps): React.ReactElement {
297290
}
298291

299292
function matchesFilter(filter: string, item: ProcessedErrataItem): boolean {
300-
const status = item.displayStatus;
293+
const status = item.displayStatus as string;
301294

302295
switch (filter) {
303296
case '':

test/src/components/shell.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ describe('shell', () => {
178178
));
179179

180180
render(AppElement);
181-
await screen.findByRole('radio', {name: 'In Review'});
181+
await screen.findByText('No book or errata ID selected');
182182
});
183183
it('routes "details" paths (top level routes to Subjects)', async () => {
184184
BrowserRouter.mockImplementationOnce(({children}) => (

test/src/data/errata-book.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ export default [
447447
"short_detail": "The solution for the question: \"June needs 48 gallons of punch for a party and ...",
448448
"resolution_date": "2017-09-06",
449449
"resolution_notes": "Revise the solution to exercise 202 as follows:\r\n\r\n\"The smaller cooler holds 8 gallons and the bigger cooler holds 40 gallons.\"",
450-
"error_type": "Incorrect calculation or solution",
450+
"error_type": "Other",
451451
"error_type_other": null,
452452
"resource": "Student solution manual",
453453
"resource_other": null,
@@ -1169,8 +1169,8 @@ export default [
11691169
"resolution_notes": "Revise Example 5.57 as follows:\r\n\r\n\"Christy sells her photographs at a booth at a street fair. At the start of the day, she wants to have at least 25 photos to display at her booth...\"",
11701170
"error_type": "Typo",
11711171
"error_type_other": null,
1172-
"resource": "Textbook",
1173-
"resource_other": null,
1172+
"resource": "Other",
1173+
"resource_other": "Another",
11741174
"submitted_by_account_id": 147546,
11751175
"file_1": null,
11761176
"file_2": null
@@ -1193,7 +1193,7 @@ export default [
11931193
"resolution_notes": "Revise Exercise 220 as follows:\r\n\r\n\"Darrin is hanging 200 feet of Christmas garland on the three sides of fencing that enclose his rectangular front yard. The length, the side along the house, is five feet less than three times the width. Find the length and width of the fencing.\"",
11941194
"error_type": "Typo",
11951195
"error_type_other": null,
1196-
"resource": "Textbook",
1196+
"resource": "Other",
11971197
"resource_other": null,
11981198
"submitted_by_account_id": 147546,
11991199
"file_1": null,

0 commit comments

Comments
 (0)