Skip to content

Commit 5155545

Browse files
authored
Core 1268 review portal routing and tests (#2784)
* fixed portal/adoption * Fix coverage on vertical-list * Port portal-page-routes; code coverage for rex-portal * Coverage for contexts/portal * test coverage for page-routes and portal-page-routes * Quiet Memory Router and a couple lint issues * Coverage for use-link-handler * Page-loaders * Remove piTracker test from shell * Reorder tests to avoid flaky failure
1 parent bb0ac13 commit 5155545

38 files changed

+373
-335
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
"setupFiles": [
134134
"<rootDir>/test/setupFile.js"
135135
],
136+
"maxWorkers": "60%",
136137
"modulePathIgnorePatterns": [
137138
"package.json"
138139
],

src/app/components/shell/router-helpers/page-loaders.js

Lines changed: 0 additions & 78 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import React, {useEffect} from 'react';
2+
import {useLocation} from 'react-router-dom';
3+
import loadable from 'react-loadable';
4+
import LoadingPlaceholder from '~/components/loading-placeholder/loading-placeholder';
5+
import useLayoutContext from '~/contexts/layout';
6+
7+
function useAnalyticsPageView() {
8+
const location = useLocation();
9+
const isRedirect = location.state?.redirect;
10+
11+
useEffect(() => {
12+
window.scrollTo(0, 0);
13+
}, [isRedirect]);
14+
}
15+
16+
function usePage(name: string) {
17+
return React.useMemo(() => {
18+
return loadable({
19+
loader: () => import(`~/pages/${name}/${name}`),
20+
loading: LoadingPlaceholder,
21+
render(loaded, props: object) {
22+
const Component = loaded.default;
23+
24+
return <Component {...props} />;
25+
}
26+
});
27+
}, [name]);
28+
}
29+
30+
export function ImportedPage({name}: {name: string}) {
31+
const {pathname} = useLocation();
32+
const Page = usePage(name);
33+
const {layoutParameters, setLayoutParameters} = useLayoutContext();
34+
35+
if (layoutParameters.name === null) {
36+
setLayoutParameters();
37+
}
38+
39+
useAnalyticsPageView();
40+
41+
// Scroll to the top when the pathname changes
42+
// (Avoids scrolling when going to a new tab)
43+
useEffect(() => window.scrollTo(0, 0), [name, pathname]);
44+
45+
return <Page />;
46+
}

src/app/components/shell/router-helpers/page-routes.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ export function DetailsRoutes() {
5454
);
5555
}
5656

