From 8e6f6323a8ca3e77409d1375dd89f462ab1c926e Mon Sep 17 00:00:00 2001 From: Roy Johnson Date: Mon, 3 Jun 2024 14:50:39 -0500 Subject: [PATCH 01/11] Link accessible stylesheet for Osano (#2224) * Link accessible stylesheet for Osano [DISCO-238] * Get all osano styling from RAM --------- Co-authored-by: staxly[bot] <35789409+staxly[bot]@users.noreply.github.com> --- public/index.html | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/public/index.html b/public/index.html index f544983b2d..55b1aab72f 100644 --- a/public/index.html +++ b/public/index.html @@ -10,24 +10,7 @@ --> - - - + From 5d40b5e9afa9751a363ed4c1c74b8568b0fd2920 Mon Sep 17 00:00:00 2001 From: Dante Soares Date: Mon, 3 Jun 2024 15:39:48 -0500 Subject: [PATCH 02/11] Removed fleet tag specifications (#2250) --- script/prerender/cfn.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/script/prerender/cfn.yml b/script/prerender/cfn.yml index d471186fe2..d858fc524d 100644 --- a/script/prerender/cfn.yml +++ b/script/prerender/cfn.yml @@ -20,17 +20,17 @@ Parameters: ConstraintDescription: Must be a valid Rex code version PublicUrl: - Description: Public URL to use, for example "/rex/releases/${ReleaseId}" + Description: Public URL to use, for example "/rex/releases/ReleaseId" Type: String ConstraintDescription: Must be a path starting with / ReleaseId: - Description: Release ID to use, for example "v4/${someHash}" + Description: Release ID to use, for example "v4/someHash" Type: String ConstraintDescription: Must be a valid Rex Release ID ImageTag: - Description: Prerender Docker container image tag, for example "v4-${someHash}" + Description: Prerender Docker container image tag, for example "v4-someHash" Type: String AllowedPattern: ^[_0-9A-Za-z][-_.0-9A-Za-z]{0,127}$ ConstraintDescription: >- @@ -198,12 +198,6 @@ Resources: Tags: - Key: Name Value: !Sub ${AWS::StackName}-fleet - - Key: Project - Value: Unified - - Key: Application - Value: Rex Prerender - - Key: Environment - Value: production TargetCapacitySpecification: DefaultTargetCapacityType: spot TotalTargetCapacity: 8 From 385a2bc20f3d1a1f7cbec19fb181bccc4f9041f8 Mon Sep 17 00:00:00 2001 From: Roy Johnson Date: Tue, 4 Jun 2024 07:37:04 -0500 Subject: [PATCH 03/11] [DISCO-146] Fix colorpicker focus (#2201) Co-authored-by: staxly[bot] <35789409+staxly[bot]@users.noreply.github.com> Co-authored-by: Malar-Natarajan <40276461+Malar-Natarajan@users.noreply.github.com> --- .../components/ColorPicker.spec.tsx | 2 +- .../highlights/components/ColorPicker.tsx | 22 ++++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/app/content/highlights/components/ColorPicker.spec.tsx b/src/app/content/highlights/components/ColorPicker.spec.tsx index 3780cb5d16..9d7696ac2d 100644 --- a/src/app/content/highlights/components/ColorPicker.spec.tsx +++ b/src/app/content/highlights/components/ColorPicker.spec.tsx @@ -89,7 +89,7 @@ describe('ColorPicker', () => { const onRemove = jest.fn(); const {root} = renderToDom( - + ); const rg = root.querySelector('[role="radiogroup"]') as HTMLDivElement; diff --git a/src/app/content/highlights/components/ColorPicker.tsx b/src/app/content/highlights/components/ColorPicker.tsx index efb0a1110a..68001ab28c 100644 --- a/src/app/content/highlights/components/ColorPicker.tsx +++ b/src/app/content/highlights/components/ColorPicker.tsx @@ -104,22 +104,18 @@ const ColorPicker = ({className, ...props}: Props) => { }, [] ); - const initialFocus = React.useCallback( - (event: React.FocusEvent) => { - if (!ref.current || event.currentTarget !== event.target) { - return; - } - const firstChecked = ref.current.querySelector('input[checked]'); - - if (firstChecked) { - firstChecked.focus(); - } else { - ref.current.querySelector('input')?.focus(); + const color = (props as SingleSelectProps).color; + const focusOnSelected = React.useCallback( + () => { + if (color && document?.activeElement === ref.current) { + ref.current?.querySelector(`input[name="${color}"]`)?.focus(); } }, - [] + [color] ); + React.useEffect(focusOnSelected, [focusOnSelected]); + return (
{ aria-label='colors' ref={ref} onKeyDown={handleKeyNavigation} - onFocus={initialFocus} + onFocus={focusOnSelected} > {highlightStyles.map((style) => Date: Tue, 4 Jun 2024 13:51:04 -0500 Subject: [PATCH 04/11] Add live region for navigation changes (#2214) * Add live region for navigation changes [DISCO-187] * Simplify! * Update PageTitleConfirmation.tsx * Get page title from store Skip announcing initial page title * Use title selector --------- Co-authored-by: Malar-Natarajan <40276461+Malar-Natarajan@users.noreply.github.com> --- src/app/components/Layout.tsx | 2 + .../components/PageTitleConfirmation.spec.tsx | 33 +++++++++++++++ src/app/components/PageTitleConfirmation.tsx | 38 ++++++++++++++++++ .../__snapshots__/Content.spec.tsx.snap | 40 +++++++++++++++++++ .../__snapshots__/Home.spec.tsx.snap | 20 ++++++++++ src/app/theme.ts | 12 ++++++ 6 files changed, 145 insertions(+) create mode 100644 src/app/components/PageTitleConfirmation.spec.tsx create mode 100644 src/app/components/PageTitleConfirmation.tsx diff --git a/src/app/components/Layout.tsx b/src/app/components/Layout.tsx index 7d7d440819..2613a8d908 100644 --- a/src/app/components/Layout.tsx +++ b/src/app/components/Layout.tsx @@ -6,11 +6,13 @@ import theme from '../theme'; import AccessibilityButtonsWrapper from './AccessibilityButtonsWrapper'; import NavBar from './NavBar'; import OnEsc from './OnEsc'; +import PageTitleConfirmation from './PageTitleConfirmation'; // tslint:disable-next-line:variable-name const Layout: SFC = ({ children }) => + {children} diff --git a/src/app/components/PageTitleConfirmation.spec.tsx b/src/app/components/PageTitleConfirmation.spec.tsx new file mode 100644 index 0000000000..ad2be45612 --- /dev/null +++ b/src/app/components/PageTitleConfirmation.spec.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { renderToDom } from '../../test/reactutils'; +// import { act } from 'react-dom/test-utils'; +import { initialState } from '../reducer'; +import createTestStore from '../../test/createTestStore'; +import PageTitleConfirmation from './PageTitleConfirmation'; +import TestContainer from '../../test/TestContainer'; +import { setHead } from '../head/actions'; + +describe('PageTitleConfirmation', () => { + it('skips blank, skips first non-blank, announces subsequent', async() => { + const state = { + ...initialState, + }; + + state.head.title = 'initial'; + const store = createTestStore(state); + + store.dispatch(setHead({...initialState.head, title: ''})); + const component = renderToDom( + + + + ); + + expect(component.node.textContent).toBe(''); + store.dispatch(setHead({...initialState.head, title: 'initial'})); + expect(component.node.textContent).toBe(''); + store.dispatch(setHead({...initialState.head, title: 'something'})); + expect(component.node.textContent).toBe('Loaded page something'); + component.unmount(); + }); +}); diff --git a/src/app/components/PageTitleConfirmation.tsx b/src/app/components/PageTitleConfirmation.tsx new file mode 100644 index 0000000000..0b990ff5fd --- /dev/null +++ b/src/app/components/PageTitleConfirmation.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { hiddenButAccessible } from '../theme'; +import { AppState } from '../types'; +import styled from 'styled-components'; +import { connect } from 'react-redux'; +import { title as titleSelector } from '../head/selectors'; + +function PageTitleConfirmation({ + className, + title, +}: { + className: string; + title: string; +}) { + const skipFirst = React.useRef(true); + const message = React.useMemo(() => { + if (!title) { + return ''; + } + if (skipFirst.current) { + skipFirst.current = false; + return ''; + } + return `Loaded page ${title}`; + }, [title]); + + return ( +
+ {message} +
+ ); +} + +export default connect((state: AppState) => ({title: titleSelector(state)}))(styled( + PageTitleConfirmation +)` + ${hiddenButAccessible} +`); diff --git a/src/app/content/components/__snapshots__/Content.spec.tsx.snap b/src/app/content/components/__snapshots__/Content.spec.tsx.snap index c26f60fa27..da08515acd 100644 --- a/src/app/content/components/__snapshots__/Content.spec.tsx.snap +++ b/src/app/content/components/__snapshots__/Content.spec.tsx.snap @@ -169,6 +169,26 @@ Array [ />
+ , + .c0 { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + +
+
, .c4 { display: inline-block; @@ -4867,6 +4887,26 @@ Array [ /> + , + .c0 { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + +
+
, .c4 { display: inline-block; diff --git a/src/app/developer/components/__snapshots__/Home.spec.tsx.snap b/src/app/developer/components/__snapshots__/Home.spec.tsx.snap index 2c81ba1cbf..4c095338a4 100644 --- a/src/app/developer/components/__snapshots__/Home.spec.tsx.snap +++ b/src/app/developer/components/__snapshots__/Home.spec.tsx.snap @@ -169,6 +169,26 @@ Array [ /> + , + .c0 { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip: rect(0,0,0,0); + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +} + +
+
, .c19 { display: inline-block; diff --git a/src/app/theme.ts b/src/app/theme.ts index c43ac98245..141ca5ffe8 100644 --- a/src/app/theme.ts +++ b/src/app/theme.ts @@ -9,6 +9,18 @@ export interface ColorSet { darkest?: string; } +export const hiddenButAccessible = ` + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + white-space: nowrap; + border: 0; +`; + const textColors = { black: '#000', default: '#424242', From d76615fc6537b8b454b2ea7c49ae394f97330d11 Mon Sep 17 00:00:00 2001 From: Roy Johnson Date: Thu, 6 Jun 2024 06:24:32 -0500 Subject: [PATCH 05/11] Use fieldset and legend for color picker (#2248) * Use fieldset and legend for color picker [DISCO-323] * Un-label fieldset --- .../components/ColorPicker.spec.tsx | 6 +++--- .../highlights/components/ColorPicker.tsx | 16 ++++++++++++---- .../__snapshots__/ContextMenu.spec.tsx.snap | 19 +++++++++++++++---- .../__snapshots__/ColorPicker.spec.tsx.snap | 19 +++++++++++++++---- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/app/content/highlights/components/ColorPicker.spec.tsx b/src/app/content/highlights/components/ColorPicker.spec.tsx index 9d7696ac2d..1b5c1d3123 100644 --- a/src/app/content/highlights/components/ColorPicker.spec.tsx +++ b/src/app/content/highlights/components/ColorPicker.spec.tsx @@ -4,7 +4,7 @@ import { renderToDom, dispatchKeyDownEvent } from '../../../../test/reactutils'; import TestContainer from '../../../../test/TestContainer'; import { highlightStyles } from '../../constants'; import ColorPicker from './ColorPicker'; -import { HTMLElement, HTMLDivElement, HTMLInputElement } from '@openstax/types/lib.dom'; +import { HTMLElement, HTMLFieldSetElement, HTMLInputElement } from '@openstax/types/lib.dom'; import { assertDocument } from '../../../utils'; describe('ColorPicker', () => { @@ -92,7 +92,7 @@ describe('ColorPicker', () => { ); - const rg = root.querySelector('[role="radiogroup"]') as HTMLDivElement; + const rg = root.querySelector('fieldset') as HTMLFieldSetElement; expect(rg).toBeTruthy(); rg?.focus(); @@ -148,7 +148,7 @@ describe('ColorPicker', () => { ); - const rg = root.querySelector('[role="radiogroup"]') as HTMLDivElement; + const rg = root.querySelector('fieldset') as HTMLFieldSetElement; expect(rg).toBeTruthy(); rg?.focus(); diff --git a/src/app/content/highlights/components/ColorPicker.tsx b/src/app/content/highlights/components/ColorPicker.tsx index 68001ab28c..415ae6f8c2 100644 --- a/src/app/content/highlights/components/ColorPicker.tsx +++ b/src/app/content/highlights/components/ColorPicker.tsx @@ -117,15 +117,14 @@ const ColorPicker = ({className, ...props}: Props) => { React.useEffect(focusOnSelected, [focusOnSelected]); return ( -
+ Choose highlight color {highlightStyles.map((style) => { ? props.onRemove ? props.onRemove() : null : props.onChange(style.label)} />)} -
+ ); }; export default styled(ColorPicker)` + border: 0; outline: none; display: flex; flex-direction: row; overflow: visible; gap: ${cardPadding}rem; padding: ${cardPadding}rem 0.3rem; + + legend { + position: absolute; + height: 1px; + width: 1px; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); + } `; diff --git a/src/app/content/highlights/components/SummaryPopup/__snapshots__/ContextMenu.spec.tsx.snap b/src/app/content/highlights/components/SummaryPopup/__snapshots__/ContextMenu.spec.tsx.snap index 6510de67d1..2511af78af 100644 --- a/src/app/content/highlights/components/SummaryPopup/__snapshots__/ContextMenu.spec.tsx.snap +++ b/src/app/content/highlights/components/SummaryPopup/__snapshots__/ContextMenu.spec.tsx.snap @@ -408,6 +408,7 @@ exports[`ContextMenu match snapshot when open 1`] = ` } .c14 { + border: 0; outline: none; display: -webkit-box; display: -webkit-flex; @@ -421,6 +422,15 @@ exports[`ContextMenu match snapshot when open 1`] = ` padding: 0.8rem 0.3rem; } +.c14 legend { + position: absolute; + height: 1px; + width: 1px; + overflow: hidden; + -webkit-clip: rect(1px,1px,1px,1px); + clip: rect(1px,1px,1px,1px); +} + .c4 { cursor: pointer; border: none; @@ -629,14 +639,15 @@ exports[`ContextMenu match snapshot when open 1`] = `
-
+ + Choose highlight color + -
+
    diff --git a/src/app/content/highlights/components/__snapshots__/ColorPicker.spec.tsx.snap b/src/app/content/highlights/components/__snapshots__/ColorPicker.spec.tsx.snap index 7a60c74b0e..087ebd073c 100644 --- a/src/app/content/highlights/components/__snapshots__/ColorPicker.spec.tsx.snap +++ b/src/app/content/highlights/components/__snapshots__/ColorPicker.spec.tsx.snap @@ -275,6 +275,7 @@ exports[`ColorPicker matches snapshot no selection 1`] = ` } .c0 { + border: 0; outline: none; display: -webkit-box; display: -webkit-flex; @@ -288,14 +289,24 @@ exports[`ColorPicker matches snapshot no selection 1`] = ` padding: 0.8rem 0.3rem; } -
    + + Choose highlight color + -
    + `; From 70d1c1e8d2094b8735cff745e87038497070eb9d Mon Sep 17 00:00:00 2001 From: Roy Johnson Date: Mon, 10 Jun 2024 06:55:54 -0500 Subject: [PATCH 06/11] Fix focus after go-to-top (#2244) * Fix focus after go-to-top [DISCO-308] * Same thing for MyHighlights --- .../highlights/components/HighlightsPopUp.tsx | 2 +- .../components/ShowMyHighlights.spec.tsx | 3 +- .../components/ShowMyHighlights.tsx | 2 ++ .../components/ShowStudyGuides.spec.tsx | 35 +++++++++---------- .../components/ShowStudyGuides.tsx | 3 +- .../components/StudyGuidesPopUp.tsx | 2 +- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/app/content/highlights/components/HighlightsPopUp.tsx b/src/app/content/highlights/components/HighlightsPopUp.tsx index 4912d7b57c..1a70cd4805 100644 --- a/src/app/content/highlights/components/HighlightsPopUp.tsx +++ b/src/app/content/highlights/components/HighlightsPopUp.tsx @@ -142,7 +142,7 @@ const HighlightsPopUp = ({ closeMyHighlights, ...props }: Props) => { - {props.user ? : } + {props.user ? : } : null; diff --git a/src/app/content/highlights/components/ShowMyHighlights.spec.tsx b/src/app/content/highlights/components/ShowMyHighlights.spec.tsx index 115475f97a..a2cc1e5697 100644 --- a/src/app/content/highlights/components/ShowMyHighlights.spec.tsx +++ b/src/app/content/highlights/components/ShowMyHighlights.spec.tsx @@ -267,8 +267,9 @@ describe('Show my highlights', () => { })); }); + const container = window.document.createElement('div'); const {root} = renderToDom( - + ); const target = root.querySelector('[data-testid="show-myhighlights-body"]'); diff --git a/src/app/content/highlights/components/ShowMyHighlights.tsx b/src/app/content/highlights/components/ShowMyHighlights.tsx index 6c9294786c..a806993c96 100644 --- a/src/app/content/highlights/components/ShowMyHighlights.tsx +++ b/src/app/content/highlights/components/ShowMyHighlights.tsx @@ -25,6 +25,7 @@ interface ShowMyHighlightsProps { loadMore: () => void; initMyHighlights: () => void; services: AppServices; + topElRef: React.RefObject; } class ShowMyHighlights extends Component { @@ -41,6 +42,7 @@ class ShowMyHighlights extends Component { window = assertWindow(); }); + function createComponent(container: HTMLElement) { + const ref: React.RefObject = {current: container}; + + return renderer.create( + + , { createNodeMock: () => container }); + } + it('doesn\'t request more if not at bottom', () => { const container = window.document.createElement('div'); const dispatch = jest.spyOn(store, 'dispatch'); @@ -30,9 +39,7 @@ describe('ShowStudyGuides', () => { jest.spyOn(selectors, 'hasMoreResults') .mockReturnValue(true); - const component = renderer.create( - - , { createNodeMock: () => container }); + const component = createComponent(container); Object.defineProperty(container, 'scrollHeight', { value: 1000 }); Object.defineProperty(container, 'offsetHeight', { value: 100 }); @@ -54,9 +61,7 @@ describe('ShowStudyGuides', () => { jest.spyOn(selectors, 'hasMoreResults') .mockReturnValue(true); - const component = renderer.create( - - , { createNodeMock: () => container}); + const component = createComponent(container); Object.defineProperty(container, 'scrollHeight', { value: 1000 }); Object.defineProperty(container, 'offsetHeight', { value: 100 }); @@ -79,9 +84,7 @@ describe('ShowStudyGuides', () => { jest.spyOn(selectors, 'summaryIsLoading').mockReturnValue(false); jest.spyOn(selectors, 'summaryStudyGuides').mockReturnValue({}); - renderer.create( - - , { createNodeMock: () => container}); + createComponent(container); runHooks(renderer); @@ -95,9 +98,7 @@ describe('ShowStudyGuides', () => { jest.spyOn(selectors, 'hasMoreResults') .mockReturnValue(false); - const component = renderer.create( - - , { createNodeMock: () => container}); + const component = createComponent(container); Object.defineProperty(container, 'scrollHeight', { value: 1000 }); Object.defineProperty(container, 'offsetHeight', { value: 100 }); @@ -122,9 +123,7 @@ describe('ShowStudyGuides', () => { jest.spyOn(selectors, 'hasMoreResults') .mockReturnValue(true); - const component = renderer.create( - - , { createNodeMock: () => container}); + const component = createComponent(container); Object.defineProperty(container, 'scrollHeight', { value: 1000 }); Object.defineProperty(container, 'offsetHeight', { value: 100 }); @@ -148,9 +147,7 @@ describe('ShowStudyGuides', () => { it('shows back to top button on scroll and works on click', async() => { const container = window.document.createElement('div'); - const component = renderer.create( - - , { createNodeMock: () => container }); + const component = createComponent(container); Object.defineProperty(container, 'height', { value: 1000 }); Object.defineProperty(container, 'scrollTop', { value: 10, writable: true }); @@ -175,7 +172,7 @@ describe('ShowStudyGuides', () => { it('does not scroll to top without ref', () => { const {root} = renderToDom( - + } /> ); const target = root.querySelector('[data-testid="show-studyguides-body"]'); diff --git a/src/app/content/studyGuides/components/ShowStudyGuides.tsx b/src/app/content/studyGuides/components/ShowStudyGuides.tsx index ec1743a11e..0f73859460 100644 --- a/src/app/content/studyGuides/components/ShowStudyGuides.tsx +++ b/src/app/content/studyGuides/components/ShowStudyGuides.tsx @@ -32,7 +32,7 @@ export const StudyGuidesBody = styled(PopupBody)` `; // tslint:disable-next-line: variable-name -const ShowStudyGuides = () => { +const ShowStudyGuides = ({topElRef}: {topElRef: React.RefObject}) => { const ref = React.useRef(null); const [showGoToTop, setShowGoToTop] = React.useState(false); const dispatch = useDispatch(); @@ -54,6 +54,7 @@ const ShowStudyGuides = () => { } refElement.scrollTop = 0; + topElRef.current?.focus(); setShowGoToTop(false); }; diff --git a/src/app/content/studyGuides/components/StudyGuidesPopUp.tsx b/src/app/content/studyGuides/components/StudyGuidesPopUp.tsx index 6f17976f5b..c2a0e5aa83 100644 --- a/src/app/content/studyGuides/components/StudyGuidesPopUp.tsx +++ b/src/app/content/studyGuides/components/StudyGuidesPopUp.tsx @@ -65,7 +65,7 @@ const StudyguidesPopUp = () => { - + : null; }; From 47ec9ef9447869f2cbcd38e5853e01b888a7f53f Mon Sep 17 00:00:00 2001 From: Malar-Natarajan <40276461+Malar-Natarajan@users.noreply.github.com> Date: Tue, 11 Jun 2024 10:52:04 -0500 Subject: [PATCH 07/11] FE playwright test: Test canonical pages (#2254) * new test * test complete * new book * exclude safari * remove commented code * remove sleep --- playwright/src/fixtures/content.page.ts | 7 ++ playwright/src/fixtures/toc.ts | 2 +- playwright/tests/rex-test/rex.behaviorspec.ts | 98 +++++++++++++++++++ pytest-selenium/utils/books.json | 6 ++ 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/playwright/src/fixtures/content.page.ts b/playwright/src/fixtures/content.page.ts index f47c972a8d..191bfd2dff 100644 --- a/playwright/src/fixtures/content.page.ts +++ b/playwright/src/fixtures/content.page.ts @@ -90,6 +90,13 @@ class ContentPage { .addCookies([{ name: 'nudge_study_guides_date', value: current_date, url: this.page.url() }]) } + async canonical() { + // Return canonical link of the current page + let canonicalPageSelector = await this.page.$('[rel="canonical"]') + const canonicalPage = await canonicalPageSelector.evaluate((e) => e.getAttribute('href')) + return canonicalPage + } + async colorLocator(color: string) { // Return locator of the color if (color === 'blue') { diff --git a/playwright/src/fixtures/toc.ts b/playwright/src/fixtures/toc.ts index 0b5f52c447..06e60a8584 100644 --- a/playwright/src/fixtures/toc.ts +++ b/playwright/src/fixtures/toc.ts @@ -89,7 +89,7 @@ class TOC { if ((await titleAfterClick) != (await titleBeforeClick)) { return } else { - sleep(1) + sleep(2) } } else { console.log('The page number specified exceeds the total pages in the book') diff --git a/playwright/tests/rex-test/rex.behaviorspec.ts b/playwright/tests/rex-test/rex.behaviorspec.ts index dc254353e1..29b73b1a7b 100644 --- a/playwright/tests/rex-test/rex.behaviorspec.ts +++ b/playwright/tests/rex-test/rex.behaviorspec.ts @@ -576,3 +576,101 @@ test('MH page dropdown filters', async ({ page, isMobile }) => { const highlightcount = await bookPage.highlightCount() expect(highlightcount).toBe(2) }) + + +test('C543224 canonicals for books with no shared content', async ({ page, isMobile, browserName }) => { + test.skip(isMobile as boolean, 'test only desktop resolution') + test.skip(browserName == 'webkit', 'test only chrome') + test.skip(browserName == 'firefox', 'test only chrome') + + // GIVEN: Open Rex page + const bookPage = new ContentPage(page) + const path = '/books/chemistry-2e/pages/1-1-chemistry-in-context' + await bookPage.open(path) + + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/chemistry-2e/pages/1-1-chemistry-in-context') + + // WHEN: click EOC page + const Toc = new TOC(page) + await Toc.pageClick(9) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/chemistry-2e/pages/1-key-equations') + + // WHEN: Click EOB page + await Toc.pageClick(221) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/chemistry-2e/pages/e-water-properties') + + // WHEN: click nested EOB page + await Toc.pageClick(230) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/chemistry-2e/pages/chapter-1') +}) + + +test('C543225 canonicals for pages derived from another book', async ({ page, isMobile, browserName }) => { + test.skip(isMobile as boolean, 'test only desktop resolution') + test.skip(browserName == 'webkit', 'test only chrome') + test.skip(browserName == 'firefox', 'test only chrome') + + // GIVEN: Open Rex page derived from another book + const bookPage = new ContentPage(page) + const path = '/books/preparing-for-college-success/pages/2-1-why-college' + await bookPage.open(path) + + // THEN: Canonical page points to original content + expect(await bookPage.canonical()).toBe('https://openstax.org/books/college-success-concise/pages/1-1-why-college') + + // WHEN: click EOC page from a chapter derived from another book + const Toc = new TOC(page) + await Toc.pageClick(14) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/preparing-for-college-success/pages/2-summary') + + + // WHEN: Open page unique to this book + await Toc.pageClick(3) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/preparing-for-college-success/pages/1-2-your-academic-journey-and-personal-story') + + // WHEN: Open EOC page from the chapter unique to this book + await Toc.pageClick(6) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/preparing-for-college-success/pages/1-family-friends-matter') + + // WHEN: Open EOB page from the chapter unique to this book + await Toc.pageClick(71) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/preparing-for-college-success/pages/index') +}) + +test('C543225 canonicals for old editions point to the latest edition', async ({ page, isMobile, browserName }) => { + test.skip(isMobile as boolean, 'test only desktop resolution') + test.skip(browserName == 'webkit', 'test only chrome') + test.skip(browserName == 'firefox', 'test only chrome') + + // GIVEN: Open older edition of Rex page derived from another book + const bookPage = new ContentPage(page) + const path = '/books/principles-macroeconomics-2e/pages/1-introduction' + await bookPage.open(path) + // THEN: Canonical page points to latest edition of the original content + expect(await bookPage.canonical()).toBe('https://openstax.org/books/principles-economics-3e/pages/1-introduction') + + // WHEN: Open older edition of EOC page of a book derived from another book + const Toc = new TOC(page) + await Toc.pageClick(7) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/principles-macroeconomics-2e/pages/1-key-concepts-and-summary') + + // WHEN: Open older edition of nested EOB page of a book derived from another book + await Toc.pageClick(243) + // THEN: Canonical page points to itself + expect(await bookPage.canonical()).toBe('https://openstax.org/books/principles-macroeconomics-2e/pages/chapter-2') + + + // WHEN: Open older edition of appendix page of a book derived from another book + await Toc.pageClick(241) + // THEN: Canonical page points to latest edition of the original content + expect(await bookPage.canonical()).toBe('https://openstax.org/books/principles-economics-3e/pages/d-the-expenditure-output-model') +}) diff --git a/pytest-selenium/utils/books.json b/pytest-selenium/utils/books.json index 2017f14e9c..8813683f98 100644 --- a/pytest-selenium/utils/books.json +++ b/pytest-selenium/utils/books.json @@ -466,6 +466,12 @@ "search_term": "NIH, 2022d", "chapter_search_results_total": 65, "rkt_search_results_total": 0 + }, + "psychiatric-mental-health": { + "default_page": "1-introduction", + "search_term": "mental health", + "chapter_search_results_total": 2674, + "rkt_search_results_total": 4 } } From 567b71182a1f3683553ab3167f7833b898cfd391 Mon Sep 17 00:00:00 2001 From: Chris Bendel Date: Tue, 11 Jun 2024 12:13:05 -0400 Subject: [PATCH 08/11] Remove staxly (#2252) --- public/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/public/index.html b/public/index.html index 55b1aab72f..6832197527 100644 --- a/public/index.html +++ b/public/index.html @@ -12,7 +12,6 @@ -