From efe89b7a547c905177539ab25ad0edc627d6c502 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 11:11:50 -0700 Subject: [PATCH 01/29] Add time slot utility to identify whether two times are both AM or PM. --- tests/utils/timeSlot.test.ts | 23 ++++++++++++++++++++++- utils/timeSlot.ts | 25 ++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/tests/utils/timeSlot.test.ts b/tests/utils/timeSlot.test.ts index 9d69b682..66a9081b 100644 --- a/tests/utils/timeSlot.test.ts +++ b/tests/utils/timeSlot.test.ts @@ -1,4 +1,4 @@ -import { isFirstTimeSlotEarlier, parseTimeSlot } from '../../utils/timeSlot' +import { isFirstTimeSlotEarlier, parseTimeSlot, samePeriod } from '../../utils/timeSlot' // Test parseTimeSlot() describe('A time slot string is', () => { @@ -66,3 +66,24 @@ describe('Comparing time slots results in', () => { expect(result).toBe(false) }) }) + +// Test samePeriod() +describe('Two times are', () => { + // Shared test values. + const eightAm = 8 + const tenAm = 10 + const onePm = 1 + const threePm = 3 + + it('the same period if they are both AM', () => { + expect(samePeriod(eightAm, tenAm)).toBe(true) + }) + + it('the same period if they are both PM', () => { + expect(samePeriod(onePm, threePm)).toBe(true) + }) + + it('not the same period if one is AM and one is PM', () => { + expect(samePeriod(eightAm, threePm)).toBe(false) + }) +}) diff --git a/utils/timeSlot.ts b/utils/timeSlot.ts index 7fc271f0..2f99f8b9 100644 --- a/utils/timeSlot.ts +++ b/utils/timeSlot.ts @@ -30,12 +30,31 @@ export function parseTimeSlot(timeSlot: string): TimeSlot | null { } /** - * Convert 12 hour time into 24 hour time. + * Identify whether a time is AM or PM. * * Assume that any time earlier than 8 is actually PM. */ -function convertTo24H(time: number): number { - if (time < 8) { +export function isAm(time: number): boolean { + return time < 8 +} + +/** + * Identify whether two times are both am, pm, or different. + * + * Note: "period" is what Unicode calls AM/PM. + * See https://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns + */ +export function samePeriod(first: number, second: number): boolean { + const bothAm = isAm(first) && isAm(second) + const bothPm = !isAm(first) && !isAm(second) + return bothAm || bothPm +} + +/** + * Convert 12 hour time into 24 hour time. + */ +export function convertTo24H(time: number): number { + if (isAm(time)) { return time + 12 } else { return time From 0ef30dc532995187ed49fdb2582b09ce538a0bfc Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 20:33:33 -0700 Subject: [PATCH 02/29] Fix business hour handling. --- tests/utils/timeSlot.test.ts | 30 +++++++++++++++++++++++++++++- utils/timeSlot.ts | 23 +++++++++++++++++------ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/tests/utils/timeSlot.test.ts b/tests/utils/timeSlot.test.ts index 66a9081b..12c848a9 100644 --- a/tests/utils/timeSlot.test.ts +++ b/tests/utils/timeSlot.test.ts @@ -1,4 +1,4 @@ -import { isFirstTimeSlotEarlier, parseTimeSlot, samePeriod } from '../../utils/timeSlot' +import { convertTo24H, isAm, isFirstTimeSlotEarlier, parseTimeSlot, samePeriod } from '../../utils/timeSlot' // Test parseTimeSlot() describe('A time slot string is', () => { @@ -87,3 +87,31 @@ describe('Two times are', () => { expect(samePeriod(eightAm, threePm)).toBe(false) }) }) + +// Test isAm() +describe('A time is in the period', () => { + it('am if it is equal to or after 8 and before 12', () => { + expect(isAm(8)).toBe(true) + expect(isAm(11)).toBe(true) + }) + + it('pm if it is before 8 and equal to or after 12', () => { + expect(isAm(7)).toBe(false) + expect(isAm(12)).toBe(false) + expect(isAm(1)).toBe(false) + expect(isAm(5)).toBe(false) + }) +}) + +// Test convertTo24H() +describe('Converting a time to 24h time', () => { + it('does not happen for times between 8–12 (inclusive)', () => { + expect(convertTo24H(8)).toBe(8) + expect(convertTo24H(12)).toBe(12) + }) + + it('happens for times between 1–7 and 13 and up', () => { + expect(convertTo24H(1)).toBe(13) + expect(convertTo24H(7)).toBe(19) + }) +}) diff --git a/utils/timeSlot.ts b/utils/timeSlot.ts index 2f99f8b9..40fe7b02 100644 --- a/utils/timeSlot.ts +++ b/utils/timeSlot.ts @@ -7,7 +7,7 @@ * - etc */ -import { TimeSlot } from '../types/common' +import { I18nString, TimeSlot } from '../types/common' /** * Parse a time slot from the API gateway. @@ -32,10 +32,21 @@ export function parseTimeSlot(timeSlot: string): TimeSlot | null { /** * Identify whether a time is AM or PM. * - * Assume that any time earlier than 8 is actually PM. + * AM = 8 (inclusive) up to 12 (not inclusive) */ export function isAm(time: number): boolean { - return time < 8 + return time < 12 && time >= 8 +} + +/** + * Return the I18nString for AM/PM. + */ +export function identifyI18nPeriod(time: number): I18nString { + if (isAm(time)) { + return 'time.am' + } else { + return 'time.pm' + } } /** @@ -54,10 +65,10 @@ export function samePeriod(first: number, second: number): boolean { * Convert 12 hour time into 24 hour time. */ export function convertTo24H(time: number): number { - if (isAm(time)) { - return time + 12 - } else { + if (isAm(time) || time === 12) { return time + } else { + return time + 12 } } From 30f4d554aeed49b61a0e665920ac59aa50291964 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 20:44:12 -0700 Subject: [PATCH 03/29] Add format for appointment dates. --- tests/utils/formatDate.test.ts | 14 +++++++++++++- utils/formatDate.ts | 18 +++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/utils/formatDate.test.ts b/tests/utils/formatDate.test.ts index 25ad67c9..7f96dcda 100644 --- a/tests/utils/formatDate.test.ts +++ b/tests/utils/formatDate.test.ts @@ -1,6 +1,7 @@ import MockDate from 'mockdate' +import { toDate } from 'date-fns-tz' -import formatDate, { isDatePast, isValidDate } from '../../utils/formatDate' +import formatDate, { formatAppointmentDate, isDatePast, isValidDate } from '../../utils/formatDate' // Test isValidDate() describe('Valid dates: A date is', () => { @@ -41,6 +42,17 @@ describe('Past dates: A date is', () => { }) }) +// Test formatAppointmentDate() +describe('Formatting appointments', () => { + it('displays the date in the expected format and timezone', () => { + // Create a date that is midnight UTC + const date = toDate('2021-01-01T00:00:00', { timeZone: 'Europe/London' }) + // Verify that it is formatted correctly for PT + const formattedDate = formatAppointmentDate(date) + expect(formattedDate).toBe('Thursday, December 31, 2020') + }) +}) + // Test formatDate() describe('Formatting dates', () => { it('displays the expected date string', () => { diff --git a/utils/formatDate.ts b/utils/formatDate.ts index 587953d8..5479c467 100644 --- a/utils/formatDate.ts +++ b/utils/formatDate.ts @@ -12,9 +12,11 @@ * in Pacific Time if there is no timezone provided in the datetime string. */ -import { format, isValid } from 'date-fns' -import { toDate } from 'date-fns-tz' -import { ApiGatewayDateString } from '../types/common' +import { isValid } from 'date-fns' +import { format, toDate, utcToZonedTime } from 'date-fns-tz' +import enUS from 'date-fns/locale/en-US' +import { ApiGatewayDateString, LocaleString } from '../types/common' +import { samePeriod } from './timeSlot' const pacificTimeZone = 'America/Los_Angeles' const apiGatewayFormat = "yyyy-MM-dd'T'HH:mm:ss" @@ -104,6 +106,16 @@ export function isDatePast(date: Date): boolean { return date < today } +/** + * Format appointment. + */ +export function formatAppointmentDate(date: Date): string { + const dateFormat = 'EEEE, LLLL d, yyyy' + const convertedDate = utcToZonedTime(date, pacificTimeZone) + const formattedDate = format(convertedDate, dateFormat, { locale: enUS, timeZone: pacificTimeZone }) + return formattedDate +} + /** * Format dates for user-facing display. * From d30bb8d1c76e753819b6910dffd626993483720a Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 21:06:29 -0700 Subject: [PATCH 04/29] Build an appointment object. Refactor test helpers. --- tests/testHelpers.ts | 27 ++++++++++++++++ tests/utils/getClaimStatus.test.tsx | 41 ++++++++++++++++++++++- tests/utils/getScenarioContent.test.tsx | 26 +-------------- types/common.tsx | 5 +++ utils/getClaimStatus.tsx | 43 +++++++++++++++++++++++-- 5 files changed, 114 insertions(+), 28 deletions(-) create mode 100644 tests/testHelpers.ts diff --git a/tests/testHelpers.ts b/tests/testHelpers.ts new file mode 100644 index 00000000..c65a9485 --- /dev/null +++ b/tests/testHelpers.ts @@ -0,0 +1,27 @@ +/** + * Common test helpers to create shared mock data. + */ + +import { PendingDetermination } from '../types/common' +import { formatFromApiGateway, getDateWithOffset } from '../utils/formatDate' + +export function getMockPendingDetermination(): PendingDetermination { + const pendingDetermination: PendingDetermination = { + pendingDate: '', + scheduleDate: '', + timeSlotDesc: '', + requestDate: '', + determinationStatus: '', + willCallIndicator: false, + spokenLanguageCode: '', + spokenLanguageDesc: '', + } + return pendingDetermination +} + +export function getPendingDeterminationWithScheduleDate(offset = 1): PendingDetermination { + const pendingDetermination = getMockPendingDetermination() + pendingDetermination.determinationStatus = 'Random string' // Can be anything other than one of NonPendingDeterminationValues + pendingDetermination.scheduleDate = formatFromApiGateway(getDateWithOffset(offset)) + return pendingDetermination +} diff --git a/tests/utils/getClaimStatus.test.tsx b/tests/utils/getClaimStatus.test.tsx index d66c6958..b70a3feb 100644 --- a/tests/utils/getClaimStatus.test.tsx +++ b/tests/utils/getClaimStatus.test.tsx @@ -1,4 +1,6 @@ -import { buildClaimStatusHeading } from '../../utils/getClaimStatus' +import { getPendingDeterminationWithScheduleDate } from '../testHelpers' +import { getDateWithOffset } from '../../utils/formatDate' +import { buildAppointment, buildClaimStatusHeading } from '../../utils/getClaimStatus' import { ScenarioType } from '../../utils/getScenarioContent' import { getNumericEnumKeys } from '../../utils/numericEnum' @@ -12,3 +14,40 @@ describe('The Claim Status heading', () => { } }) }) + +// Test buildAppointment() +describe('An appointment is', () => { + it('returned with a time slot if there is a time slot value', () => { + const pendingDetermination = getPendingDeterminationWithScheduleDate(0) + const expectedDate = getDateWithOffset(0) + + pendingDetermination.timeSlotDesc = '10-12' + const expectedTimeSlot = { + rangeStart: 10, + rangeEnd: 12, + } + + const appointment = buildAppointment(ScenarioType.Scenario2, pendingDetermination) + expect(appointment.date).toStrictEqual(expectedDate) + expect(appointment.timeSlot).toStrictEqual(expectedTimeSlot) + }) + + it('returned with no time slot if there is no time slot value', () => { + const pendingDetermination = getPendingDeterminationWithScheduleDate(0) + const expectedDate = getDateWithOffset(0) + const appointment = buildAppointment(ScenarioType.Scenario2, pendingDetermination) + expect(appointment.date).toStrictEqual(expectedDate) + expect(appointment.timeSlot).toBe(undefined) + }) + + it('not returned (null) if it is not scenario 2', () => { + const pendingDetermination = getPendingDeterminationWithScheduleDate(0) + const appointment = buildAppointment(ScenarioType.Scenario1, pendingDetermination) + expect(appointment).toBe(null) + }) + + it('not returned (null) if there is no pending determination object (undefined)', () => { + const appointment = buildAppointment(ScenarioType.Scenario2, undefined) + expect(appointment).toBe(null) + }) +}) diff --git a/tests/utils/getScenarioContent.test.tsx b/tests/utils/getScenarioContent.test.tsx index 0d6073a2..08b82545 100644 --- a/tests/utils/getScenarioContent.test.tsx +++ b/tests/utils/getScenarioContent.test.tsx @@ -1,5 +1,6 @@ import MockDate from 'mockdate' +import { getMockPendingDetermination, getPendingDeterminationWithScheduleDate } from '../testHelpers' import { PendingDetermination } from '../../types/common' import apiGatewayStub from '../../utils/apiGatewayStub' import { @@ -10,31 +11,6 @@ import { NonPendingDeterminationValues, ScenarioType, } from '../../utils/getScenarioContent' -import { formatFromApiGateway, getDateWithOffset } from '../../utils/formatDate' - -/** - * Test helpers to create shared mock data. - */ -function getMockPendingDetermination(): PendingDetermination { - const pendingDetermination: PendingDetermination = { - pendingDate: '', - scheduleDate: '', - timeSlotDesc: '', - requestDate: '', - determinationStatus: '', - willCallIndicator: false, - spokenLanguageCode: '', - spokenLanguageDesc: '', - } - return pendingDetermination -} - -function getPendingDeterminationWithScheduleDate(offset = 1): PendingDetermination { - const pendingDetermination = getMockPendingDetermination() - pendingDetermination.determinationStatus = 'Random string' // Can be anything other than one of NonPendingDeterminationValues - pendingDetermination.scheduleDate = formatFromApiGateway(getDateWithOffset(offset)) - return pendingDetermination -} /** * Setup before all tests. diff --git a/types/common.tsx b/types/common.tsx index cd8cffc6..b504f8fb 100644 --- a/types/common.tsx +++ b/types/common.tsx @@ -52,6 +52,11 @@ export interface TimeSlot { rangeEnd: number } +export interface Appointment { + date: Date + timeSlot?: TimeSlot +} + export interface ClaimStatusContent { heading: I18nString summary: TransLineContent[] diff --git a/utils/getClaimStatus.tsx b/utils/getClaimStatus.tsx index 8c86c7ab..1eeeacd2 100644 --- a/utils/getClaimStatus.tsx +++ b/utils/getClaimStatus.tsx @@ -2,9 +2,18 @@ * Utility file to get content for the Claim Status section. */ -import claimStatusJson from '../public/locales/en/claim-status.json' -import { ClaimStatusContent, I18nString, TextOptionalLink, TransLineContent } from '../types/common' +import { parseApiGatewayDate } from './formatDate' import { ScenarioType } from './getScenarioContent' +import { parseTimeSlot } from './timeSlot' +import claimStatusJson from '../public/locales/en/claim-status.json' +import { + Appointment, + ClaimStatusContent, + I18nString, + PendingDetermination, + TextOptionalLink, + TransLineContent, +} from '../types/common' type StepType = 'your-next-steps' | 'edd-next-steps' @@ -58,6 +67,36 @@ function buildI18nKey(keys: string[]): I18nString { return 'claim-status:' + keys.join('.') + '.text' } +/** + * Construct Scenario 2 appointment date & time. + * + * Expects a valid pendingDetermination.scheduleDate. + * Will validate the pendingDetermination.timeSlotDesc. + */ +export function buildAppointment( + scenarioType: ScenarioType, + pendingDetermination: PendingDetermination | undefined, +): Appointment | null { + // Return an appointment only if: + // - this is scenario 2 + // - AND there is a pendingDetermination object + if (scenarioType === ScenarioType.Scenario2 && pendingDetermination) { + const parsedDate = parseApiGatewayDate(pendingDetermination.scheduleDate) + const appointment: Appointment = { + date: parsedDate, + } + + const timeSlot = parseTimeSlot(pendingDetermination.timeSlotDesc) + if (timeSlot) { + appointment.timeSlot = timeSlot + } + + return appointment + } else { + return null + } +} + /** * Get Claim Status summary. */ From e9f72eae6f07262b2186089b5f7c2524c727fd54 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 21:10:15 -0700 Subject: [PATCH 05/29] Pass appointment object through to Claim Status component. --- components/ClaimSection.tsx | 1 + components/ClaimStatus.tsx | 3 ++- types/common.tsx | 1 + utils/getClaimStatus.tsx | 7 ++++++- utils/getScenarioContent.tsx | 6 +++++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/ClaimSection.tsx b/components/ClaimSection.tsx index 96ce6b62..9e96750d 100644 --- a/components/ClaimSection.tsx +++ b/components/ClaimSection.tsx @@ -22,6 +22,7 @@ export const ClaimSection: React.FC = ({ summary={statusContent.summary} yourNextSteps={statusContent.yourNextSteps} eddNextSteps={statusContent.eddNextSteps} + appointment={statusContent.appointment} /> = ({ summary, yourNextSteps, eddNextSteps, + appointment, }) => { const { t } = useTranslation(['common', 'claim-status']) diff --git a/types/common.tsx b/types/common.tsx index b504f8fb..07aa22d7 100644 --- a/types/common.tsx +++ b/types/common.tsx @@ -62,6 +62,7 @@ export interface ClaimStatusContent { summary: TransLineContent[] yourNextSteps: TransLineContent[] eddNextSteps: TransLineContent[] + appointment: null | Appointment } export interface ClaimDetailsContent { diff --git a/utils/getClaimStatus.tsx b/utils/getClaimStatus.tsx index 1eeeacd2..6532c8f9 100644 --- a/utils/getClaimStatus.tsx +++ b/utils/getClaimStatus.tsx @@ -149,7 +149,11 @@ export function buildNextSteps( /** * Get combined Claim Status content. */ -export default function getClaimStatus(scenarioType: ScenarioType, continueCertifying: boolean): ClaimStatusContent { +export default function getClaimStatus( + scenarioType: ScenarioType, + continueCertifying: boolean, + pendingDetermination: PendingDetermination | undefined, +): ClaimStatusContent { // Explicitly cast the scenario string (e.g. scenario1, scenario2) into the union of literal types // expected by Typescript. scenarioString must be one of the key names in claimStatusJson.scenarios // or this won't compile. For a very good explanation of `keyof typeof` Typescript's and union of @@ -164,5 +168,6 @@ export default function getClaimStatus(scenarioType: ScenarioType, continueCerti summary: buildClaimStatusSummary(scenarioObject, scenarioString), yourNextSteps: buildNextSteps(scenarioObject, scenarioString, 'your-next-steps', continueCertifying), eddNextSteps: buildNextSteps(scenarioObject, scenarioString, 'edd-next-steps'), + appointment: buildAppointment(scenarioType, pendingDetermination), } } diff --git a/utils/getScenarioContent.tsx b/utils/getScenarioContent.tsx index 080fa5f9..c2af17d7 100644 --- a/utils/getScenarioContent.tsx +++ b/utils/getScenarioContent.tsx @@ -212,7 +212,11 @@ export default function getScenarioContent(claimData: Claim): ScenarioContent { const scenarioType = scenarioTypeObject.scenarioType // Construct claim status content. - const statusContent = getClaimStatus(scenarioType, continueCertifying(scenarioType, claimData)) + const statusContent = getClaimStatus( + scenarioType, + continueCertifying(scenarioType, claimData), + scenarioTypeObject.pendingDetermination, + ) // Construct claim details content. if (!claimData.claimDetails) { From de6cf62861c6e747b5a21fc688ed90f109c59f87 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 21:42:49 -0700 Subject: [PATCH 06/29] Add mockdate to getClaimStatus tests. --- tests/utils/getClaimStatus.test.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/utils/getClaimStatus.test.tsx b/tests/utils/getClaimStatus.test.tsx index b70a3feb..d62d5927 100644 --- a/tests/utils/getClaimStatus.test.tsx +++ b/tests/utils/getClaimStatus.test.tsx @@ -1,3 +1,5 @@ +import MockDate from 'mockdate' + import { getPendingDeterminationWithScheduleDate } from '../testHelpers' import { getDateWithOffset } from '../../utils/formatDate' import { buildAppointment, buildClaimStatusHeading } from '../../utils/getClaimStatus' @@ -17,6 +19,10 @@ describe('The Claim Status heading', () => { // Test buildAppointment() describe('An appointment is', () => { + beforeAll(() => { + MockDate.set('2020-01-05') + }) + it('returned with a time slot if there is a time slot value', () => { const pendingDetermination = getPendingDeterminationWithScheduleDate(0) const expectedDate = getDateWithOffset(0) From eb26ae497517c3ac8ba76ccbf536c42454d25bcc Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Tue, 27 Jul 2021 21:44:13 -0700 Subject: [PATCH 07/29] Add missing claim status snapshot tests for scenario 2 and 3. --- tests/components/ClaimStatus.test.tsx | 37 + .../__snapshots__/ClaimStatus.test.tsx.snap | 832 ++++++++++++++++++ 2 files changed, 869 insertions(+) diff --git a/tests/components/ClaimStatus.test.tsx b/tests/components/ClaimStatus.test.tsx index 6c5e734f..f9027f5a 100644 --- a/tests/components/ClaimStatus.test.tsx +++ b/tests/components/ClaimStatus.test.tsx @@ -1,4 +1,5 @@ import renderer from 'react-test-renderer' + import { ClaimStatus } from '../../components/ClaimStatus' import getScenarioContent, { ScenarioType } from '../../utils/getScenarioContent' import apiGatewayStub from '../../utils/apiGatewayStub' @@ -28,6 +29,10 @@ function testClaimStatus( return renderClaimStatusComponent(scenarioContent.statusContent, userArrivedFromUioMobile) } +/** + * Scenario snapshot tests. + */ + describe('Scenario 1', () => { it('matches when there are weeks to certify, on desktop', () => { expect(testClaimStatus(ScenarioType.Scenario1, true)).toMatchSnapshot() @@ -44,6 +49,38 @@ describe('Scenario 1', () => { }) }) +describe('Scenario 2', () => { + it('matches when there are weeks to certify, on desktop', () => { + expect(testClaimStatus(ScenarioType.Scenario2, true)).toMatchSnapshot() + }) + it('matches when there are weeks to certify, on mobile', () => { + expect(testClaimStatus(ScenarioType.Scenario2, true, true)).toMatchSnapshot() + }) + + it("matches when there aren't weeks to certify, on desktop", () => { + expect(testClaimStatus(ScenarioType.Scenario2, false)).toMatchSnapshot() + }) + it("matches when there aren't weeks to certify, on mobile", () => { + expect(testClaimStatus(ScenarioType.Scenario2, false, true)).toMatchSnapshot() + }) +}) + +describe('Scenario 3', () => { + it('matches when there are weeks to certify, on desktop', () => { + expect(testClaimStatus(ScenarioType.Scenario3, true)).toMatchSnapshot() + }) + it('matches when there are weeks to certify, on mobile', () => { + expect(testClaimStatus(ScenarioType.Scenario3, true, true)).toMatchSnapshot() + }) + + it("matches when there aren't weeks to certify, on desktop", () => { + expect(testClaimStatus(ScenarioType.Scenario3, false)).toMatchSnapshot() + }) + it("matches when there aren't weeks to certify, on mobile", () => { + expect(testClaimStatus(ScenarioType.Scenario3, false, true)).toMatchSnapshot() + }) +}) + describe('Scenario 4', () => { it('matches when there are weeks to certify, on desktop', () => { expect(testClaimStatus(ScenarioType.Scenario4, true)).toMatchSnapshot() diff --git a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap index 9eb29039..ce4ff0ca 100644 --- a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap +++ b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap @@ -378,6 +378,838 @@ exports[`Scenario 1 matches when there aren't weeks to certify, on mobile 1`] = `; +exports[`Scenario 2 matches when there are weeks to certify, on desktop 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Continue to + + certify for benefits + + while we determine your eligibility. +
  • +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`Scenario 2 matches when there are weeks to certify, on mobile 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Continue to + + certify for benefits + + while we determine your eligibility. +
  • +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`Scenario 2 matches when there aren't weeks to certify, on desktop 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`Scenario 2 matches when there aren't weeks to certify, on mobile 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`Scenario 3 matches when there are weeks to certify, on desktop 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Under Review +

+
+
+
+ Your phone interview time has passed and your eligibility for benefits is under review. +
+
+ + Important + + : If you missed your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Continue to + + certify for benefits + + while we determine your eligibility. +
  • +
  • + Allow up to 10 days for the EDD to make a decision. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will determine your eligibility. +
  • +
+
+
+
+`; + +exports[`Scenario 3 matches when there are weeks to certify, on mobile 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Under Review +

+
+
+
+ Your phone interview time has passed and your eligibility for benefits is under review. +
+
+ + Important + + : If you missed your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Continue to + + certify for benefits + + while we determine your eligibility. +
  • +
  • + Allow up to 10 days for the EDD to make a decision. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will determine your eligibility. +
  • +
+
+
+
+`; + +exports[`Scenario 3 matches when there aren't weeks to certify, on desktop 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Under Review +

+
+
+
+ Your phone interview time has passed and your eligibility for benefits is under review. +
+
+ + Important + + : If you missed your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Allow up to 10 days for the EDD to make a decision. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will determine your eligibility. +
  • +
+
+
+
+`; + +exports[`Scenario 3 matches when there aren't weeks to certify, on mobile 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Under Review +

+
+
+
+ Your phone interview time has passed and your eligibility for benefits is under review. +
+
+ + Important + + : If you missed your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Allow up to 10 days for the EDD to make a decision. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will determine your eligibility. +
  • +
+
+
+
+`; + exports[`Scenario 4 matches when there are weeks to certify, on desktop 1`] = `
Date: Tue, 27 Jul 2021 21:55:13 -0700 Subject: [PATCH 08/29] Display the appointment date in the Claim Status component. --- components/ClaimStatus.tsx | 99 ++- public/locales/en/common.json | 8 + public/locales/es/common.json | 8 + tests/components/ClaimStatus.test.tsx | 90 ++- .../__snapshots__/ClaimStatus.test.tsx.snap | 605 ++++++++++++++++++ utils/apiGatewayStub.tsx | 1 + utils/formatDate.ts | 3 +- 7 files changed, 793 insertions(+), 21 deletions(-) diff --git a/components/ClaimStatus.tsx b/components/ClaimStatus.tsx index 42f2593a..a2029128 100644 --- a/components/ClaimStatus.tsx +++ b/components/ClaimStatus.tsx @@ -3,7 +3,9 @@ import { useTranslation } from 'next-i18next' import { NextSteps } from './NextSteps' import { TextLine } from './TextLine' import { TransLine } from './TransLine' -import { Appointment, ClaimStatusContent } from '../types/common' +import { Appointment, ClaimStatusContent, TransLineContent } from '../types/common' +import { formatAppointmentDate } from '../utils/formatDate' +import { identifyI18nPeriod, samePeriod } from '../utils/timeSlot' export interface ClaimStatusProps extends ClaimStatusContent { loading: boolean @@ -21,24 +23,95 @@ export const ClaimStatus: React.FC = ({ }) => { const { t } = useTranslation(['common', 'claim-status']) + /** + * Nested function to format appointment dates and times. + */ + function formatAppointment(appointment: Appointment): string { + let formattedAppointment = '' + + if (appointment) { + // Format the date portion. + formattedAppointment = formatAppointmentDate(appointment.date) + + // Format the time portion. + if (appointment.timeSlot) { + const start = appointment.timeSlot.rangeStart + const end = appointment.timeSlot.rangeEnd + let words: string[] = [] + + // If the times are both am or both pm, the string should look something like: + // ", between 1–3 p.m. Pacific time" + if (samePeriod(start, end)) { + words = [',', t('time.between'), `${start}–${end}`, t(identifyI18nPeriod(end)), t('time.pacific-time')] + } + // If one time is am and one time is pm, the string should look something like: + // ", between 10 a.m. and 12 p.m. Pacific time" + else { + words = [ + ',', + t('time.from-mixed-times'), + start.toString(), + t(identifyI18nPeriod(start)), + t('time.and'), + end.toString(), + t(identifyI18nPeriod(end)), + t('time.pacific-time'), + ] + } + + // Join word arrays. + formattedAppointment += words.join(' ') + } + } + + return formattedAppointment + } + + /** + * Nested function to construct the summary containing multiple paragraphs. + */ + function buildSummary( + loading: boolean, + userArrivedFromUioMobile: boolean, + summary: TransLineContent[], + appointment: Appointment | null, + ): JSX.Element[] { + let elements: JSX.Element[] = [] + + // Build generic summary paragraphs. + elements = summary.map((paragraph, index) => ( +
+ +
+ )) + + // Build scenario 2 appointment. + if (appointment) { + const formattedAppointment: string = formatAppointment(appointment) + const wrappedAppointment = ( +
+ +
+ ) + // Splice it in as the second element. + elements.splice(1, 0, wrappedAppointment) + } + + return elements + } + return (

{t('claim-status.title')}

-
- {summary.map((paragraph, index) => ( -
- -
- ))} -
+
{buildSummary(loading, userArrivedFromUioMobile, summary, appointment)}
, ) .toJSON() @@ -22,11 +39,12 @@ function renderClaimStatusComponent(statusContent: ClaimStatusContent, userArriv function testClaimStatus( scenarioType: ScenarioType, - hasCertificationWeeksAvailable: boolean, - userArrivedFromUioMobile: boolean, + hasCertificationWeeksAvailable = false, + userArrivedFromUioMobile = false, + appointment: Appointment | null = null, ): string { const scenarioContent = getScenarioContent(apiGatewayStub(scenarioType, hasCertificationWeeksAvailable)) - return renderClaimStatusComponent(scenarioContent.statusContent, userArrivedFromUioMobile) + return renderClaimStatusComponent(scenarioContent.statusContent, userArrivedFromUioMobile, appointment) } /** @@ -116,3 +134,63 @@ describe('Scenario 6', () => { expect(testClaimStatus(ScenarioType.Scenario6, true, true)).toMatchSnapshot() }) }) + +/** + * Appointment snapshot tests. + */ +describe('If given an appointment', () => { + beforeAll(() => { + MockDate.set('2021-05-05') + }) + + it('with no time slot, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + } + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + }) + + it('with a morning time slot, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 10, + }, + } + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + }) + + it('with an afternoon time slot, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 1, + rangeEnd: 3, + }, + } + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + }) + + it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 3, + }, + } + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + }) + + it('with a time slot that has a nonsense time range, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 3, + rangeEnd: 9, + }, + } + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + }) +}) diff --git a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap index ce4ff0ca..e20124bb 100644 --- a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap +++ b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap @@ -1,5 +1,610 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`If given an appointment with a morning time slot, then match the snapshot 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, May 4, 2021, between 8–10 a.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, May 4, 2021, between 3 p.m. and 9 a.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, May 4, 2021, between 8 a.m. and 3 p.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`If given an appointment with an afternoon time slot, then match the snapshot 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, May 4, 2021, between 1–3 p.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`If given an appointment with no time slot, then match the snapshot 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Tuesday, May 4, 2021 + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + exports[`Scenario 1 matches when there are weeks to certify, on desktop 1`] = `
Date: Wed, 28 Jul 2021 18:09:31 -0700 Subject: [PATCH 09/29] Pass current language to date-fns for i18n. --- components/ClaimStatus.tsx | 4 ++-- utils/formatDate.ts | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/components/ClaimStatus.tsx b/components/ClaimStatus.tsx index a2029128..37e3e5c5 100644 --- a/components/ClaimStatus.tsx +++ b/components/ClaimStatus.tsx @@ -21,7 +21,7 @@ export const ClaimStatus: React.FC = ({ eddNextSteps, appointment, }) => { - const { t } = useTranslation(['common', 'claim-status']) + const { t, i18n } = useTranslation(['common', 'claim-status']) /** * Nested function to format appointment dates and times. @@ -31,7 +31,7 @@ export const ClaimStatus: React.FC = ({ if (appointment) { // Format the date portion. - formattedAppointment = formatAppointmentDate(appointment.date) + formattedAppointment = formatAppointmentDate(appointment.date, i18n.language) // Format the time portion. if (appointment.timeSlot) { diff --git a/utils/formatDate.ts b/utils/formatDate.ts index a71a8180..18ad45a0 100644 --- a/utils/formatDate.ts +++ b/utils/formatDate.ts @@ -15,6 +15,8 @@ import { isValid } from 'date-fns' import { format, toDate, utcToZonedTime } from 'date-fns-tz' import enUS from 'date-fns/locale/en-US' +import es from 'date-fns/locale/es' + import { ApiGatewayDateString } from '../types/common' const pacificTimeZone = 'America/Los_Angeles' @@ -105,13 +107,25 @@ export function isDatePast(date: Date): boolean { return date < today } +/** + * Convert date locale from string. + * + * Falls back to English if an unexpected value is given. + */ +export function convertStringToLocale(localeString: string): Locale { + return localeString === 'es' ? es : enUS +} + /** * Format appointment. */ -export function formatAppointmentDate(date: Date): string { +export function formatAppointmentDate(date: Date, localeString: string): string { const dateFormat = 'EEEE, LLLL d, yyyy' const convertedDate = utcToZonedTime(date, pacificTimeZone) - const formattedDate = format(convertedDate, dateFormat, { locale: enUS, timeZone: pacificTimeZone }) + const formattedDate = format(convertedDate, dateFormat, { + locale: convertStringToLocale(localeString), + timeZone: pacificTimeZone, + }) return formattedDate } From 7edecea3be613073502b4bb7b81c1ba6ab111128 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Wed, 28 Jul 2021 18:20:48 -0700 Subject: [PATCH 10/29] Fix time zone mock bug. --- tests/components/ClaimStatus.test.tsx | 4 ++++ .../__snapshots__/ClaimStatus.test.tsx.snap | 18 +++++++++--------- utils/formatDate.ts | 5 ++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/tests/components/ClaimStatus.test.tsx b/tests/components/ClaimStatus.test.tsx index 65c2671f..0d72ac82 100644 --- a/tests/components/ClaimStatus.test.tsx +++ b/tests/components/ClaimStatus.test.tsx @@ -68,6 +68,10 @@ describe('Scenario 1', () => { }) describe('Scenario 2', () => { + beforeAll(() => { + MockDate.set('2021-05-05') + }) + it('matches when there are weeks to certify, on desktop', () => { expect(testClaimStatus(ScenarioType.Scenario2, true)).toMatchSnapshot() }) diff --git a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap index e20124bb..a881fa05 100644 --- a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap +++ b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap @@ -30,7 +30,7 @@ exports[`If given an appointment with a morning time slot, then match the snapsh - Tuesday, May 4, 2021, between 8–10 a.m. Pacific time + Wednesday, May 5, 2021, between 8–10 a.m. Pacific time
- Tuesday, May 4, 2021, between 3 p.m. and 9 a.m. Pacific time + Wednesday, May 5, 2021, between 3 p.m. and 9 a.m. Pacific time
- Tuesday, May 4, 2021, between 8 a.m. and 3 p.m. Pacific time + Wednesday, May 5, 2021, between 8 a.m. and 3 p.m. Pacific time
- Tuesday, May 4, 2021, between 1–3 p.m. Pacific time + Wednesday, May 5, 2021, between 1–3 p.m. Pacific time
- Tuesday, May 4, 2021 + Wednesday, May 5, 2021
- Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + Wednesday, May 12, 2021, between 1–3 p.m. Pacific time
- Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + Wednesday, May 12, 2021, between 1–3 p.m. Pacific time
- Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + Wednesday, May 12, 2021, between 1–3 p.m. Pacific time
- Tuesday, August 3, 2021, between 1–3 p.m. Pacific time + Wednesday, May 12, 2021, between 1–3 p.m. Pacific time
Date: Thu, 29 Jul 2021 12:57:31 -0700 Subject: [PATCH 11/29] Correct Spanish language translation based on feedback from the translation team. --- components/ClaimStatus.tsx | 5 +++-- public/locales/en/common.json | 1 - public/locales/es/common.json | 3 +-- utils/strings.ts | 3 +++ 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 utils/strings.ts diff --git a/components/ClaimStatus.tsx b/components/ClaimStatus.tsx index 37e3e5c5..259b0862 100644 --- a/components/ClaimStatus.tsx +++ b/components/ClaimStatus.tsx @@ -5,6 +5,7 @@ import { TextLine } from './TextLine' import { TransLine } from './TransLine' import { Appointment, ClaimStatusContent, TransLineContent } from '../types/common' import { formatAppointmentDate } from '../utils/formatDate' +import { capitalizeFirstLetter } from '../utils/strings' import { identifyI18nPeriod, samePeriod } from '../utils/timeSlot' export interface ClaimStatusProps extends ClaimStatusContent { @@ -31,7 +32,7 @@ export const ClaimStatus: React.FC = ({ if (appointment) { // Format the date portion. - formattedAppointment = formatAppointmentDate(appointment.date, i18n.language) + formattedAppointment = capitalizeFirstLetter(formatAppointmentDate(appointment.date, i18n.language)) // Format the time portion. if (appointment.timeSlot) { @@ -49,7 +50,7 @@ export const ClaimStatus: React.FC = ({ else { words = [ ',', - t('time.from-mixed-times'), + t('time.between'), start.toString(), t(identifyI18nPeriod(start)), t('time.and'), diff --git a/public/locales/en/common.json b/public/locales/en/common.json index d628d7fb..d853a6a8 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -42,7 +42,6 @@ }, "time": { "between": "between", - "from-mixed-times": "between", "and": "and", "am": "a.m.", "pm": "p.m.", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 7afb701d..a07fd2da 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -42,8 +42,7 @@ }, "time": { "between": "entre", - "from-mixed-times": "de", - "and": "a", + "and": "y", "am": "a.m.", "pm": "p.m.", "pacific-time": "hora del Pacífico" diff --git a/utils/strings.ts b/utils/strings.ts new file mode 100644 index 00000000..c783d7aa --- /dev/null +++ b/utils/strings.ts @@ -0,0 +1,3 @@ +export function capitalizeFirstLetter(string: string): string { + return string.charAt(0).toUpperCase() + string.slice(1) +} From 2b810d96f9b207d1df10c8117c3879ef0ef8b6c8 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 13:01:26 -0700 Subject: [PATCH 12/29] Add Spanish language snapshots for appointment. --- tests/components/ClaimStatus.test.tsx | 86 ++- .../__snapshots__/ClaimStatus.test.tsx.snap | 615 +++++++++++++++++- 2 files changed, 695 insertions(+), 6 deletions(-) diff --git a/tests/components/ClaimStatus.test.tsx b/tests/components/ClaimStatus.test.tsx index 0d72ac82..af952e13 100644 --- a/tests/components/ClaimStatus.test.tsx +++ b/tests/components/ClaimStatus.test.tsx @@ -1,6 +1,7 @@ import MockDate from 'mockdate' -import renderer from 'react-test-renderer' +import renderer, { act } from 'react-test-renderer' +import i18n from '../jest-i18n' import { ClaimStatus } from '../../components/ClaimStatus' import { Appointment, ClaimStatusContent } from '../../types/common' import apiGatewayStub from '../../utils/apiGatewayStub' @@ -142,6 +143,7 @@ describe('Scenario 6', () => { /** * Appointment snapshot tests. */ +/* eslint-disable @typescript-eslint/no-floating-promises */ describe('If given an appointment', () => { beforeAll(() => { MockDate.set('2021-05-05') @@ -154,6 +156,19 @@ describe('If given an appointment', () => { expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() }) + it('with no time slot, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + } + act(() => { + i18n.changeLanguage('es') + }) + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + it('with a morning time slot, then match the snapshot', () => { const appointment = { date: getDateWithOffset(0), @@ -165,6 +180,23 @@ describe('If given an appointment', () => { expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() }) + it('with a morning time slot, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 10, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + it('with an afternoon time slot, then match the snapshot', () => { const appointment = { date: getDateWithOffset(0), @@ -176,6 +208,23 @@ describe('If given an appointment', () => { expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() }) + it('with an afternoon time slot, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 1, + rangeEnd: 3, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', () => { const appointment = { date: getDateWithOffset(0), @@ -187,6 +236,23 @@ describe('If given an appointment', () => { expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() }) + it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 3, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + it('with a time slot that has a nonsense time range, then match the snapshot', () => { const appointment = { date: getDateWithOffset(0), @@ -197,4 +263,22 @@ describe('If given an appointment', () => { } expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() }) + + it('with a time slot that has a nonsense time range, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 3, + rangeEnd: 9, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) }) +/* eslint-enable @typescript-eslint/no-floating-promises */ diff --git a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap index a881fa05..eaa41e42 100644 --- a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap +++ b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap @@ -121,6 +121,127 @@ exports[`If given an appointment with a morning time slot, then match the snapsh
`; +exports[`If given an appointment with a morning time slot, then match the snapshot, in Spanish 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Miércoles, mayo 5, 2021, entre 8–10 a.m. hora del Pacífico + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Tus Siguientes Pasos +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ Próximos pasos del EDD +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot 1`] = `
- Wednesday, May 5, 2021, between 3 p.m. and 9 a.m. Pacific time + Wednesday, May 5, 2021, between 3 p.m. and 9 a.m. Pacific time + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Your Next Steps +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ EDD Next Steps +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot, in Spanish 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Miércoles, mayo 5, 2021, entre 3 p.m. y 9 a.m. hora del Pacífico + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Tus Siguientes Pasos +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ Próximos pasos del EDD +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + +exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Wednesday, May 5, 2021, between 8 a.m. and 3 p.m. Pacific time
`; -exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot 1`] = ` +exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish 1`] = `
@@ -272,7 +635,7 @@ exports[`If given an appointment with a time slot that starts in the morning and - Wednesday, May 5, 2021, between 8 a.m. and 3 p.m. Pacific time + Miércoles, mayo 5, 2021, entre 8 a.m. y 3 p.m. hora del Pacífico
- Your Next Steps + Tus Siguientes Pasos
- EDD Next Steps + Próximos pasos del EDD
`; +exports[`If given an appointment with an afternoon time slot, then match the snapshot, in Spanish 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Miércoles, mayo 5, 2021, entre 1–3 p.m. hora del Pacífico + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Tus Siguientes Pasos +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ Próximos pasos del EDD +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + exports[`If given an appointment with no time slot, then match the snapshot 1`] = `
`; +exports[`If given an appointment with no time slot, then match the snapshot, in Spanish 1`] = ` +
+

+ Claim Status +

+
+

+ Pending Eligibility — Phone Interview Scheduled +

+
+
+
+ We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: +
+
+ + Miércoles, mayo 5, 2021 + +
+
+ + Important + + : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. +
+
+
+

+ Tus Siguientes Pasos +

+
+
    +
  • + Confirm we have your current phone number. Go to the + + UI Online homepage + + , select + + Profile + + from the main menu, then select + + Contact Information + + . +
  • +
  • + Prepare for the interview. The + <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> + (DE 4800) includes the questions the interviewer is most likely to ask. +
  • +
  • + If you need to reschedule your interview, select + + Reschedule + + in the Appointments section on your + + UI Online homepage + + . You must reschedule at least one day before the interview. +
  • +
+
+
+
+

+ Próximos pasos del EDD +

+
+
    +
  • + We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
  • +
+
+
+
+`; + exports[`Scenario 1 matches when there are weeks to certify, on desktop 1`] = `
Date: Thu, 29 Jul 2021 13:45:43 -0700 Subject: [PATCH 13/29] Refactor into separate Appointment component. --- components/Appointment.tsx | 57 + components/ClaimStatus.tsx | 63 +- stories/Appointment.stories.tsx | 17 + tests/components/Appointment.test.tsx | 159 +++ tests/components/ClaimStatus.test.tsx | 166 +-- .../__snapshots__/Appointment.test.tsx.snap | 121 ++ .../__snapshots__/ClaimStatus.test.tsx.snap | 1210 ----------------- types/common.tsx | 4 +- utils/getClaimStatus.tsx | 6 +- 9 files changed, 370 insertions(+), 1433 deletions(-) create mode 100644 components/Appointment.tsx create mode 100644 stories/Appointment.stories.tsx create mode 100644 tests/components/Appointment.test.tsx create mode 100644 tests/components/__snapshots__/Appointment.test.tsx.snap diff --git a/components/Appointment.tsx b/components/Appointment.tsx new file mode 100644 index 00000000..09762ae2 --- /dev/null +++ b/components/Appointment.tsx @@ -0,0 +1,57 @@ +import { useTranslation } from 'next-i18next' + +import { TextLine } from './TextLine' +import { AppointmentContent } from '../types/common' +import { formatAppointmentDate } from '../utils/formatDate' +import { capitalizeFirstLetter } from '../utils/strings' +import { identifyI18nPeriod, samePeriod } from '../utils/timeSlot' + +export interface AppointmentProps { + loading: boolean + appointment: AppointmentContent +} + +export const Appointment: React.FC = ({ loading = false, appointment }) => { + const { t, i18n } = useTranslation('common') + + let formattedAppointment = '' + + // Format the date portion. + formattedAppointment = capitalizeFirstLetter(formatAppointmentDate(appointment.date, i18n.language)) + + // Format the time portion. + if (appointment.timeSlot) { + const start = appointment.timeSlot.rangeStart + const end = appointment.timeSlot.rangeEnd + let words: string[] = [] + + // If the times are both am or both pm, the string should look something like: + // ", between 1–3 p.m. Pacific time" + if (samePeriod(start, end)) { + words = [',', t('time.between'), `${start}–${end}`, t(identifyI18nPeriod(end)), t('time.pacific-time')] + } + // If one time is am and one time is pm, the string should look something like: + // ", between 10 a.m. and 12 p.m. Pacific time" + else { + words = [ + ',', + t('time.between'), + start.toString(), + t(identifyI18nPeriod(start)), + t('time.and'), + end.toString(), + t(identifyI18nPeriod(end)), + t('time.pacific-time'), + ] + } + + // Join word arrays. + formattedAppointment += words.join(' ') + } + + return ( +
+ +
+ ) +} diff --git a/components/ClaimStatus.tsx b/components/ClaimStatus.tsx index 259b0862..f2c04aa7 100644 --- a/components/ClaimStatus.tsx +++ b/components/ClaimStatus.tsx @@ -1,12 +1,10 @@ import { useTranslation } from 'next-i18next' +import { Appointment } from './Appointment' import { NextSteps } from './NextSteps' import { TextLine } from './TextLine' import { TransLine } from './TransLine' -import { Appointment, ClaimStatusContent, TransLineContent } from '../types/common' -import { formatAppointmentDate } from '../utils/formatDate' -import { capitalizeFirstLetter } from '../utils/strings' -import { identifyI18nPeriod, samePeriod } from '../utils/timeSlot' +import { AppointmentContent, ClaimStatusContent, TransLineContent } from '../types/common' export interface ClaimStatusProps extends ClaimStatusContent { loading: boolean @@ -22,51 +20,7 @@ export const ClaimStatus: React.FC = ({ eddNextSteps, appointment, }) => { - const { t, i18n } = useTranslation(['common', 'claim-status']) - - /** - * Nested function to format appointment dates and times. - */ - function formatAppointment(appointment: Appointment): string { - let formattedAppointment = '' - - if (appointment) { - // Format the date portion. - formattedAppointment = capitalizeFirstLetter(formatAppointmentDate(appointment.date, i18n.language)) - - // Format the time portion. - if (appointment.timeSlot) { - const start = appointment.timeSlot.rangeStart - const end = appointment.timeSlot.rangeEnd - let words: string[] = [] - - // If the times are both am or both pm, the string should look something like: - // ", between 1–3 p.m. Pacific time" - if (samePeriod(start, end)) { - words = [',', t('time.between'), `${start}–${end}`, t(identifyI18nPeriod(end)), t('time.pacific-time')] - } - // If one time is am and one time is pm, the string should look something like: - // ", between 10 a.m. and 12 p.m. Pacific time" - else { - words = [ - ',', - t('time.between'), - start.toString(), - t(identifyI18nPeriod(start)), - t('time.and'), - end.toString(), - t(identifyI18nPeriod(end)), - t('time.pacific-time'), - ] - } - - // Join word arrays. - formattedAppointment += words.join(' ') - } - } - - return formattedAppointment - } + const { t } = useTranslation(['common', 'claim-status']) /** * Nested function to construct the summary containing multiple paragraphs. @@ -75,7 +29,7 @@ export const ClaimStatus: React.FC = ({ loading: boolean, userArrivedFromUioMobile: boolean, summary: TransLineContent[], - appointment: Appointment | null, + appointment: AppointmentContent | null, ): JSX.Element[] { let elements: JSX.Element[] = [] @@ -93,14 +47,9 @@ export const ClaimStatus: React.FC = ({ // Build scenario 2 appointment. if (appointment) { - const formattedAppointment: string = formatAppointment(appointment) - const wrappedAppointment = ( -
- -
- ) + const formattedAppointment = // Splice it in as the second element. - elements.splice(1, 0, wrappedAppointment) + elements.splice(1, 0, formattedAppointment) } return elements diff --git a/stories/Appointment.stories.tsx b/stories/Appointment.stories.tsx new file mode 100644 index 00000000..bd2bf322 --- /dev/null +++ b/stories/Appointment.stories.tsx @@ -0,0 +1,17 @@ +import { Story, Meta } from '@storybook/react' + +import { Appointment as AppointmentComponent, AppointmentProps } from '../components/Appointment' + +export default { + title: 'Component/Atoms/Appointment', + component: AppointmentComponent, +} as Meta + +const Template: Story = (args) => + +export const Appointment = Template.bind({}) +Appointment.args = { + appointment: { + date: new Date(), + }, +} diff --git a/tests/components/Appointment.test.tsx b/tests/components/Appointment.test.tsx new file mode 100644 index 00000000..00fd8d95 --- /dev/null +++ b/tests/components/Appointment.test.tsx @@ -0,0 +1,159 @@ +import MockDate from 'mockdate' +import renderer, { act } from 'react-test-renderer' + +import i18n from '../jest-i18n' +import { Appointment } from '../../components/Appointment' +import { AppointmentContent } from '../../types/common' +import { getDateWithOffset } from '../../utils/formatDate' + +/** + * Helper functions. + */ + +function renderAppointmentComponent(appointment: AppointmentContent): string { + return renderer.create().toJSON() +} + +/** + * Appointment snapshot tests. + */ + +/* eslint-disable @typescript-eslint/no-floating-promises */ +describe('If given an appointment', () => { + beforeAll(() => { + MockDate.set('2021-05-05') + }) + + it('with no time slot, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + } + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + }) + + it('with no time slot, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + } + act(() => { + i18n.changeLanguage('es') + }) + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + + it('with a morning time slot, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 10, + }, + } + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + }) + + it('with a morning time slot, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 10, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + + it('with an afternoon time slot, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 1, + rangeEnd: 3, + }, + } + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + }) + + it('with an afternoon time slot, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 1, + rangeEnd: 3, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + + it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 3, + }, + } + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + }) + + it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 8, + rangeEnd: 3, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) + + it('with a time slot that has a nonsense time range, then match the snapshot', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 3, + rangeEnd: 9, + }, + } + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + }) + + it('with a time slot that has a nonsense time range, then match the snapshot, in Spanish', () => { + const appointment = { + date: getDateWithOffset(0), + timeSlot: { + rangeStart: 3, + rangeEnd: 9, + }, + } + act(() => { + i18n.changeLanguage('es') + }) + expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + act(() => { + i18n.changeLanguage('en') + }) + }) +}) +/* eslint-enable @typescript-eslint/no-floating-promises */ diff --git a/tests/components/ClaimStatus.test.tsx b/tests/components/ClaimStatus.test.tsx index af952e13..0807778e 100644 --- a/tests/components/ClaimStatus.test.tsx +++ b/tests/components/ClaimStatus.test.tsx @@ -1,28 +1,16 @@ import MockDate from 'mockdate' -import renderer, { act } from 'react-test-renderer' +import renderer from 'react-test-renderer' -import i18n from '../jest-i18n' import { ClaimStatus } from '../../components/ClaimStatus' -import { Appointment, ClaimStatusContent } from '../../types/common' +import { ClaimStatusContent } from '../../types/common' import apiGatewayStub from '../../utils/apiGatewayStub' -import { getDateWithOffset } from '../../utils/formatDate' import getScenarioContent, { ScenarioType } from '../../utils/getScenarioContent' /** * Helper functions. */ -function renderClaimStatusComponent( - statusContent: ClaimStatusContent, - userArrivedFromUioMobile: boolean, - appointment: Appointment | null = null, -): string { - // Optionally override the appointment. - let appointmentToRender = statusContent.appointment - if (appointment) { - appointmentToRender = appointment - } - +function renderClaimStatusComponent(statusContent: ClaimStatusContent, userArrivedFromUioMobile: boolean): string { return renderer .create( , ) .toJSON() @@ -42,10 +30,9 @@ function testClaimStatus( scenarioType: ScenarioType, hasCertificationWeeksAvailable = false, userArrivedFromUioMobile = false, - appointment: Appointment | null = null, ): string { const scenarioContent = getScenarioContent(apiGatewayStub(scenarioType, hasCertificationWeeksAvailable)) - return renderClaimStatusComponent(scenarioContent.statusContent, userArrivedFromUioMobile, appointment) + return renderClaimStatusComponent(scenarioContent.statusContent, userArrivedFromUioMobile) } /** @@ -139,146 +126,3 @@ describe('Scenario 6', () => { expect(testClaimStatus(ScenarioType.Scenario6, true, true)).toMatchSnapshot() }) }) - -/** - * Appointment snapshot tests. - */ -/* eslint-disable @typescript-eslint/no-floating-promises */ -describe('If given an appointment', () => { - beforeAll(() => { - MockDate.set('2021-05-05') - }) - - it('with no time slot, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - } - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - }) - - it('with no time slot, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - } - act(() => { - i18n.changeLanguage('es') - }) - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - - it('with a morning time slot, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 10, - }, - } - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - }) - - it('with a morning time slot, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 10, - }, - } - act(() => { - i18n.changeLanguage('es') - }) - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - - it('with an afternoon time slot, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 1, - rangeEnd: 3, - }, - } - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - }) - - it('with an afternoon time slot, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 1, - rangeEnd: 3, - }, - } - act(() => { - i18n.changeLanguage('es') - }) - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - - it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 3, - }, - } - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - }) - - it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 3, - }, - } - act(() => { - i18n.changeLanguage('es') - }) - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - - it('with a time slot that has a nonsense time range, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 3, - rangeEnd: 9, - }, - } - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - }) - - it('with a time slot that has a nonsense time range, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 3, - rangeEnd: 9, - }, - } - act(() => { - i18n.changeLanguage('es') - }) - expect(testClaimStatus(ScenarioType.Scenario2, false, false, appointment)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) -}) -/* eslint-enable @typescript-eslint/no-floating-promises */ diff --git a/tests/components/__snapshots__/Appointment.test.tsx.snap b/tests/components/__snapshots__/Appointment.test.tsx.snap new file mode 100644 index 00000000..966d2716 --- /dev/null +++ b/tests/components/__snapshots__/Appointment.test.tsx.snap @@ -0,0 +1,121 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`If given an appointment with a morning time slot, then match the snapshot 1`] = ` +
+ + Wednesday, May 5, 2021, between 8–10 a.m. Pacific time + +
+`; + +exports[`If given an appointment with a morning time slot, then match the snapshot, in Spanish 1`] = ` +
+ + Miércoles, mayo 5, 2021, entre 8–10 a.m. hora del Pacífico + +
+`; + +exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot 1`] = ` +
+ + Wednesday, May 5, 2021, between 3 p.m. and 9 a.m. Pacific time + +
+`; + +exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot, in Spanish 1`] = ` +
+ + Miércoles, mayo 5, 2021, entre 3 p.m. y 9 a.m. hora del Pacífico + +
+`; + +exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot 1`] = ` +
+ + Wednesday, May 5, 2021, between 8 a.m. and 3 p.m. Pacific time + +
+`; + +exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish 1`] = ` +
+ + Miércoles, mayo 5, 2021, entre 8 a.m. y 3 p.m. hora del Pacífico + +
+`; + +exports[`If given an appointment with an afternoon time slot, then match the snapshot 1`] = ` +
+ + Wednesday, May 5, 2021, between 1–3 p.m. Pacific time + +
+`; + +exports[`If given an appointment with an afternoon time slot, then match the snapshot, in Spanish 1`] = ` +
+ + Miércoles, mayo 5, 2021, entre 1–3 p.m. hora del Pacífico + +
+`; + +exports[`If given an appointment with no time slot, then match the snapshot 1`] = ` +
+ + Wednesday, May 5, 2021 + +
+`; + +exports[`If given an appointment with no time slot, then match the snapshot, in Spanish 1`] = ` +
+ + Miércoles, mayo 5, 2021 + +
+`; diff --git a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap index eaa41e42..c60b834a 100644 --- a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap +++ b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap @@ -1,1215 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`If given an appointment with a morning time slot, then match the snapshot 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Wednesday, May 5, 2021, between 8–10 a.m. Pacific time - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Your Next Steps -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- EDD Next Steps -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with a morning time slot, then match the snapshot, in Spanish 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Miércoles, mayo 5, 2021, entre 8–10 a.m. hora del Pacífico - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Tus Siguientes Pasos -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- Próximos pasos del EDD -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Wednesday, May 5, 2021, between 3 p.m. and 9 a.m. Pacific time - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Your Next Steps -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- EDD Next Steps -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with a time slot that has a nonsense time range, then match the snapshot, in Spanish 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Miércoles, mayo 5, 2021, entre 3 p.m. y 9 a.m. hora del Pacífico - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Tus Siguientes Pasos -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- Próximos pasos del EDD -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Wednesday, May 5, 2021, between 8 a.m. and 3 p.m. Pacific time - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Your Next Steps -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- EDD Next Steps -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Miércoles, mayo 5, 2021, entre 8 a.m. y 3 p.m. hora del Pacífico - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Tus Siguientes Pasos -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- Próximos pasos del EDD -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with an afternoon time slot, then match the snapshot 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Wednesday, May 5, 2021, between 1–3 p.m. Pacific time - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Your Next Steps -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- EDD Next Steps -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with an afternoon time slot, then match the snapshot, in Spanish 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Miércoles, mayo 5, 2021, entre 1–3 p.m. hora del Pacífico - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Tus Siguientes Pasos -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- Próximos pasos del EDD -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with no time slot, then match the snapshot 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Wednesday, May 5, 2021 - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Your Next Steps -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- EDD Next Steps -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - -exports[`If given an appointment with no time slot, then match the snapshot, in Spanish 1`] = ` -
-

- Claim Status -

-
-

- Pending Eligibility — Phone Interview Scheduled -

-
-
-
- We identified a potential issue that could make you ineligible for benefits. You have a phone interview scheduled for: -
-
- - Miércoles, mayo 5, 2021 - -
-
- - Important - - : If you miss your phone interview, a decision will be made based on the available facts, which could result in your unemployment benefits being delayed or denied. -
-
-
-

- Tus Siguientes Pasos -

-
-
    -
  • - Confirm we have your current phone number. Go to the - - UI Online homepage - - , select - - Profile - - from the main menu, then select - - Contact Information - - . -
  • -
  • - Prepare for the interview. The - <em>Notification of Unemployment Insurance Benefits Eligibility Interview</em> - (DE 4800) includes the questions the interviewer is most likely to ask. -
  • -
  • - If you need to reschedule your interview, select - - Reschedule - - in the Appointments section on your - - UI Online homepage - - . You must reschedule at least one day before the interview. -
  • -
-
-
-
-

- Próximos pasos del EDD -

-
-
    -
  • - We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. -
  • -
-
-
-
-`; - exports[`Scenario 1 matches when there are weeks to certify, on desktop 1`] = `
Date: Thu, 29 Jul 2021 15:20:05 -0700 Subject: [PATCH 14/29] Refactor into separate ClaimSummary component. --- components/ClaimStatus.tsx | 45 ++++++-------------------------- components/ClaimSummary.tsx | 40 ++++++++++++++++++++++++++++ stories/ClaimSummary.stories.tsx | 25 ++++++++++++++++++ types/common.tsx | 5 ++++ 4 files changed, 78 insertions(+), 37 deletions(-) create mode 100644 components/ClaimSummary.tsx create mode 100644 stories/ClaimSummary.stories.tsx diff --git a/components/ClaimStatus.tsx b/components/ClaimStatus.tsx index f2c04aa7..69bce524 100644 --- a/components/ClaimStatus.tsx +++ b/components/ClaimStatus.tsx @@ -1,10 +1,9 @@ import { useTranslation } from 'next-i18next' -import { Appointment } from './Appointment' +import { ClaimSummary } from './ClaimSummary' import { NextSteps } from './NextSteps' import { TextLine } from './TextLine' -import { TransLine } from './TransLine' -import { AppointmentContent, ClaimStatusContent, TransLineContent } from '../types/common' +import { ClaimStatusContent } from '../types/common' export interface ClaimStatusProps extends ClaimStatusContent { loading: boolean @@ -22,46 +21,18 @@ export const ClaimStatus: React.FC = ({ }) => { const { t } = useTranslation(['common', 'claim-status']) - /** - * Nested function to construct the summary containing multiple paragraphs. - */ - function buildSummary( - loading: boolean, - userArrivedFromUioMobile: boolean, - summary: TransLineContent[], - appointment: AppointmentContent | null, - ): JSX.Element[] { - let elements: JSX.Element[] = [] - - // Build generic summary paragraphs. - elements = summary.map((paragraph, index) => ( -
- -
- )) - - // Build scenario 2 appointment. - if (appointment) { - const formattedAppointment = - // Splice it in as the second element. - elements.splice(1, 0, formattedAppointment) - } - - return elements - } - return (

{t('claim-status.title')}

-
{buildSummary(loading, userArrivedFromUioMobile, summary, appointment)}
+ = ({ + loading = false, + userArrivedFromUioMobile = false, + summary, + appointment, +}) => { + let elements: JSX.Element[] = [] + + // Build generic summary paragraphs. + elements = summary.map((paragraph, index) => ( +
+ +
+ )) + + // Insert appointment as second element. + // Currently only needed for Scenario 2. + if (appointment) { + const formattedAppointment = + // Splice it in as the second element. + elements.splice(1, 0, formattedAppointment) + } + console.log(elements) + + return
{elements}
+} diff --git a/stories/ClaimSummary.stories.tsx b/stories/ClaimSummary.stories.tsx new file mode 100644 index 00000000..31e45573 --- /dev/null +++ b/stories/ClaimSummary.stories.tsx @@ -0,0 +1,25 @@ +import { Story, Meta } from '@storybook/react' + +import { ClaimSummary as ClaimSummaryComponent, ClaimSummaryProps } from '../components/ClaimSummary' + +export default { + title: 'Component/Atoms/ClaimSummary', + component: ClaimSummaryComponent, +} as Meta + +const Template: Story = (args) => + +export const ClaimSummary = Template.bind({}) +ClaimSummary.args = { + summary: [ + { + i18nKey: 'claim-status:scenarios.scenario2.summary.0.text', + }, + { + i18nKey: 'claim-status:scenarios.scenario2.summary.1.text', + }, + ], + appointment: { + date: new Date(), + }, +} diff --git a/types/common.tsx b/types/common.tsx index c142de63..b9f0708d 100644 --- a/types/common.tsx +++ b/types/common.tsx @@ -57,6 +57,11 @@ export interface AppointmentContent { timeSlot?: TimeSlot } +export interface ClaimSummaryContent { + summary: TransLineContent[] + appointment: null | AppointmentContent +} + export interface ClaimStatusContent { heading: I18nString summary: TransLineContent[] From ed665bb20a31208456aeccf844b6c0a0da5734d1 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 15:51:49 -0700 Subject: [PATCH 15/29] Refactor appointment translation string using i18n interpolation. --- components/Appointment.tsx | 23 ++++++++--------------- public/locales/en/common.json | 7 +++---- public/locales/es/common.json | 7 +++---- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/components/Appointment.tsx b/components/Appointment.tsx index 09762ae2..1b61b64a 100644 --- a/components/Appointment.tsx +++ b/components/Appointment.tsx @@ -23,30 +23,23 @@ export const Appointment: React.FC = ({ loading = false, appoi if (appointment.timeSlot) { const start = appointment.timeSlot.rangeStart const end = appointment.timeSlot.rangeEnd - let words: string[] = [] + + // Appointment time slots are formatted using i18n's interpolation feature. + // See https://www.i18next.com/translation-function/interpolation // If the times are both am or both pm, the string should look something like: // ", between 1–3 p.m. Pacific time" if (samePeriod(start, end)) { - words = [',', t('time.between'), `${start}–${end}`, t(identifyI18nPeriod(end)), t('time.pacific-time')] + formattedAppointment += t('time.between-range', { range: `${start}–${end}`, ampm: t(identifyI18nPeriod(end)) }) } // If one time is am and one time is pm, the string should look something like: // ", between 10 a.m. and 12 p.m. Pacific time" else { - words = [ - ',', - t('time.between'), - start.toString(), - t(identifyI18nPeriod(start)), - t('time.and'), - end.toString(), - t(identifyI18nPeriod(end)), - t('time.pacific-time'), - ] + formattedAppointment += t('time.between-start-end', { + start: { time: start, ampm: t(identifyI18nPeriod(start)) }, + end: { time: end, ampm: t(identifyI18nPeriod(end)) }, + }) } - - // Join word arrays. - formattedAppointment += words.join(' ') } return ( diff --git a/public/locales/en/common.json b/public/locales/en/common.json index d853a6a8..a580726a 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -41,11 +41,10 @@ "button": "Return to UI Home" }, "time": { - "between": "between", - "and": "and", + "between-range": ", between {{range}} {{ampm}} Pacific time", + "between-start-end": ", between {{start.time}} {{start.ampm}} and {{end.time}} {{end.ampm}} Pacific time", "am": "a.m.", - "pm": "p.m.", - "pacific-time": "Pacific time" + "pm": "p.m." }, "urls": { "edd": { diff --git a/public/locales/es/common.json b/public/locales/es/common.json index a07fd2da..46fa3452 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -41,11 +41,10 @@ "button": "Volver a UI Casa" }, "time": { - "between": "entre", - "and": "y", + "between-range": ", entre {{range}} {{ampm}} hora del Pacífico", + "between-start-end": ", entre {{start.time}} {{start.ampm}} y {{end.time}} {{end.ampm}} hora del Pacífico", "am": "a.m.", - "pm": "p.m.", - "pacific-time": "hora del Pacífico" + "pm": "p.m." }, "urls": { "edd": { From 2814d226a438a617cb1983f3ec75adabb1399be4 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 16:05:24 -0700 Subject: [PATCH 16/29] Refactor types. --- components/ClaimSection.tsx | 1 - components/ClaimStatus.tsx | 5 ++--- components/ClaimSummary.tsx | 7 +++---- stories/ClaimStatus.stories.tsx | 5 ++++- stories/ClaimSummary.stories.tsx | 2 +- tests/components/ClaimStatus.test.tsx | 1 - types/common.tsx | 5 ++--- utils/getClaimStatus.tsx | 8 +++++--- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/components/ClaimSection.tsx b/components/ClaimSection.tsx index 9e96750d..96ce6b62 100644 --- a/components/ClaimSection.tsx +++ b/components/ClaimSection.tsx @@ -22,7 +22,6 @@ export const ClaimSection: React.FC = ({ summary={statusContent.summary} yourNextSteps={statusContent.yourNextSteps} eddNextSteps={statusContent.eddNextSteps} - appointment={statusContent.appointment} /> = ({ summary, yourNextSteps, eddNextSteps, - appointment, }) => { const { t } = useTranslation(['common', 'claim-status']) @@ -30,8 +29,8 @@ export const ClaimStatus: React.FC = ({ = ({ loading = false, userArrivedFromUioMobile = false, - summary, + paragraphs, appointment, }) => { let elements: JSX.Element[] = [] - // Build generic summary paragraphs. - elements = summary.map((paragraph, index) => ( + // Build generic paragraphs. + elements = paragraphs.map((paragraph, index) => (
= ({ // Splice it in as the second element. elements.splice(1, 0, formattedAppointment) } - console.log(elements) return
{elements}
} diff --git a/stories/ClaimStatus.stories.tsx b/stories/ClaimStatus.stories.tsx index ec6f7d20..d49dc4d4 100644 --- a/stories/ClaimStatus.stories.tsx +++ b/stories/ClaimStatus.stories.tsx @@ -12,7 +12,10 @@ const Template: Story = (args) => = (args) => , ) .toJSON() diff --git a/types/common.tsx b/types/common.tsx index b9f0708d..2f29b6e1 100644 --- a/types/common.tsx +++ b/types/common.tsx @@ -58,16 +58,15 @@ export interface AppointmentContent { } export interface ClaimSummaryContent { - summary: TransLineContent[] + paragraphs: TransLineContent[] appointment: null | AppointmentContent } export interface ClaimStatusContent { heading: I18nString - summary: TransLineContent[] + summary: ClaimSummaryContent yourNextSteps: TransLineContent[] eddNextSteps: TransLineContent[] - appointment: null | AppointmentContent } export interface ClaimDetailsContent { diff --git a/utils/getClaimStatus.tsx b/utils/getClaimStatus.tsx index e299c350..9d80f304 100644 --- a/utils/getClaimStatus.tsx +++ b/utils/getClaimStatus.tsx @@ -100,7 +100,7 @@ export function buildAppointment( /** * Get Claim Status summary. */ -export function buildClaimStatusSummary( +export function buildSummaryParagraphs( scenarioObject: ClaimStatusScenarioJson, scenarioString: string, ): TransLineContent[] { @@ -165,9 +165,11 @@ export default function getClaimStatus( return { heading: buildClaimStatusHeading(scenarioType), - summary: buildClaimStatusSummary(scenarioObject, scenarioString), + summary: { + paragraphs: buildSummaryParagraphs(scenarioObject, scenarioString), + appointment: buildAppointment(scenarioType, pendingDetermination), + }, yourNextSteps: buildNextSteps(scenarioObject, scenarioString, 'your-next-steps', continueCertifying), eddNextSteps: buildNextSteps(scenarioObject, scenarioString, 'edd-next-steps'), - appointment: buildAppointment(scenarioType, pendingDetermination), } } From 1d55769601402e5a5e7c3b71cab00b7791dcbd0f Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 16:17:38 -0700 Subject: [PATCH 17/29] Refactor type for Appointment component. --- components/Appointment.tsx | 13 ++- components/ClaimSummary.tsx | 4 +- stories/Appointment.stories.tsx | 4 +- tests/components/Appointment.test.tsx | 113 ++++++++++---------------- 4 files changed, 52 insertions(+), 82 deletions(-) diff --git a/components/Appointment.tsx b/components/Appointment.tsx index 1b61b64a..afb90cc2 100644 --- a/components/Appointment.tsx +++ b/components/Appointment.tsx @@ -6,23 +6,22 @@ import { formatAppointmentDate } from '../utils/formatDate' import { capitalizeFirstLetter } from '../utils/strings' import { identifyI18nPeriod, samePeriod } from '../utils/timeSlot' -export interface AppointmentProps { +export interface AppointmentProps extends AppointmentContent { loading: boolean - appointment: AppointmentContent } -export const Appointment: React.FC = ({ loading = false, appointment }) => { +export const Appointment: React.FC = ({ loading = false, date, timeSlot }) => { const { t, i18n } = useTranslation('common') let formattedAppointment = '' // Format the date portion. - formattedAppointment = capitalizeFirstLetter(formatAppointmentDate(appointment.date, i18n.language)) + formattedAppointment = capitalizeFirstLetter(formatAppointmentDate(date, i18n.language)) // Format the time portion. - if (appointment.timeSlot) { - const start = appointment.timeSlot.rangeStart - const end = appointment.timeSlot.rangeEnd + if (timeSlot) { + const start = timeSlot.rangeStart + const end = timeSlot.rangeEnd // Appointment time slots are formatted using i18n's interpolation feature. // See https://www.i18next.com/translation-function/interpolation diff --git a/components/ClaimSummary.tsx b/components/ClaimSummary.tsx index 64e8eb82..5ea0d2ef 100644 --- a/components/ClaimSummary.tsx +++ b/components/ClaimSummary.tsx @@ -30,7 +30,9 @@ export const ClaimSummary: React.FC = ({ // Insert appointment as second element. // Currently only needed for Scenario 2. if (appointment) { - const formattedAppointment = + const formattedAppointment = ( + + ) // Splice it in as the second element. elements.splice(1, 0, formattedAppointment) } diff --git a/stories/Appointment.stories.tsx b/stories/Appointment.stories.tsx index bd2bf322..db33a654 100644 --- a/stories/Appointment.stories.tsx +++ b/stories/Appointment.stories.tsx @@ -11,7 +11,5 @@ const Template: Story = (args) => ).toJSON() +function renderAppointmentComponent(timeSlot?: TimeSlot): string { + const date = getDateWithOffset(0) + return renderer.create().toJSON() } /** @@ -25,132 +26,102 @@ describe('If given an appointment', () => { }) it('with no time slot, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - } - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + expect(renderAppointmentComponent()).toMatchSnapshot() }) it('with no time slot, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - } act(() => { i18n.changeLanguage('es') }) - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + expect(renderAppointmentComponent()).toMatchSnapshot() act(() => { i18n.changeLanguage('en') }) }) it('with a morning time slot, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 10, - }, + const timeSlot = { + rangeStart: 8, + rangeEnd: 10, } - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() }) it('with a morning time slot, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 10, - }, - } act(() => { i18n.changeLanguage('es') }) - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + const timeSlot = { + rangeStart: 8, + rangeEnd: 10, + } + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() act(() => { i18n.changeLanguage('en') }) }) it('with an afternoon time slot, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 1, - rangeEnd: 3, - }, + const timeSlot = { + rangeStart: 1, + rangeEnd: 3, } - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() }) it('with an afternoon time slot, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 1, - rangeEnd: 3, - }, - } act(() => { i18n.changeLanguage('es') }) - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + const timeSlot = { + rangeStart: 1, + rangeEnd: 3, + } + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() act(() => { i18n.changeLanguage('en') }) }) it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 3, - }, + const timeSlot = { + rangeStart: 8, + rangeEnd: 3, } - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() }) it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 8, - rangeEnd: 3, - }, - } act(() => { i18n.changeLanguage('es') }) - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + const timeSlot = { + rangeStart: 8, + rangeEnd: 3, + } + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() act(() => { i18n.changeLanguage('en') }) }) it('with a time slot that has a nonsense time range, then match the snapshot', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 3, - rangeEnd: 9, - }, + const timeSlot = { + rangeStart: 3, + rangeEnd: 9, } - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() }) it('with a time slot that has a nonsense time range, then match the snapshot, in Spanish', () => { - const appointment = { - date: getDateWithOffset(0), - timeSlot: { - rangeStart: 3, - rangeEnd: 9, - }, - } act(() => { i18n.changeLanguage('es') }) - expect(renderAppointmentComponent(appointment)).toMatchSnapshot() + const timeSlot = { + rangeStart: 3, + rangeEnd: 9, + } + expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() act(() => { i18n.changeLanguage('en') }) From 229d80887496ff1914d4d1aa39f12f92f93c9bd8 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 17:06:29 -0700 Subject: [PATCH 18/29] Validate time slot times. --- tests/utils/timeSlot.test.ts | 10 ++++++++++ utils/timeSlot.ts | 27 ++++++++++++++++++++------- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/tests/utils/timeSlot.test.ts b/tests/utils/timeSlot.test.ts index 12c848a9..637d7676 100644 --- a/tests/utils/timeSlot.test.ts +++ b/tests/utils/timeSlot.test.ts @@ -17,6 +17,16 @@ describe('A time slot string is', () => { expect(badTimeSlot).toBe(null) }) + it('handled if it is a number less than 1', () => { + const badTimeSlot = parseTimeSlot('0-12') + expect(badTimeSlot).toBe(null) + }) + + it('handled if it is a greater than 12', () => { + const badTimeSlot = parseTimeSlot('3-16') + expect(badTimeSlot).toBe(null) + }) + it('handled if the separator is an ndash', () => { const multipleDigits = parseTimeSlot('10–12') expect(multipleDigits.rangeStart).toBe(10) diff --git a/utils/timeSlot.ts b/utils/timeSlot.ts index 40fe7b02..a9a1986b 100644 --- a/utils/timeSlot.ts +++ b/utils/timeSlot.ts @@ -9,24 +9,37 @@ import { I18nString, TimeSlot } from '../types/common' +/** + * Validate times. + * + * @TODO: Log if we receive a time that is outside this range. + */ +export function validTime(time: number): boolean { + return time >= 1 && time <= 12 +} + /** * Parse a time slot from the API gateway. */ export function parseTimeSlot(timeSlot: string): TimeSlot | null { // Time slots are expected to be in the format 10-12, // where the dash can either be a hyphen (-) or an ndash (–) or an mdash (—). + let result: TimeSlot | null = null + const match = /(\d+)[-–—](\d+)/.exec(timeSlot) if (match) { - const formattedTimeSlot: TimeSlot = { - rangeStart: parseInt(match[1]), - rangeEnd: parseInt(match[2]), + const start = parseInt(match[1]) + const end = parseInt(match[2]) + + if (validTime(start) && validTime(end)) { + result = { + rangeStart: start, + rangeEnd: end, + } } - return formattedTimeSlot } // If the arg does not match the regex, return null. - else { - return null - } + return result } /** From 72ee757d6924faab30ceae912c6e7e3377178864 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 17:08:44 -0700 Subject: [PATCH 19/29] Customize Appointment story controls. --- stories/Appointment.stories.tsx | 55 ++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/stories/Appointment.stories.tsx b/stories/Appointment.stories.tsx index db33a654..26c5dc9f 100644 --- a/stories/Appointment.stories.tsx +++ b/stories/Appointment.stories.tsx @@ -5,9 +5,62 @@ import { Appointment as AppointmentComponent, AppointmentProps } from '../compon export default { title: 'Component/Atoms/Appointment', component: AppointmentComponent, + argTypes: { + date: { + description: 'Please ignore the time picker', + control: { + type: 'date', + }, + }, + start: { + name: 'start time', + table: { + type: { + summary: 'number', + }, + }, + control: { + type: 'number', + min: 1, + max: 12, + }, + }, + end: { + name: 'end time', + table: { + type: { + summary: 'number', + }, + }, + control: { + type: 'number', + min: 1, + max: 12, + }, + }, + timeSlot: { + table: { + disable: true, + }, + }, + }, } as Meta -const Template: Story = (args) => +interface StoryAppointmentProps extends AppointmentProps { + date: Date + start?: number + end?: number +} + +const Template: Story = ({ ...args }) => { + if (args.start && args.end) { + args.timeSlot = { + rangeStart: args.start, + rangeEnd: args.end, + } + } + return +} export const Appointment = Template.bind({}) Appointment.args = { From b9789e5a0dd6d3370ec318f8f4cfcca6e236c8fb Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 17:12:20 -0700 Subject: [PATCH 20/29] Fix Claim Summary story nesting. --- stories/ClaimSummary.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stories/ClaimSummary.stories.tsx b/stories/ClaimSummary.stories.tsx index 295a43af..3e1d52aa 100644 --- a/stories/ClaimSummary.stories.tsx +++ b/stories/ClaimSummary.stories.tsx @@ -3,7 +3,7 @@ import { Story, Meta } from '@storybook/react' import { ClaimSummary as ClaimSummaryComponent, ClaimSummaryProps } from '../components/ClaimSummary' export default { - title: 'Component/Atoms/ClaimSummary', + title: 'Component/Atoms/Claim Summary', component: ClaimSummaryComponent, } as Meta From 0f100b22e75b70dffa79d5fe33a3c7b8be105bc7 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 17:41:42 -0700 Subject: [PATCH 21/29] Refactor appointment component tests. --- tests/components/Appointment.test.tsx | 128 ++++++++------------------ 1 file changed, 38 insertions(+), 90 deletions(-) diff --git a/tests/components/Appointment.test.tsx b/tests/components/Appointment.test.tsx index f9e9504c..3e2de58b 100644 --- a/tests/components/Appointment.test.tsx +++ b/tests/components/Appointment.test.tsx @@ -10,7 +10,7 @@ import { getDateWithOffset } from '../../utils/formatDate' * Helper functions. */ -function renderAppointmentComponent(timeSlot?: TimeSlot): string { +function renderAppointmentComponent(timeSlot: TimeSlot | undefined): string { const date = getDateWithOffset(0) return renderer.create().toJSON() } @@ -19,112 +19,60 @@ function renderAppointmentComponent(timeSlot?: TimeSlot): string { * Appointment snapshot tests. */ -/* eslint-disable @typescript-eslint/no-floating-promises */ -describe('If given an appointment', () => { - beforeAll(() => { - MockDate.set('2021-05-05') - }) +beforeAll(() => { + MockDate.set('2021-05-05') +}) - it('with no time slot, then match the snapshot', () => { - expect(renderAppointmentComponent()).toMatchSnapshot() - }) +// Each test case should be: +// [test description, timeSlot.rangeStart, timeSlot.rangeEnd] +const testCases = [ + ['with no time slot, then match the snapshot', null, null], + ['with a morning time slot, then match the snapshot', 8, 10], + ['with an afternoon time slot, then match the snapshot', 1, 3], + ['with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', 8, 3], + ['with a time slot that has a nonsense time range, then match the snapshot', 3, 9], +] - it('with no time slot, then match the snapshot, in Spanish', () => { - act(() => { - i18n.changeLanguage('es') - }) - expect(renderAppointmentComponent()).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - - it('with a morning time slot, then match the snapshot', () => { - const timeSlot = { - rangeStart: 8, - rangeEnd: 10, +// Use describe.each() to DRY up the tests. +// See https://jestjs.io/docs/api#describeeachtablename-fn-timeout +describe.each(testCases)('If given an appointment', (description: string, start: number | null, end: number | null) => { + // Construct the timeslot argument. + let timeSlot: TimeSlot | undefined + if (start && end) { + timeSlot = { + rangeStart: start, + rangeEnd: end, } - expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - }) + } - it('with a morning time slot, then match the snapshot, in Spanish', () => { - act(() => { - i18n.changeLanguage('es') - }) - const timeSlot = { - rangeStart: 8, - rangeEnd: 10, - } + // Run through the test cases first in English. + it(`${description}`, () => { expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) }) - it('with an afternoon time slot, then match the snapshot', () => { - const timeSlot = { - rangeStart: 1, - rangeEnd: 3, - } - expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - }) + // Run through the test cases again in Spanish. + it(`${description}, in Spanish`, () => { + // Change the language to Spanish. - it('with an afternoon time slot, then match the snapshot, in Spanish', () => { - act(() => { - i18n.changeLanguage('es') - }) - const timeSlot = { - rangeStart: 1, - rangeEnd: 3, - } - expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - - it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot', () => { - const timeSlot = { - rangeStart: 8, - rangeEnd: 3, - } - expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - }) + // The call to changeLanguage() must be wrapped in act(), otherwise Jest/react + // complains. + // See https://reactjs.org/link/wrap-tests-with-act - it('with a time slot that starts in the morning and ends in the afternoon, then match the snapshot, in Spanish', () => { + // Disable floating promises lint check. eslint really wants us to handle the Promise + // returned by changeLanguage(), but it doesn't appear necessary to this test. + // This can be revisited and refactored in the future if necessary. + /* eslint-disable @typescript-eslint/no-floating-promises */ act(() => { i18n.changeLanguage('es') }) - const timeSlot = { - rangeStart: 8, - rangeEnd: 3, - } - expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - act(() => { - i18n.changeLanguage('en') - }) - }) - it('with a time slot that has a nonsense time range, then match the snapshot', () => { - const timeSlot = { - rangeStart: 3, - rangeEnd: 9, - } + // Run the actual test. expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - }) - it('with a time slot that has a nonsense time range, then match the snapshot, in Spanish', () => { - act(() => { - i18n.changeLanguage('es') - }) - const timeSlot = { - rangeStart: 3, - rangeEnd: 9, - } - expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() + // Change the language back to Spanish so the first it() renders correctly in English. act(() => { i18n.changeLanguage('en') }) + /* eslint-enable @typescript-eslint/no-floating-promises */ }) }) -/* eslint-enable @typescript-eslint/no-floating-promises */ From 5aaba29d875bb00bf0047460f0e93b925c5b275f Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 18:00:49 -0700 Subject: [PATCH 22/29] Add document-level comment for strings util. --- utils/strings.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/strings.ts b/utils/strings.ts index c783d7aa..dedfe1e5 100644 --- a/utils/strings.ts +++ b/utils/strings.ts @@ -1,3 +1,7 @@ +/** + * Utility file for helper functions related to strings. + */ + export function capitalizeFirstLetter(string: string): string { return string.charAt(0).toUpperCase() + string.slice(1) } From 7388dc4e1f40111202e5f82b243c1eadb1425b80 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 18:01:19 -0700 Subject: [PATCH 23/29] Add key to all claim summary components. --- components/ClaimSummary.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ClaimSummary.tsx b/components/ClaimSummary.tsx index 5ea0d2ef..ed1503c3 100644 --- a/components/ClaimSummary.tsx +++ b/components/ClaimSummary.tsx @@ -31,7 +31,7 @@ export const ClaimSummary: React.FC = ({ // Currently only needed for Scenario 2. if (appointment) { const formattedAppointment = ( - + ) // Splice it in as the second element. elements.splice(1, 0, formattedAppointment) From 236a9c164a5d48cbd60ada750adcc1af6f391b2c Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 18:28:07 -0700 Subject: [PATCH 24/29] Add another comment about act(). --- tests/components/Appointment.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/components/Appointment.test.tsx b/tests/components/Appointment.test.tsx index 3e2de58b..2a7f779c 100644 --- a/tests/components/Appointment.test.tsx +++ b/tests/components/Appointment.test.tsx @@ -57,6 +57,7 @@ describe.each(testCases)('If given an appointment', (description: string, start: // The call to changeLanguage() must be wrapped in act(), otherwise Jest/react // complains. // See https://reactjs.org/link/wrap-tests-with-act + // and https://reactjs.org/docs/test-renderer.html#testrendereract // Disable floating promises lint check. eslint really wants us to handle the Promise // returned by changeLanguage(), but it doesn't appear necessary to this test. From d22837f2ba6a841b914d4c64742e8281c54a722f Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 22:47:52 -0400 Subject: [PATCH 25/29] Remove use of unnecessary helper. --- tests/components/Appointment.test.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/components/Appointment.test.tsx b/tests/components/Appointment.test.tsx index 2a7f779c..92dd23ae 100644 --- a/tests/components/Appointment.test.tsx +++ b/tests/components/Appointment.test.tsx @@ -1,17 +1,16 @@ -import MockDate from 'mockdate' import renderer, { act } from 'react-test-renderer' import i18n from '../jest-i18n' import { Appointment } from '../../components/Appointment' import { TimeSlot } from '../../types/common' -import { getDateWithOffset } from '../../utils/formatDate' /** * Helper functions. */ function renderAppointmentComponent(timeSlot: TimeSlot | undefined): string { - const date = getDateWithOffset(0) + // Set a random date in PT time. + const date = new Date('2021-05-05T00:00:00.000-0800') return renderer.create().toJSON() } @@ -19,10 +18,6 @@ function renderAppointmentComponent(timeSlot: TimeSlot | undefined): string { * Appointment snapshot tests. */ -beforeAll(() => { - MockDate.set('2021-05-05') -}) - // Each test case should be: // [test description, timeSlot.rangeStart, timeSlot.rangeEnd] const testCases = [ From 838d2afbe11c9ede1804f3246e9b2bee7c40e44b Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Thu, 29 Jul 2021 22:48:59 -0400 Subject: [PATCH 26/29] Eliminate issue with differences in server time resulting in test failures. --- tests/testHelpers.ts | 4 ++-- tests/utils/getClaimStatus.test.tsx | 6 +++--- utils/apiGatewayStub.tsx | 6 +++--- utils/formatDate.ts | 11 +++-------- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/tests/testHelpers.ts b/tests/testHelpers.ts index c65a9485..e38d8cd4 100644 --- a/tests/testHelpers.ts +++ b/tests/testHelpers.ts @@ -3,7 +3,7 @@ */ import { PendingDetermination } from '../types/common' -import { formatFromApiGateway, getDateWithOffset } from '../utils/formatDate' +import { formatFromApiGateway } from '../utils/formatDate' export function getMockPendingDetermination(): PendingDetermination { const pendingDetermination: PendingDetermination = { @@ -22,6 +22,6 @@ export function getMockPendingDetermination(): PendingDetermination { export function getPendingDeterminationWithScheduleDate(offset = 1): PendingDetermination { const pendingDetermination = getMockPendingDetermination() pendingDetermination.determinationStatus = 'Random string' // Can be anything other than one of NonPendingDeterminationValues - pendingDetermination.scheduleDate = formatFromApiGateway(getDateWithOffset(offset)) + pendingDetermination.scheduleDate = formatFromApiGateway(offset) return pendingDetermination } diff --git a/tests/utils/getClaimStatus.test.tsx b/tests/utils/getClaimStatus.test.tsx index d62d5927..c59dfa1e 100644 --- a/tests/utils/getClaimStatus.test.tsx +++ b/tests/utils/getClaimStatus.test.tsx @@ -1,7 +1,7 @@ import MockDate from 'mockdate' import { getPendingDeterminationWithScheduleDate } from '../testHelpers' -import { getDateWithOffset } from '../../utils/formatDate' +import { formatFromApiGateway, parseApiGatewayDate } from '../../utils/formatDate' import { buildAppointment, buildClaimStatusHeading } from '../../utils/getClaimStatus' import { ScenarioType } from '../../utils/getScenarioContent' import { getNumericEnumKeys } from '../../utils/numericEnum' @@ -25,7 +25,7 @@ describe('An appointment is', () => { it('returned with a time slot if there is a time slot value', () => { const pendingDetermination = getPendingDeterminationWithScheduleDate(0) - const expectedDate = getDateWithOffset(0) + const expectedDate = parseApiGatewayDate(formatFromApiGateway(0)) pendingDetermination.timeSlotDesc = '10-12' const expectedTimeSlot = { @@ -40,7 +40,7 @@ describe('An appointment is', () => { it('returned with no time slot if there is no time slot value', () => { const pendingDetermination = getPendingDeterminationWithScheduleDate(0) - const expectedDate = getDateWithOffset(0) + const expectedDate = parseApiGatewayDate(formatFromApiGateway(0)) const appointment = buildAppointment(ScenarioType.Scenario2, pendingDetermination) expect(appointment.date).toStrictEqual(expectedDate) expect(appointment.timeSlot).toBe(undefined) diff --git a/utils/apiGatewayStub.tsx b/utils/apiGatewayStub.tsx index 70314571..30a7472b 100644 --- a/utils/apiGatewayStub.tsx +++ b/utils/apiGatewayStub.tsx @@ -6,7 +6,7 @@ import { Claim, PendingDetermination } from '../types/common' import { ScenarioType } from '../utils/getScenarioContent' -import { formatFromApiGateway, getDateWithOffset } from '../utils/formatDate' +import { formatFromApiGateway } from '../utils/formatDate' /** * Stub the API gateway response for a given scenario. @@ -52,7 +52,7 @@ export default function apiGatewayStub( case ScenarioType.Scenario2: pendingDetermination.determinationStatus = '' - pendingDetermination.scheduleDate = formatFromApiGateway(getDateWithOffset(7)) + pendingDetermination.scheduleDate = formatFromApiGateway(7) pendingDetermination.timeSlotDesc = '1-3' claim.pendingDetermination = [pendingDetermination] claim.hasCertificationWeeksAvailable = hasCertificationWeeksAvailable @@ -60,7 +60,7 @@ export default function apiGatewayStub( case ScenarioType.Scenario3: pendingDetermination.determinationStatus = '' - pendingDetermination.scheduleDate = formatFromApiGateway(getDateWithOffset(-7)) + pendingDetermination.scheduleDate = formatFromApiGateway(-7) claim.pendingDetermination = [pendingDetermination] claim.hasCertificationWeeksAvailable = hasCertificationWeeksAvailable break diff --git a/utils/formatDate.ts b/utils/formatDate.ts index 6fbd2abf..ac125d39 100644 --- a/utils/formatDate.ts +++ b/utils/formatDate.ts @@ -47,22 +47,17 @@ export function parseApiGatewayDate(dateString: ApiGatewayDateString): Date { /** * Return a string that matches the API gateway format for datetimes. - */ -export function formatFromApiGateway(date: Date): string { - return format(date, apiGatewayFormat) -} - -/** + * * Create a Date object that is offset from today. * * Note: This returns a date at either midnight or 1am, depending on whether it is * currently PST (-8) or PDT (-7). */ -export function getDateWithOffset(daysOffset = 1): Date { +export function formatFromApiGateway(daysOffset = 1): string { const today = new Date() today.setDate(today.getDate() + daysOffset) today.setUTCHours(8, 0, 0, 0) - return today + return format(today, apiGatewayFormat) } /** From 8247a1691b33da632d011af17a9aceefa603295b Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Fri, 30 Jul 2021 10:08:47 -0700 Subject: [PATCH 27/29] Fix comment typo. --- tests/components/Appointment.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/Appointment.test.tsx b/tests/components/Appointment.test.tsx index 92dd23ae..77c66b5d 100644 --- a/tests/components/Appointment.test.tsx +++ b/tests/components/Appointment.test.tsx @@ -65,7 +65,7 @@ describe.each(testCases)('If given an appointment', (description: string, start: // Run the actual test. expect(renderAppointmentComponent(timeSlot)).toMatchSnapshot() - // Change the language back to Spanish so the first it() renders correctly in English. + // Change the language back to English so the first it() renders correctly in English. act(() => { i18n.changeLanguage('en') }) From 67882ed387681993da9be123b8547967dee0fbf7 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Fri, 30 Jul 2021 10:10:09 -0700 Subject: [PATCH 28/29] Use integers in test instead of unnecessary consts. --- tests/utils/timeSlot.test.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/utils/timeSlot.test.ts b/tests/utils/timeSlot.test.ts index 637d7676..083a2513 100644 --- a/tests/utils/timeSlot.test.ts +++ b/tests/utils/timeSlot.test.ts @@ -79,22 +79,16 @@ describe('Comparing time slots results in', () => { // Test samePeriod() describe('Two times are', () => { - // Shared test values. - const eightAm = 8 - const tenAm = 10 - const onePm = 1 - const threePm = 3 - it('the same period if they are both AM', () => { - expect(samePeriod(eightAm, tenAm)).toBe(true) + expect(samePeriod(8, 10)).toBe(true) }) it('the same period if they are both PM', () => { - expect(samePeriod(onePm, threePm)).toBe(true) + expect(samePeriod(1, 3)).toBe(true) }) it('not the same period if one is AM and one is PM', () => { - expect(samePeriod(eightAm, threePm)).toBe(false) + expect(samePeriod(8, 3)).toBe(false) }) }) From 8b81264444aedc2aa2f0a02e72499166e0834068 Mon Sep 17 00:00:00 2001 From: Rocket ! Date: Fri, 30 Jul 2021 10:26:41 -0700 Subject: [PATCH 29/29] Update snapshots. --- .../__snapshots__/ClaimStatus.test.tsx.snap | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap index c60b834a..cf69c6c7 100644 --- a/tests/components/__snapshots__/ClaimStatus.test.tsx.snap +++ b/tests/components/__snapshots__/ClaimStatus.test.tsx.snap @@ -503,6 +503,18 @@ exports[`Scenario 2 matches when there are weeks to certify, on desktop 1`] = ` className="next-step" > We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
    +
  • + If you do not receive a call from the EDD at your scheduled appointment time, we may have canceled your appointment because we confirmed your eligibility or resolved the issue before your interview. +
  • +
  • + If your appointment has been canceled, it will no longer display on your UI Online homepage. +
  • +
@@ -635,6 +647,18 @@ exports[`Scenario 2 matches when there are weeks to certify, on mobile 1`] = ` className="next-step" > We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
    +
  • + If you do not receive a call from the EDD at your scheduled appointment time, we may have canceled your appointment because we confirmed your eligibility or resolved the issue before your interview. +
  • +
  • + If your appointment has been canceled, it will no longer display on your UI Online homepage. +
  • +
@@ -756,6 +780,18 @@ exports[`Scenario 2 matches when there aren't weeks to certify, on desktop 1`] = className="next-step" > We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
    +
  • + If you do not receive a call from the EDD at your scheduled appointment time, we may have canceled your appointment because we confirmed your eligibility or resolved the issue before your interview. +
  • +
  • + If your appointment has been canceled, it will no longer display on your UI Online homepage. +
  • +
@@ -877,6 +913,18 @@ exports[`Scenario 2 matches when there aren't weeks to certify, on mobile 1`] = className="next-step" > We will call you during your scheduled interview time. Your caller ID may show “St of CA EDD” or the UI Customer Service number 1-800-300-5616. +
    +
  • + If you do not receive a call from the EDD at your scheduled appointment time, we may have canceled your appointment because we confirmed your eligibility or resolved the issue before your interview. +
  • +
  • + If your appointment has been canceled, it will no longer display on your UI Online homepage. +
  • +
@@ -964,6 +1012,29 @@ exports[`Scenario 3 matches when there are weeks to certify, on desktop 1`] = ` className="next-step" > We will determine your eligibility. +
    +
  • + If you are found eligible and no other issues are identified, we will pay you for all pending weeks. +
  • +
  • + If you are found not eligible, we will mail you a + <em>Notice of Determination</em> + (DE 1080CZ) with the reasons you were denied benefits and an + <em>Appeal Form</em> + (DE 1000M). If you disagree with the decision, you have the right to appeal. +
  • +
  • + If you are paid benefits and are later found not eligible, we will also mail you a + <em>Notice of Overpayment</em> + (DE 1444) that explains why you were overpaid. +
  • +
@@ -1051,6 +1122,29 @@ exports[`Scenario 3 matches when there are weeks to certify, on mobile 1`] = ` className="next-step" > We will determine your eligibility. +
    +
  • + If you are found eligible and no other issues are identified, we will pay you for all pending weeks. +
  • +
  • + If you are found not eligible, we will mail you a + <em>Notice of Determination</em> + (DE 1080CZ) with the reasons you were denied benefits and an + <em>Appeal Form</em> + (DE 1000M). If you disagree with the decision, you have the right to appeal. +
  • +
  • + If you are paid benefits and are later found not eligible, we will also mail you a + <em>Notice of Overpayment</em> + (DE 1444) that explains why you were overpaid. +
  • +
@@ -1127,6 +1221,29 @@ exports[`Scenario 3 matches when there aren't weeks to certify, on desktop 1`] = className="next-step" > We will determine your eligibility. +
    +
  • + If you are found eligible and no other issues are identified, we will pay you for all pending weeks. +
  • +
  • + If you are found not eligible, we will mail you a + <em>Notice of Determination</em> + (DE 1080CZ) with the reasons you were denied benefits and an + <em>Appeal Form</em> + (DE 1000M). If you disagree with the decision, you have the right to appeal. +
  • +
  • + If you are paid benefits and are later found not eligible, we will also mail you a + <em>Notice of Overpayment</em> + (DE 1444) that explains why you were overpaid. +
  • +
@@ -1203,6 +1320,29 @@ exports[`Scenario 3 matches when there aren't weeks to certify, on mobile 1`] = className="next-step" > We will determine your eligibility. +
    +
  • + If you are found eligible and no other issues are identified, we will pay you for all pending weeks. +
  • +
  • + If you are found not eligible, we will mail you a + <em>Notice of Determination</em> + (DE 1080CZ) with the reasons you were denied benefits and an + <em>Appeal Form</em> + (DE 1000M). If you disagree with the decision, you have the right to appeal. +
  • +
  • + If you are paid benefits and are later found not eligible, we will also mail you a + <em>Notice of Overpayment</em> + (DE 1444) that explains why you were overpaid. +
  • +