57-
// eslint-disable-next-line complexity
5857
export function OtherPageRoutes() {
5958
const dir = assertDefined(useParams().dir);
6059
const {'*': path} = useParams();
@@ -79,25 +78,27 @@ export function OtherPageRoutes() {
7978
}
8079

8180
// Some pages have no page data in the CMS!
82-
if (
83-
[
84-
'adopters',
85-
'adoption',
86-
'blog',
87-
'campaign',
88-
'confirmation',
89-
'institutional-partnership-application',
90-
'interest',
91-
'renewal-form',
92-
'separatemap'
93-
].includes(dir)
94-
) {
81+
if (isNoDataPage(dir)) {
9582
return <ImportedPage name={dir} />;
9683
}
9784

9885
return <RouteAsPortalOrNot />;
9986
}
10087

88+
export function isNoDataPage(dir: string) {
89+
return [
90+
'adopters',
91+
'adoption',
92+
'blog',
93+
'campaign',
94+
'confirmation',
95+
'institutional-partnership-application',
96+
'interest',
97+
'renewal-form',
98+
'separatemap'
99+
].includes(dir);
100+
}
101+
101102
// There are a couple of pages whose names in the CMS don't match their osweb urls
102103
const mismatch: Record<string, string> = {
103104
press: 'news',

src/app/components/shell/router-helpers/portal-page-routes.js renamed to src/app/components/shell/router-helpers/portal-page-routes.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
usePageDataFromRoute,
1212
FlexPageUsingItsOwnLayout,
1313
NonFlexPageUsingDefaultLayout,
14-
DetailsRoutes
14+
DetailsRoutes,
15+
isNoDataPage
1516
} from './page-routes';
1617
import {assertDefined} from '~/helpers/data';
1718
import {ImportedPage} from './page-loaders';
@@ -30,16 +31,26 @@ export function RouteAsPortalOrNot() {
3031
}
3132

3233
const isFlex = !hasError && isFlexPage(data);
33-
const isPortal = isFlex && data.layout[0].type === 'landing';
34+
const isPortal = isFlex && data.layout[0]?.type === 'landing';
3435

3536
if (isPortal) {
3637
if (portalPrefix !== `/${name}`) {
3738
setPortal(assertDefined(name));
3839
return null;
3940
}
41+
4042
if (!other) {
4143
return <FlexPageUsingItsOwnLayout data={data} />;
4244
}
45+
46+
if (isNoDataPage(other)) {
47+
return (
48+
<LayoutUsingData data={data}>
49+
<ImportedPage name={other} />
50+
</LayoutUsingData>
51+
);
52+
}
53+
4354
return (
4455
<LayoutUsingData data={data}>
4556
<Routes>
@@ -61,29 +72,20 @@ export function RouteAsPortalOrNot() {
6172
return <NonFlexPageUsingDefaultLayout data={data} />;
6273
}
6374

64-
// eslint-disable-next-line complexity
65-
export function PortalSubRoute() {
75+
function PortalSubRoute() {
6676
const {name, data, hasError} = usePageDataFromRoute();
6777

68-
if (!data) {
69-
return null;
70-
}
71-
7278
if (hasError) {
7379
return <Error404 />;
7480
}
7581

76-
const isFlex = !hasError && isFlexPage(data);
82+
if (isFlexPage(data)) {
83+
return <FlexPage data={assertDefined(data)} />;
84+
}
7785

78-
if (isFlex) {
79-
return <FlexPage data={data} />;
86+
if (data?.body) {
87+
return <GeneralPageFromSlug slug={`spike/${data?.meta.slug}`} />;
8088
}
81-
const isGeneral = Boolean(data?.body);
8289

83-
return isGeneral ? (
84-
<GeneralPageFromSlug slug={`spike/${data?.meta.slug}`} />
85-
) : (
86-
<ImportedPage name={name} />
87-
);
90+
return <ImportedPage name={assertDefined(name)} />;
8891
}
89-

src/app/helpers/rex-portal.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import usePortalContext from '~/contexts/portal';
22

3+
// This is about making TOC links to Rex work with a portal there.
4+
// Will probably need to be revisited.
35
export function useRexPortalLinkOrNot(link: string) {
46
const {portalPrefix} = usePortalContext();
57

test/src/components/book-selector.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import BookSelector, {
55
useSelectedBooks
66
} from '~/components/book-selector/book-selector';
77
import {useAfterSubmit} from '~/components/book-selector/after-form-submit';
8-
import {MemoryRouter} from 'react-router-dom';
8+
import MemoryRouter from '~/../../test/helpers/future-memory-router';
99
import {describe, it, expect} from '@jest/globals';
1010
import {LanguageContextProvider} from '~/contexts/language';
1111

test/src/components/loader-page.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import {render, screen} from '@testing-library/preact';
33
import { LoadedPage } from '~/components/jsx-helpers/loader-page';
4-
import {MemoryRouter} from 'react-router-dom';
4+
import MemoryRouter from '~/../../test/helpers/future-memory-router';
55

66
describe('loader-page', () => {
77
// The rest of the code is exercised in other tests.

test/src/components/role-selector.test.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,20 @@ describe('role-selector', () => {
4747
expect(options[0].getAttribute('aria-selected')).toBe('false');
4848
await user.keyboard('{Enter}');
4949
expect(options[0].getAttribute('aria-selected')).toBe('true');
50+
listbox.focus();
5051
await user.keyboard('{Escape}');
5152
// Select by space
53+
listbox.focus();
5254
await user.keyboard('{ArrowDown} ');
53-
const i = options.findIndex((o) => o.getAttribute('aria-selected') === 'true');
55+
const i = options.findIndex(
56+
(o) => o.getAttribute('aria-selected') === 'true'
57+
);
5458

5559
expect(i).toBe(1);
60+
// Select by mouse
61+
listbox.focus();
62+
// fireEvent.mouseEnter(options[1]);
63+
await user.click(options[1]);
64+
expect(options[1].getAttribute('aria-selected')).toBe('true');
5665
});
5766
});

test/src/components/search-bar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import {describe, it, expect} from '@jest/globals';
33
import {render, screen, fireEvent} from '@testing-library/preact';
4-
import {MemoryRouter} from 'react-router-dom';
4+
import MemoryRouter from '~/../../test/helpers/future-memory-router';
55
import SearchBar from '~/components/search-bar/search-bar';
66

77
describe('search-bar', () => {

0 commit comments

Comments
 (0)