-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CHAL-53 #done - Implement election reminders page (#36)
* added election reminders page * added tests * added tests * added pledge-to-vote-iframe to coveragePathIgnorePatterns array
- Loading branch information
Showing
27 changed files
with
959 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 165 additions & 0 deletions
165
src/__tests__/unit/app/reminders/completed/page.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import CompletedRemindersPage from '@/app/reminders/completed/page'; | ||
import { render, screen, cleanup } from '@testing-library/react'; | ||
import userEvent from '@testing-library/user-event'; | ||
import '@testing-library/jest-dom'; | ||
import { UserContext, type UserContextType } from '@/contexts/user-context'; | ||
import { AlertsContextProvider } from '@/contexts/alerts-context'; | ||
import { Builder } from 'builder-pattern'; | ||
import navigation from 'next/navigation'; | ||
import { UserType } from '@/model/enums/user-type'; | ||
import type { User } from '@/model/types/user'; | ||
import type { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime'; | ||
|
||
jest.mock('next/navigation', () => ({ | ||
useRouter: jest.fn(), | ||
})); | ||
|
||
describe('CompletedRemindersPage', () => { | ||
let router: AppRouterInstance; | ||
|
||
beforeEach(() => { | ||
router = Builder<AppRouterInstance>().push(jest.fn()).build(); | ||
jest.spyOn(navigation, 'useRouter').mockImplementation(() => router); | ||
}); | ||
|
||
afterEach(cleanup); | ||
|
||
it('renders.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>() | ||
.user(user) | ||
.gotElectionReminders(() => Promise.resolve()) | ||
.build(); | ||
|
||
render( | ||
<AlertsContextProvider> | ||
<UserContext.Provider value={userContextValue}> | ||
<CompletedRemindersPage searchParams={{}} /> | ||
</UserContext.Provider> | ||
</AlertsContextProvider>, | ||
); | ||
}); | ||
|
||
it('displays an alert if its searchParams include hasError=true.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>() | ||
.user(user) | ||
.gotElectionReminders(() => Promise.resolve()) | ||
.build(); | ||
|
||
render( | ||
<AlertsContextProvider> | ||
<UserContext.Provider value={userContextValue}> | ||
<CompletedRemindersPage searchParams={{ hasError: 'true' }} /> | ||
</UserContext.Provider> | ||
</AlertsContextProvider>, | ||
); | ||
|
||
const alert = screen.getByRole('alert'); | ||
expect(alert.classList).not.toContain('hidden'); | ||
expect(alert.textContent).toBe( | ||
"Oops! We couldn't award you a badge. Please try again later.", | ||
); | ||
}); | ||
|
||
it(`does not display an alert if its searchParams do not include | ||
hasError=true.`, () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>() | ||
.user(user) | ||
.gotElectionReminders(() => Promise.resolve()) | ||
.build(); | ||
|
||
render( | ||
<AlertsContextProvider> | ||
<UserContext.Provider value={userContextValue}> | ||
<CompletedRemindersPage searchParams={{}} /> | ||
</UserContext.Provider> | ||
</AlertsContextProvider>, | ||
); | ||
|
||
const alert = screen.getByRole('alert'); | ||
expect(alert.classList).toContain('hidden'); | ||
}); | ||
|
||
it(`redirects the user to /progress if they click 'Continue' and are a | ||
challenger.`, async () => { | ||
const userContextValue = Builder<UserContextType>() | ||
.user( | ||
Builder<User>() | ||
.type(UserType.Challenger) | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(), | ||
) | ||
.gotElectionReminders(() => Promise.resolve()) | ||
.build(); | ||
|
||
const user = userEvent.setup(); | ||
|
||
render( | ||
<AlertsContextProvider> | ||
<UserContext.Provider value={userContextValue}> | ||
<CompletedRemindersPage searchParams={{}} /> | ||
</UserContext.Provider> | ||
</AlertsContextProvider>, | ||
); | ||
|
||
await user.click(screen.getByText(/continue/i)); | ||
expect(router.push).toHaveBeenCalledWith('/progress'); | ||
}); | ||
|
||
it(`redirects the user to /actions if they click 'Continue' and are not a | ||
challenger.`, async () => { | ||
const userContextValue = Builder<UserContextType>() | ||
.user( | ||
Builder<User>() | ||
.type(UserType.Player) | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(), | ||
) | ||
.gotElectionReminders(() => Promise.resolve()) | ||
.build(); | ||
|
||
const user = userEvent.setup(); | ||
|
||
render( | ||
<AlertsContextProvider> | ||
<UserContext.Provider value={userContextValue}> | ||
<CompletedRemindersPage searchParams={{}} /> | ||
</UserContext.Provider> | ||
</AlertsContextProvider>, | ||
); | ||
|
||
await user.click(screen.getByText(/continue/i)); | ||
expect(router.push).toHaveBeenCalledWith('/actions'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import RemindersPage from '@/app/reminders/page'; | ||
import { render, cleanup } from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
import { UserContext, type UserContextType } from '@/contexts/user-context'; | ||
import { AlertsContextProvider } from '@/contexts/alerts-context'; | ||
import { Builder } from 'builder-pattern'; | ||
import type { User } from '@/model/types/user'; | ||
|
||
jest.mock('next/navigation', () => require('next-router-mock')); | ||
|
||
describe('RemindersPage', () => { | ||
afterEach(cleanup); | ||
|
||
it('renders.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: false, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>() | ||
.user(user) | ||
.gotElectionReminders(() => Promise.resolve()) | ||
.build(); | ||
|
||
render( | ||
<AlertsContextProvider> | ||
<UserContext.Provider value={userContextValue}> | ||
<RemindersPage /> | ||
</UserContext.Provider> | ||
</AlertsContextProvider>, | ||
); | ||
}); | ||
}); |
137 changes: 137 additions & 0 deletions
137
src/__tests__/unit/components/guards/has-not-completed-action.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import { hasNotCompletedAction } from '@/components/guards/has-not-completed-action'; | ||
import { render, screen, cleanup } from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
import navigation from 'next/navigation'; | ||
import { Builder } from 'builder-pattern'; | ||
import { UserContext, type UserContextType } from '@/contexts/user-context'; | ||
import { Actions } from '@/model/enums/actions'; | ||
import type { User } from '@/model/types/user'; | ||
import type { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime'; | ||
|
||
jest.mock('next/navigation', () => ({ | ||
useRouter: jest.fn(), | ||
})); | ||
|
||
describe('hasNotCompletedAction', () => { | ||
let router: AppRouterInstance; | ||
|
||
beforeEach(() => { | ||
router = Builder<AppRouterInstance>().push(jest.fn()).build(); | ||
jest.spyOn(navigation, 'useRouter').mockImplementation(() => router); | ||
}); | ||
|
||
afterEach(cleanup); | ||
|
||
it('returns a component that can be rendered.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: false, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>().user(user).build(); | ||
|
||
const TestComponent = hasNotCompletedAction( | ||
function () { | ||
return <div data-testid="test"></div>; | ||
}, | ||
{ action: Actions.ElectionReminders, redirectTo: '/' }, | ||
); | ||
|
||
render( | ||
<UserContext.Provider value={userContextValue}> | ||
<TestComponent /> | ||
</UserContext.Provider>, | ||
); | ||
expect(screen.queryByTestId('test')).toBeInTheDocument(); | ||
}); | ||
|
||
it('returns a component that can accept props.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: false, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>().user(user).build(); | ||
|
||
interface TestComponentProps { | ||
message: string; | ||
} | ||
|
||
const TestComponent = hasNotCompletedAction( | ||
function ({ message }: TestComponentProps) { | ||
return <div>{message}</div>; | ||
}, | ||
{ action: Actions.ElectionReminders, redirectTo: '/' }, | ||
); | ||
|
||
const message = 'test'; | ||
|
||
render( | ||
<UserContext.Provider value={userContextValue}> | ||
<TestComponent message={message} /> | ||
</UserContext.Provider>, | ||
); | ||
expect(screen.queryByText(message)).toBeInTheDocument(); | ||
}); | ||
|
||
it('blocks access to a page if the user has completed the provided action.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: false, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>().user(user).build(); | ||
|
||
const redirectTo = '/'; | ||
|
||
const TestComponent = hasNotCompletedAction( | ||
function () { | ||
return null; | ||
}, | ||
{ action: Actions.ElectionReminders, redirectTo }, | ||
); | ||
|
||
render( | ||
<UserContext.Provider value={userContextValue}> | ||
<TestComponent /> | ||
</UserContext.Provider>, | ||
); | ||
|
||
expect(router.push).toHaveBeenCalledWith(redirectTo); | ||
}); | ||
|
||
it('allows access to a page if the user has not completed the provided action.', () => { | ||
const user = Builder<User>() | ||
.completedActions({ | ||
electionReminders: true, | ||
registerToVote: true, | ||
sharedChallenge: false, | ||
}) | ||
.build(); | ||
|
||
const userContextValue = Builder<UserContextType>().user(user).build(); | ||
|
||
const TestComponent = hasNotCompletedAction( | ||
function () { | ||
return null; | ||
}, | ||
{ action: Actions.SharedChallenge, redirectTo: '/' }, | ||
); | ||
|
||
render( | ||
<UserContext.Provider value={userContextValue}> | ||
<TestComponent /> | ||
</UserContext.Provider>, | ||
); | ||
expect(router.push).not.toHaveBeenCalled(); | ||
}); | ||
}); |
Oops, something went wrong.