Skip to content

Commit

Permalink
Merge branch 'main' into fix-non-tabbable-highlights
Browse files Browse the repository at this point in the history
  • Loading branch information
staxly[bot] authored Jun 13, 2024
2 parents 917a423 + 09339d2 commit 982abb0
Show file tree
Hide file tree
Showing 26 changed files with 345 additions and 83 deletions.
7 changes: 7 additions & 0 deletions playwright/src/fixtures/content.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down
2 changes: 1 addition & 1 deletion playwright/src/fixtures/toc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
98 changes: 98 additions & 0 deletions playwright/tests/rex-test/rex.behaviorspec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
20 changes: 1 addition & 19 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,8 @@
-->
<link rel="manifest" href="/dist/assets/manifest.json">


<!--
this style shows the osano widget after a delay, giving the app
a chance to explicitly hide it but still defaulting to showing it
as a safety fallback
-->
<style>
.osano-cm-widget {
animation: fadeInAnimation 5s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
@keyframes fadeInAnimation {
0% { opacity: 0; }
90% { opacity: 0; }
100% { opacity: 1; }
}
</style>
<link rel="stylesheet" href="https://ram.openstax.org/osano/osano.css">
<script src="https://cmp.osano.com/AzZqbXTbzhHsU3cv1/68d8e8ae-4024-4489-a000-72766ad284a6/osano.js"></script>
<script src="https://chat.research.openstax.org/assets/static/loader.js" async></script>

<!-- Google Tag Manager -->
<script>
Expand Down
6 changes: 6 additions & 0 deletions pytest-selenium/utils/books.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

12 changes: 3 additions & 9 deletions script/prerender/cfn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: >-
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/app/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => <AccessibilityButtonsWrapper>
<NavBar />
<OnEsc />
<PageTitleConfirmation />
<ErrorModal />
<ErrorBoundary>
{children}
Expand Down
33 changes: 33 additions & 0 deletions src/app/components/PageTitleConfirmation.spec.tsx
Original file line number Diff line number Diff line change
@@ -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(
<TestContainer store={store}>
<PageTitleConfirmation className='any' />
</TestContainer>
);

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();
});
});
38 changes: 38 additions & 0 deletions src/app/components/PageTitleConfirmation.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div id='page-title-confirmation' className={className} aria-live='polite'>
{message}
</div>
);
}

export default connect((state: AppState) => ({title: titleSelector(state)}))(styled(
PageTitleConfirmation
)`
${hiddenButAccessible}
`);
1 change: 1 addition & 0 deletions src/app/content/components/Page/PageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export default class PageComponent extends Component<PagePropTypes> {
});
}
this.scrollToTopOrHashManager(null, this.props.scrollToTopOrHash);
lazyResources.checkLazyResources();
}

public async componentDidUpdate(prevProps: PagePropTypes) {
Expand Down
1 change: 0 additions & 1 deletion src/app/content/components/Page/lazyResourceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const checkLazyResources = () => {
element.setAttribute('src', src);
}
element.removeAttribute('data-lazy-src');

}
});
};
Expand Down
40 changes: 40 additions & 0 deletions src/app/content/components/__snapshots__/Content.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,26 @@ Array [
/>
</a>
</div>
</div>,
.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;
}
<div
aria-live="polite"
className="c0"
id="page-title-confirmation"
>
</div>,
.c4 {
display: inline-block;
Expand Down Expand Up @@ -4900,6 +4920,26 @@ Array [
/>
</a>
</div>
</div>,
.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;
}
<div
aria-live="polite"
className="c0"
id="page-title-confirmation"
>
</div>,
.c4 {
display: inline-block;
Expand Down
8 changes: 4 additions & 4 deletions src/app/content/highlights/components/ColorPicker.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -89,10 +89,10 @@ describe('ColorPicker', () => {
const onRemove = jest.fn();
const {root} = renderToDom(
<TestContainer>
<ColorPicker onChange={onChange} onRemove={onRemove} />
<ColorPicker color={highlightStyles[0].label} onChange={onChange} onRemove={onRemove} />
</TestContainer>
);
const rg = root.querySelector('[role="radiogroup"]') as HTMLDivElement;
const rg = root.querySelector('fieldset') as HTMLFieldSetElement;

expect(rg).toBeTruthy();
rg?.focus();
Expand Down Expand Up @@ -148,7 +148,7 @@ describe('ColorPicker', () => {
<ColorPicker color={highlightStyles[0].label} onChange={onChange} onRemove={onRemove} />
</TestContainer>
);
const rg = root.querySelector('[role="radiogroup"]') as HTMLDivElement;
const rg = root.querySelector('fieldset') as HTMLFieldSetElement;

expect(rg).toBeTruthy();
rg?.focus();
Expand Down
Loading

0 comments on commit 982abb0

Please sign in to comment.