Skip to content

Commit

Permalink
Port Contact page to TS
Browse files Browse the repository at this point in the history
[CORE-540]
  • Loading branch information
RoyEJohnson committed Oct 25, 2024
1 parent a3d24f9 commit e83b47a
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/app/components/select/drop-down/drop-down.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function AutoFocusVerticalList({options}) {
}, [options, select])

return (
<div className="vl-wrapper" hidden={!isOpen}>
<div className="vl-wrapper" hidden={!isOpen} role="presentation">
<VerticalList
items={options} RenderItem={RenderItem}
onSelect={onSelect} onCancel={close}
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/select/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function Select({name, required, onValueUpdate, children}) {

return (
<SelectContextProvider contextValueParameters={{onValueUpdate}}>
<div className="Select" role="listbox">
<div className="Select">
{name && <HiddenSelect {...{name, required, elementRef}} />}
{children}
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/app/components/toggle/toggle-control-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default function ToggleControlBar({ Indicator, children }) {
[isOpen]
);
const focusRef = useRefToFocusAfterClose();
const listboxId = `lbid-${Math.floor(Math.random() * 1010101)}`;

React.useEffect(() => {
if (isOpen) {
Expand All @@ -41,8 +42,11 @@ export default function ToggleControlBar({ Indicator, children }) {
onClick={() => toggle()}
onKeyDown={onKeyDown}
ref={focusRef}
role="combobox"
aria-controls={listboxId}
aria-haspopup={listboxId}
>
<div>{children}</div>
<div role="listbox" id={listboxId}>{children}</div>
<Indicator isOpen={isOpen} />
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/app/components/vertical-list/vertical-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function RenderInContext({items, RenderItem, vListRef, onSelect, onCancel}) {
<div
className="vertical-list" tabIndex="0" ref={vListRef}
onBlur={onCancel} onKeyDown={onKeyDown}
role="listbox"
>
{
items.map((item, i) =>
Expand Down
7 changes: 2 additions & 5 deletions src/app/pages/contact/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,10 @@ function LabeledInputWithInvalidMessage({
const [message, setMessage] = useState('');

useEffect(() => {
const el = ref?.current?.querySelector<HTMLInputElement & {
const el = ref?.current?.querySelector('[name]') as HTMLInputElement & {
validationMessage: string;
}>('[name]');
};

if (!el) {
return () => null; // Get assertDefined() instead
}
const updateMessage = () => setMessage(el.validationMessage);

updateMessage();
Expand Down
163 changes: 163 additions & 0 deletions test/src/pages/contact.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import React from 'react';
import {fireEvent, render, screen, waitFor} from '@testing-library/preact';
import {describe, it} from '@jest/globals';
import userEvent from '@testing-library/user-event';
import ContactPage from '~/pages/contact/contact';
import Form from '~/pages/contact/form';
import * as UPD from '~/helpers/use-page-data';
import {MemoryRouter} from 'react-router-dom';
import {SalesforceContextProvider} from '~/contexts/salesforce';
import * as SFF from '~/components/salesforce-form/salesforce-form';

const spyUsePageData = jest.spyOn(UPD, 'default');
/* eslint-disable max-len */
const pageData = {
id: 318,
meta: {
slug: 'contact',
seoTitle:
'Let us know if you have any questions or comments about our content',
searchDescription:
'Do you have a question or comment about OpenStax and want to let us know? Fill out our Contact Us form. We would love to hear your thoughts!',
type: 'pages.ContactUs',
detailUrl: 'https://dev.openstax.org/apps/cms/api/v2/pages/318/',
htmlUrl: 'https://dev.openstax.org/contact/',
showInMenus: false,
firstPublishedAt: '2016-06-23T10:25:21.881000-05:00',
aliasOf: null,
parent: {
id: 29,
meta: {
type: 'pages.HomePage',
detailUrl: 'https://dev.openstax.org/apps/cms/api/v2/pages/29/',
htmlUrl: 'https://dev.openstax.org/'
},
title: 'Openstax Homepage'
},
locale: 'en'
},
title: 'Contact Us',
tagline: 'If you have any questions or feedback, drop us a line!',
mailingHeader: 'Mailing Address',
mailingAddress:
'<h3 data-block-key="nek5u">OpenStax</h3><p data-block-key="4sbtp">Rice University<br/>6100 Main Street MS-375<br/>Houston, TX 77005</p>',
customerService:
'<p data-block-key="9iesw"><b>Need help?</b><br/>Visit our <a href="https://openstax.secure.force.com/help">Support Center</a>.<br/></p>',
promoteImage: null,
slug: 'pages/contact'
};

function Component({path='/contact'}) {
return (
<MemoryRouter initialEntries={[path]}>
<SalesforceContextProvider>
<ContactPage />
</SalesforceContextProvider>
</MemoryRouter>
);
}

jest.spyOn(SFF, 'default').mockImplementation(MockSfForm);

describe('contact page', () => {
const user = userEvent.setup();

it('returns null until data', () => {
spyUsePageData.mockReturnValue(undefined);
const {container} = render(<Component />);

expect(container.innerHTML).toBe('');
});
it('displays the form', async () => {
spyUsePageData.mockReturnValue(pageData);
render(<Component />);

const getLoadingText = () => screen.getByText('Loading...');

await waitFor(() => expect(getLoadingText).toThrow());
const inputs = screen.getAllByRole('textbox');

expect(inputs).toHaveLength(3);
// Fill out the form
await user.click(screen.getByRole('combobox'));
const polskaOption = screen.getByRole('option', {
name: 'OpenStax Polska'
});

await user.click(polskaOption as HTMLElement);
const [nameBox, emailBox, messageBox] = [
'Your Name',
'Your Email Address',
'Your Message'
].map((name) => screen.getByRole('textbox', {name}));
const submitButton = screen.getByRole('button', {name: 'Submit'});

fireEvent.change(nameBox, {target: {value: 'Username'}});
fireEvent.change(emailBox, {target: {value: '[email protected]'}});
fireEvent.change(messageBox, {target: {value: 'message text'}});

await user.click(submitButton);
});
it('displays as embedded', async () => {
const setSubmitted = jest.fn();

spyUsePageData.mockReturnValue(pageData);
render(
<MemoryRouter initialEntries={['/embedded/contact']}>
<SalesforceContextProvider>
<Form setSubmitted={setSubmitted} />
</SalesforceContextProvider>
</MemoryRouter>
);
const getLoadingText = () => screen.getByText('Loading...');

await waitFor(() => expect(getLoadingText).toThrow());
const [questionBox, topicBox] = screen.getAllByRole('combobox');

expect(questionBox.textContent).toBe('OpenStax Assignable');
await user.click(topicBox);
await user.click(screen.getByRole('option', {
name: 'Grade book'
}));

const [nameBox, emailBox, messageBox] = [
'Your Name',
'Your Email Address',
'Your Message'
].map((name) => screen.getByRole('textbox', {name}));
const submitButton = screen.getByRole('button', {name: 'Submit'});

fireEvent.change(nameBox, {target: {value: 'Username'}});
fireEvent.change(emailBox, {target: {value: '[email protected]'}});
fireEvent.change(messageBox, {target: {value: 'message text'}});

await user.click(submitButton);
expect(setSubmitted).toHaveBeenCalledWith(true);
});
});

function MockSfForm({children, postTo, afterSubmit}: React.PropsWithChildren<{
postTo: string;
afterSubmit: () => void;
}>) {
const onSubmit = React.useCallback(
(event: Pick<Event, 'preventDefault'>) => {
event?.preventDefault();
afterSubmit();
},
[afterSubmit]
);

return (
<React.Fragment>
<form
action={postTo} method="post"
onSubmit={onSubmit}
>
<div className="form-content">
{children}
</div>
</form>
</React.Fragment>
);
}

0 comments on commit e83b47a

Please sign in to comment.