diff --git a/src/applications/ivc-champva/10-10D/components/CustomPrefillAlert.jsx b/src/applications/ivc-champva/10-10D/components/CustomPrefillAlert.jsx
new file mode 100644
index 000000000000..0c8f24cd1d94
--- /dev/null
+++ b/src/applications/ivc-champva/10-10D/components/CustomPrefillAlert.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+
+/**
+ * Displays a custom alert based on the current `certifierRole` value.
+ * Used to alert the user when we automatically fill in some portions
+ * of the form based on their previous answers, e.g., adding an applicant
+ * with the certifier's information if the certifier specified that they
+ * were applying for themselves.
+ * @param {object} formData Standard formdata object
+ * @param {string} role Value we expect certifierRole to have if we are to display this message
+ * @param {string} msg Optional custom text to display in our alert
+ * @returns
+ */
+export default function CustomPrefillMessage(formData, role, msg) {
+ const text =
+ msg ||
+ 'We’ve prefilled some details based on information you provided earlier in this form. If you need to make changes, you can edit on this screen.';
+ const certifierRole =
+ formData.certifierRole ?? formData['view:certifierRole'];
+ if (certifierRole && certifierRole === role)
+ return (
+
+ Note: {text}
+
+ We’ll send any important information about this application + to this address. +
+ {CustomPrefillMessage(formData, 'sponsor')} + > + ), ), sponsorAddress: { ...addressUI({ @@ -500,15 +519,14 @@ const formConfig = { title: 'Applicant information', path: 'applicant-info', uiSchema: { - ...titleUI('Applicant name and date of birth', () => ( + ...titleUI('Applicant name and date of birth', ({ formData }) => ( + // Prefill message conditionally displays based on `certifierRole` <> - Enter the information for any applicants you want to enroll in - CHAMPVA benefits. -+ Enter the information for any applicants you want to enroll in + CHAMPVA benefits. +
+ {CustomPrefillMessage(formData, 'applicant')} > )), applicants: { @@ -624,11 +642,20 @@ const formConfig = { ...titleUI( ({ formData }) => `${applicantWording(formData)} mailing address`, + ({ formData, formContext }) => { + const txt = + 'We’ll send any important information about your application to this address'; + // Prefill message conditionally displays based on `certifierRole` + return formContext.pagePerItemIndex === '0' ? ( + <> +{txt}
+ {CustomPrefillMessage(formData, 'applicant')} + > + ) : ( +{txt}
+ ); + }, ), - 'view:description': { - 'ui:description': - 'We’ll send any important information about your application to this address.', - }, applicantAddress: { ...addressUI({ labels: { @@ -642,7 +669,6 @@ const formConfig = { }, schema: applicantListSchema([], { titleSchema, - 'view:description': blankSchema, applicantAddress: addressSchema(), }), }, @@ -657,8 +683,24 @@ const formConfig = { items: { ...titleUI( ({ formData }) => - `${applicantWording(formData)} contact information`, - 'This information helps us contact you faster if we need to follow up with you about your application', + `${applicantWording(formData)} mailing address`, + ({ formData, formContext }) => { + const txt = `We'll use this information to contact ${applicantWording( + formData, + false, + false, + true, + )} if we need to follow up about this application.`; + // Prefill message conditionally displays based on `certifierRole` + return formContext.pagePerItemIndex === '0' ? ( + <> +{txt}
+ {CustomPrefillMessage(formData, 'applicant')} + > + ) : ( +{txt}
+ ); + }, ), applicantPhone: phoneUI(), applicantEmailAddress: emailUI(), diff --git a/src/applications/ivc-champva/10-10D/config/submitTransformer.js b/src/applications/ivc-champva/10-10D/config/submitTransformer.js index 28d4299658db..c1af3461484c 100644 --- a/src/applications/ivc-champva/10-10D/config/submitTransformer.js +++ b/src/applications/ivc-champva/10-10D/config/submitTransformer.js @@ -13,6 +13,12 @@ function fmtDate(date) { : date; } +// Returns list of object keys where obj[key] === true. Used +// to get the list of relationships a certifier has w/ the applicants: +function trueKeysOnly(obj) { + return Object.keys(obj ?? {}).filter(k => obj[k] === true); +} + // Simplify a relationship object from (potentially) multiple nested objects to a single string function transformRelationship(obj) { if (typeof obj === 'string') return obj; @@ -107,8 +113,7 @@ export default function transformForSubmit(formConfig, form) { // If certifier is also applicant, we don't need to fill out the // bottom "Certification" section of the PDF: certification: - transformedData?.certifierRelationship?.relationshipToVeteran - ?.applicant === true + transformedData?.certifierRole === 'applicant' ? { date: currentDate } : { date: currentDate, @@ -116,9 +121,10 @@ export default function transformForSubmit(formConfig, form) { middleInitial: transformedData?.certifierName?.middle || '', firstName: transformedData?.certifierName?.first || '', phoneNumber: transformedData?.certifierPhone || '', - relationship: transformRelationship( - transformedData?.certifierRelationship, - ), + // will produce string list of checkboxgroup keys (e.g., "spouse; child") + relationship: trueKeysOnly( + transformedData?.certifierRelationship?.relationshipToVeteran, + ).join('; '), streetAddress: transformedData?.certifierAddress?.streetCombined || '', city: transformedData?.certifierAddress?.city || '', @@ -156,12 +162,7 @@ export default function transformForSubmit(formConfig, form) { dataPostTransform.supportingDocs = dataPostTransform.supportingDocs .flat() .concat(supDocs); - // TODO - remove usage of `certifierRole` in vets-api - dataPostTransform.certifierRole = - dataPostTransform?.certifierRelationship?.relationshipToVeteran - ?.applicant === true - ? 'applicant' - : 'other'; + dataPostTransform.certifierRole = transformedData.certifierRole; dataPostTransform.statementOfTruthSignature = transformedData.statementOfTruthSignature; // `primaryContactInfo` is who BE callback API emails if there's a notification event diff --git a/src/applications/ivc-champva/10-10D/helpers/utilities.js b/src/applications/ivc-champva/10-10D/helpers/utilities.js index 08bf96d0c1b9..265eef2f5263 100644 --- a/src/applications/ivc-champva/10-10D/helpers/utilities.js +++ b/src/applications/ivc-champva/10-10D/helpers/utilities.js @@ -54,24 +54,12 @@ export function sponsorWording(formData, isPosessive = true, cap = true) { * array. This is used to add the certifier info to the first applicant * slot so users don't have to enter info twice if the certifier is also an app. * @param {object} formData standard formData object - * @param {string} path formconfig page path of the page where this function should apply * @param {object} name standard fullNameUI name to populate * @param {string} email email address to populate * @param {string} phone phone number to populate * @param {object} address standard addressUI address object to populate */ -export function populateFirstApplicant( - formData, - path, - name, - email, - phone, - address, -) { - // Make sure we apply this change when the user is on the certifier relationship - // page, as firing later in the form would potentially add duplicate info: - if (!window.location.href.endsWith(path)) return formData; - +export function populateFirstApplicant(formData, name, email, phone, address) { const modifiedFormData = formData; // changes will affect original formData const newApplicant = { applicantName: name, @@ -103,12 +91,20 @@ export function populateFirstApplicant( // Only show address dropdown if we're not the certifier // AND there's another address present to choose from: export function page15aDepends(formData, index) { - const certifierIsApp = - get('certifierRelationship.relationshipToVeteran.applicant', formData) === - true; + const certifierIsApp = get('certifierRole', formData) === 'applicant'; const certAddress = get('street', formData?.certifierAddress); return ( (index && index > 0) || (certAddress && !(certifierIsApp && index === 0)) ); } + +// Compare two objects (with the same keys) and identify differences +export function objDiff(obj1, obj2, ignoreViewOnlyProps = true) { + return Object.keys(obj1).filter( + k => + (obj1[k] && obj2[k]) !== undefined && + obj1[k] !== obj2[k] && + !(ignoreViewOnlyProps && k.includes('view:')), + ); +} diff --git a/src/applications/ivc-champva/10-10D/helpers/validations.js b/src/applications/ivc-champva/10-10D/helpers/validations.js new file mode 100644 index 000000000000..6c862a369e93 --- /dev/null +++ b/src/applications/ivc-champva/10-10D/helpers/validations.js @@ -0,0 +1,99 @@ +import { objDiff } from './utilities'; +import { makeHumanReadable } from '../../shared/utilities'; + +/* +This validation checks if the `certProp` value matches the corresponding +`appProp` or `sponsorProp` entry (since the certifier may be either +an applicant or the sponsor). Helps ensure their information is entered +consistently across the form. +*/ +export const fieldsMustMatchValidation = ( + errors, + page, + formData, + certProp, + appProp, + sponsorProp, +) => { + let target; // will populate with form data prop we want to compare against + if (formData.certifierRole === 'applicant') { + target = formData?.applicants?.[0]?.[appProp]; + } else if (formData.certifierRole === 'sponsor') { + target = formData[sponsorProp]; + } else { + return; // This validation is not applicable here. + } + + if (target === undefined) return; + + // E.g.: `certifierName` => `Name`: + const friendlyName = makeHumanReadable(certProp) + .toLowerCase() + .split(' ') + .at(-1); + + // For string props like phones/emails: + if (typeof target === 'string' && page[certProp] !== target) { + errors[certProp].addError( + `Must match corresponding ${ + formData.certifierRole + } ${friendlyName}: ${target}`, + ); + } else { + // Identify which fields of the multi-field name object are different (e.g., address fields): + const diff = objDiff(page[certProp], target); + if (target && diff.length > 0) { + diff.forEach(k => + errors[certProp][k].addError( + `Must match corresponding ${ + formData.certifierRole + } ${friendlyName}: ${target[k]}`, + ), + ); + } + } +}; + +export const certifierNameValidation = (errors, page, formData) => { + return fieldsMustMatchValidation( + errors, + page, + formData, + 'certifierName', + 'applicantName', + 'veteransFullName', + ); +}; + +export const certifierAddressValidation = (errors, page, formData) => { + return fieldsMustMatchValidation( + errors, + page, + formData, + 'certifierAddress', + 'applicantAddress', + 'sponsorAddress', + ); +}; + +export const certifierPhoneValidation = (errors, page, formData) => { + return fieldsMustMatchValidation( + errors, + page, + formData, + 'certifierPhone', + 'applicantPhone', + 'sponsorPhone', + ); +}; + +export const certifierEmailValidation = (errors, page, formData) => { + return fieldsMustMatchValidation( + errors, + page, + formData, + 'certifierEmail', + 'applicantEmailAddress', + '_undefined', // Sponsor has no email field + ); +}; diff --git a/src/applications/ivc-champva/10-10D/pages/SignerContactInfoPage.jsx b/src/applications/ivc-champva/10-10D/pages/SignerContactInfoPage.jsx new file mode 100644 index 000000000000..8e7da694d141 --- /dev/null +++ b/src/applications/ivc-champva/10-10D/pages/SignerContactInfoPage.jsx @@ -0,0 +1,126 @@ +/* eslint-disable react/sort-prop-types */ +import React from 'react'; +import PropTypes from 'prop-types'; +import SchemaForm from '@department-of-veterans-affairs/platform-forms-system/SchemaForm'; +import { + titleUI, + titleSchema, + phoneSchema, + phoneUI, + emailSchema, + emailUI, +} from 'platform/forms-system/src/js/web-component-patterns'; +import FormNavButtons from '~/platform/forms-system/src/js/components/FormNavButtons'; +import { populateFirstApplicant } from '../helpers/utilities'; +import { + certifierPhoneValidation, + certifierEmailValidation, +} from '../helpers/validations'; + +export const signerContactInfoPage = { + uiSchema: { + ...titleUI( + 'Your contact information', + 'We use this information to contact you if we have more questions.', + ), + certifierPhone: phoneUI(), + certifierEmail: emailUI(), + 'ui:validations': [certifierPhoneValidation, certifierEmailValidation], + }, + schema: { + type: 'object', + required: ['certifierPhone', 'certifierEmail'], + properties: { + titleSchema, + certifierPhone: phoneSchema, + certifierEmail: emailSchema, + }, + }, +}; + +export function signerContactOnGoForward(props) { + const formData = props.data; // changes made here will reflect in global formData; + if (props?.data?.certifierRole === 'applicant') { + populateFirstApplicant( + formData, + formData.certifierName, + formData.certifierEmail, + formData.certifierPhone, + formData.certifierAddress, + ); + } else if (props?.data?.certifierRole === 'sponsor') { + // Populate some sponsor fields with certifier info: + formData.sponsorIsDeceased = false; + formData.veteransFullName = formData.certifierName; + formData.sponsorAddress = formData.certifierAddress; + formData.sponsorPhone = formData.certifierPhone; + } + + if (formData?.applicants?.[0]) { + // This is so we have an accurate `certifierRole` prop inside the + // list loop where that context is normally unavailable: + formData.applicants[0]['view:certifierRole'] = formData?.certifierRole; + } +} + +/** @type {CustomPageType} */ +export function SignerContactInfoPage(props) { + const updateButton = ( + // eslint-disable-next-line @department-of-veterans-affairs/prefer-button-component + + ); + + return ( +{descriptionText(formData)}
+ {CustomPrefillMessage(formData, 'sponsor')} + > + ), ), veteransFullName: fullNameUI(), sponsorDob: dateOfBirthUI(), diff --git a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sa-cs-medab.json b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sa-cs-medab.json index 5acbd0e81907..62abda78fdf3 100644 --- a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sa-cs-medab.json +++ b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sa-cs-medab.json @@ -3,13 +3,13 @@ "data": { "applicants": [ { - "applicantPhone": "2341232345", + "applicantPhone": "1231231234", "applicantEmailAddress": "certifier@email.gov", "applicantAddress": { "country": "USA", - "street": "321 Street Av", - "city": "Cityburg", - "state": "AS", + "street": "123 Certifier Street", + "city": "CertTown", + "state": "AK", "postalCode": "12312" }, "applicantSSN": { @@ -85,13 +85,7 @@ "suffix": "Sr." }, "sponsorDob": "1999-01-01", - "certifierRelationship": { - "relationshipToVeteran": { - "applicant": true, - "spouse": false, - "thirdParty": true - } - }, + "certifierRole": "applicant", "certifierPhone": "1231231234", "certifierEmail": "certifier@email.gov", "certifierAddress": { diff --git a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sd-cb-ohi.json b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sd-cb-ohi.json index 162b56cd6783..a54e673f7fb4 100644 --- a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sd-cb-ohi.json +++ b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/app-sd-cb-ohi.json @@ -70,6 +70,7 @@ "ssn": { "ssn": "123123123" }, + "certifierRole": "other", "certifierRelationship": { "relationshipToVeteran": { "spouse": true, diff --git a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/cert-sd-spoused.json b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/cert-sd-spoused.json index 9f113bef9bd1..ff07929803df 100644 --- a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/cert-sd-spoused.json +++ b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/cert-sd-spoused.json @@ -47,6 +47,7 @@ "last": "Jones" }, "sponsorDob": "1950-01-01", + "certifierRole": "other", "certifierRelationship": { "relationshipToVeteran": { "spouse": false, diff --git a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/maximal-test.json b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/maximal-test.json index 1e191a67f51b..e77fa6dfb084 100644 --- a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/maximal-test.json +++ b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/maximal-test.json @@ -191,6 +191,7 @@ "last": "Jones" }, "sponsorDob": "1950-01-01", + "certifierRole": "other", "certifierRelationship": { "relationshipToVeteran": { "spouse": true, diff --git a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/test-data.json b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/test-data.json index c228fb817da3..474fe6e43bed 100644 --- a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/test-data.json +++ b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/test-data.json @@ -42,6 +42,7 @@ "first": "Joe", "last": "Johnson" }, + "certifierRole": "other", "certifierRelationship": { "relationshipToVeteran": { "spouse": true, diff --git a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/vet-2a-spouse-child-medabd-ohi.json b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/vet-2a-spouse-child-medabd-ohi.json index 46f0091efb60..c61f33a1cd00 100644 --- a/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/vet-2a-spouse-child-medabd-ohi.json +++ b/src/applications/ivc-champva/10-10D/tests/e2e/fixtures/data/vet-2a-spouse-child-medabd-ohi.json @@ -129,6 +129,7 @@ "first": "Sponsor", "last": "Jones" }, + "certifierRole": "other", "certifierRelationship": { "relationshipToVeteran": { "spouse": true, diff --git a/src/applications/ivc-champva/10-10D/tests/unit/config/form.unit.spec.jsx b/src/applications/ivc-champva/10-10D/tests/unit/config/form.unit.spec.jsx index caa68778b00d..eafd8f6e534e 100644 --- a/src/applications/ivc-champva/10-10D/tests/unit/config/form.unit.spec.jsx +++ b/src/applications/ivc-champva/10-10D/tests/unit/config/form.unit.spec.jsx @@ -34,7 +34,7 @@ testNumberOfWebComponentFields( formConfig, formConfig.chapters.certifierInformation.pages.page5.schema, formConfig.chapters.certifierInformation.pages.page5.uiSchema, - 7, + 6, 'Signer relationship', { certifierRelationship: { diff --git a/src/applications/ivc-champva/10-10D/tests/unit/config/submitTransformer.unit.spec.js b/src/applications/ivc-champva/10-10D/tests/unit/config/submitTransformer.unit.spec.js index fa9c59fa81b9..f728c04cb428 100644 --- a/src/applications/ivc-champva/10-10D/tests/unit/config/submitTransformer.unit.spec.js +++ b/src/applications/ivc-champva/10-10D/tests/unit/config/submitTransformer.unit.spec.js @@ -9,24 +9,45 @@ describe('transform for submit', () => { const transformed = JSON.parse( transformForSubmit(formConfig, { data: { - certifierRelationship: 'Spouse', + applicants: [{ applicantRelationshipToSponsor: 'Spouse' }], }, }), ); - expect(transformed.certification.relationship).to.equal('Spouse'); + expect(transformed.applicants[0].vetRelationship).to.equal('Spouse'); }); it('should flatten relationship details', () => { const transformed = JSON.parse( transformForSubmit(formConfig, { data: { + applicants: [ + { + applicantRelationshipToSponsor: { + relationshipToVeteran: 'other', + otherRelationshipToVeteran: 'Sibling', + }, + }, + ], + }, + }), + ); + expect(transformed.applicants[0].vetRelationship).to.equal('Sibling'); + }); + it('should produce a semicolon separated list of relationships for third party certifiers', () => { + const transformed = JSON.parse( + transformForSubmit(formConfig, { + data: { + certifierRole: 'other', certifierRelationship: { - relationshipToVeteran: 'other', - otherRelationshipToVeteran: 'Sibling', + relationshipToVeteran: { + spouse: true, + parent: true, + thirdParty: false, + }, }, }, }), ); - expect(transformed.certification.relationship).to.equal('Sibling'); + expect(transformed.certification.relationship).to.equal('spouse; parent'); }); it('should insert blank values as needed', () => { const transformed = JSON.parse( diff --git a/src/applications/ivc-champva/10-10D/tests/unit/helpers/helpers.unit.spec.js b/src/applications/ivc-champva/10-10D/tests/unit/helpers/helpers.unit.spec.js index 22a1e96b1e6a..7d61f0f7603f 100644 --- a/src/applications/ivc-champva/10-10D/tests/unit/helpers/helpers.unit.spec.js +++ b/src/applications/ivc-champva/10-10D/tests/unit/helpers/helpers.unit.spec.js @@ -103,7 +103,6 @@ describe('populateFirstApplicant', () => { const formData = { applicants: [{ applicantName: { first: 'Test' } }] }; const result = populateFirstApplicant( formData, - '', newAppInfo.name, newAppInfo.email, newAppInfo.phone, @@ -118,7 +117,6 @@ describe('populateFirstApplicant', () => { const formData = {}; const result = populateFirstApplicant( formData, - '', newAppInfo.name, newAppInfo.email, newAppInfo.phone, @@ -130,7 +128,7 @@ describe('populateFirstApplicant', () => { describe('page15a depends function', () => { const isApp = { - certifierRelationship: { relationshipToVeteran: { applicant: true } }, + certifierRole: 'applicant', certifierAddress: { street: '123' }, }; const notApp = { diff --git a/src/applications/ivc-champva/10-10D/tests/unit/helpers/validations.unit.spec.js b/src/applications/ivc-champva/10-10D/tests/unit/helpers/validations.unit.spec.js new file mode 100644 index 000000000000..7152dfa79124 --- /dev/null +++ b/src/applications/ivc-champva/10-10D/tests/unit/helpers/validations.unit.spec.js @@ -0,0 +1,66 @@ +import { expect } from 'chai'; +import { fieldsMustMatchValidation } from '../../../helpers/validations'; + +describe('fieldsMustMatchValidation helper', () => { + let errorMessage = []; + + const errors = { + addError: message => { + errorMessage.push(message || ''); + }, + }; + + beforeEach(() => { + errorMessage = []; + }); + + it('should add error message when certifierPhone does not match applicantPhone', () => { + expect(errorMessage[0]).to.be.undefined; + + const props = { + page: { certifierPhone: '' }, + formData: { + certifierRole: 'applicant', + applicants: [{ applicantPhone: '1231231234' }], + sponsorPhone: '', + }, + }; + + fieldsMustMatchValidation( + { + certifierPhone: errors, + }, + props.page, + props.formData, + 'certifierPhone', + 'applicantPhone', + 'sponsorPhone', + ); + expect(errorMessage.length > 0).to.be.true; + }); + + it('should add error message when certifierName does not match veteransFullName', () => { + expect(errorMessage[0]).to.be.undefined; + + const props = { + page: { certifierName: { first: '', last: '' } }, + formData: { + certifierRole: 'sponsor', + applicants: [{ applicantName: { first: '', last: '' } }], + veteransFullName: { first: 'x', last: 'y' }, + }, + }; + + fieldsMustMatchValidation( + { + certifierName: { first: errors, last: errors }, + }, + props.page, + props.formData, + 'certifierName', + 'applicantName', + 'veteransFullName', + ); + expect(errorMessage.length > 0).to.be.true; + }); +}); diff --git a/src/applications/ivc-champva/10-10D/tests/unit/pages/combinedPageTests.unit.spec.js b/src/applications/ivc-champva/10-10D/tests/unit/pages/combinedPageTests.unit.spec.js index af6f4ddcf2e5..1581cfe07c75 100644 --- a/src/applications/ivc-champva/10-10D/tests/unit/pages/combinedPageTests.unit.spec.js +++ b/src/applications/ivc-champva/10-10D/tests/unit/pages/combinedPageTests.unit.spec.js @@ -1,4 +1,5 @@ import React from 'react'; +import { expect } from 'chai'; import { testComponentRender } from '../../../../shared/tests/pages/pageTests.spec'; import { ApplicantDependentStatusPage, @@ -19,6 +20,10 @@ import { ApplicantRelOriginPage, ApplicantRelOriginReviewPage, } from '../../../pages/ApplicantRelOriginPage'; +import { + SignerContactInfoPage, + signerContactOnGoForward, +} from '../../../pages/SignerContactInfoPage'; import mockData from '../../e2e/fixtures/data/test-data.json'; // Basic render tests: @@ -76,3 +81,37 @@ testComponentRender( title={() => {}} />, ); +testComponentRender( + 'SignerContactInfoPage', +