diff --git a/frontend/tests/components/pages/FormStaffPage.cy.ts b/frontend/tests/components/pages/FormStaffPage.cy.ts
new file mode 100644
index 0000000000..87e380ad05
--- /dev/null
+++ b/frontend/tests/components/pages/FormStaffPage.cy.ts
@@ -0,0 +1,72 @@
+import FormStaffPage from "@/pages/FormStaffPage.vue";
+
+const individualBaseData = {
+ firstName: "John",
+ middleName: "Michael",
+ lastName: "Silver",
+ birthdateYear: "2001",
+ birthdateMonth: "05",
+ birthdateDay: "30",
+ identificationTypeCode: "PASS",
+ identificationTypeValue: "Canadian passport",
+ identificationProvinceValue: undefined,
+ clientIdentification: "AB345678",
+};
+
+const fillIndividual = (data = individualBaseData) => {
+ cy.fillFormEntry("#firstName",data.firstName);
+ cy.fillFormEntry("#middleName",data.middleName);
+ cy.fillFormEntry("#lastName",data.lastName);
+ cy.fillFormEntry("#birthdateYear",data.birthdateYear);
+ cy.fillFormEntry("#birthdateMonth",data.birthdateMonth);
+ cy.fillFormEntry("#birthdateDay",data.birthdateDay);
+ cy.selectFormEntry("#identificationType",data.identificationTypeValue,false);
+ cy.fillFormEntry("#clientIdentification",data.clientIdentification);
+};
+
+describe("Step 2 - Locations", () => {
+
+ beforeEach(() => {
+ cy.intercept("GET", "/api/codes/countries?page=0&size=250", {
+ fixture: "countries.json",
+ }).as("getCountries");
+
+ cy.intercept("GET", "/api/codes/countries/CA/provinces?page=0&size=250", {
+ fixture: "provinces.json",
+ }).as("getProvinces");
+
+ cy.intercept("GET", "/api/codes/countries/US/provinces?page=0&size=250", {
+ fixture: "states.json",
+ }).as("getStates");
+
+ cy.intercept("GET", "/api/codes/identification-types", {
+ fixture: "identificationTypes.json",
+ }).as("getIdentificationTypes");
+
+ cy.intercept("POST", "/api/clients/matches", {
+ statusCode: 204,
+ }).as("doMatches");
+
+ cy.viewport(1056, 800);
+ });
+
+ it("should render the LocationsWizardStep with maxLocations set to 25", () => {
+
+ cy.mount(FormStaffPage, {}).its("wrapper").as("wrapper");
+
+ cy.get("#clientType").find("[part='trigger-button']").click();
+
+ cy.get("#clientType").find('cds-combo-box-item[data-id="I"]').click();
+
+ fillIndividual();
+
+ cy.get("[data-test='wizard-next-button']").click();
+
+ cy.get("@wrapper")
+ .then((wrapper) => {
+ const locations = wrapper.findComponent({ name: "LocationsWizardStep" });
+ return locations.props("maxLocations");
+ })
+ .should("eq", 25);
+ });
+});
diff --git a/frontend/tests/components/pages/bceidform/AddressWizardStep.cy.ts b/frontend/tests/components/pages/bceidform/AddressWizardStep.cy.ts
new file mode 100644
index 0000000000..a471556dd4
--- /dev/null
+++ b/frontend/tests/components/pages/bceidform/AddressWizardStep.cy.ts
@@ -0,0 +1,269 @@
+import AddressWizardStep from "@/pages/bceidform/AddressWizardStep.vue";
+import { emptyAddress } from "@/dto/ApplyClientNumberDto";
+import type { Address, FormDataDto } from "@/dto/ApplyClientNumberDto";
+import type { ModalNotification } from "@/dto/CommonTypesDto";
+import { useEventBus } from "@vueuse/core";
+
+describe("", () => {
+
+ beforeEach(() => {
+ cy.intercept("GET", `/api/addresses?country=CA&maxSuggestions=10&searchTerm=*`, {
+ fixture: "addressSearch.json",
+ });
+ });
+
+ describe("when feature BCEID_MULTI_ADDRESS is enabled", () => {
+ const global = {
+ config: {
+ globalProperties: {
+ $features: {
+ BCEID_MULTI_ADDRESS: true,
+ },
+ },
+ },
+ };
+
+ it("renders the AddressWizardStep component", () => {
+ cy.mount(AddressWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "Mailing address",
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ global,
+ });
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ // Assert that the first field is displayed
+ cy.get("#addr_0").should("exist");
+ });
+
+ it("should display an error when two locations have the same address data", () => {
+ const address = {
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address;
+ cy.mount(AddressWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "My Office",
+ ...address,
+ } as Address,
+ {
+ locationName: "My Store",
+ ...address,
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ global,
+ });
+
+ cy.get("#addr_1").find("div").should("have.class", "cds--dropdown--invalid");
+ cy.get("#city_1").find("input").should("have.class", "cds--text-input--invalid");
+ });
+
+ describe("when an address which is not the last one gets deleted", () => {
+ const otherAddressNames = ["Sales Office", "Beach Office"];
+ const addAddress = (addressId: number, name: string) => {
+ cy.contains("Add another address").should("be.visible").click();
+
+ cy.focused().should("contain.text", "Additional address");
+
+ cy.get(`#name_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(name);
+ };
+ const fillAddress = (
+ addressId: number,
+ { streetAddress, postalCode }: { streetAddress: string; postalCode: string },
+ ) => {
+ cy.get(`#addr_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(streetAddress);
+
+ cy.get(`#city_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type("Victoria");
+
+ cy.get(`#postalCode_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(postalCode);
+ };
+
+ let bus: ReturnType>;
+
+ const mountTest = (includeOtherAddressesInProps: boolean) => {
+ cy.mount(AddressWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "Mailing address",
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ...(includeOtherAddressesInProps ? otherAddressNames : []).map(
+ (locationName) => ({
+ ...emptyAddress(),
+ locationName,
+ }),
+ ),
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ global,
+ })
+ .its("wrapper")
+ .as("vueWrapper");
+ };
+
+ // Multi-scenario test
+ [
+ { includeOtherAddressesInProps: true, predicate: "are provided in the props" },
+ { includeOtherAddressesInProps: false, predicate: "are added manually" },
+ ].forEach(({ includeOtherAddressesInProps, predicate }) =>
+ describe(`when other addresses ${predicate}`, () => {
+ beforeEach(() => {
+ bus = useEventBus("modal-notification");
+ bus.on((payload) => {
+ payload.handler(); // automatically proceed with the deletion
+ });
+
+ mountTest(includeOtherAddressesInProps);
+
+ if (!includeOtherAddressesInProps) {
+ otherAddressNames.forEach((name, index) => {
+ addAddress(index + 1, name);
+ });
+ }
+ });
+
+ afterEach(() => {
+ bus.reset();
+ });
+
+ it("removes the intended address from the DOM", () => {
+ cy.get("#deleteAddress_1").click();
+ cy.wait(150);
+ cy.get("#name_1").should("not.exist");
+ cy.get("#name_2").should("exist");
+ });
+
+ it("can submit the form (regardless of the deleted address being invalid)", () => {
+ cy.get("#deleteAddress_1").click();
+ cy.wait(150);
+
+ fillAddress(2, {
+ streetAddress: "456 Lumber Street",
+ postalCode: "B0B0B0",
+ });
+
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // The last valid event was emitted with true.
+ expect(lastValid[0]).to.equal(true);
+ });
+ });
+ }),
+ );
+ });
+
+ });
+
+ describe("when feature BCEID_MULTI_ADDRESS is disabled", () => {
+ const global = {
+ config: {
+ globalProperties: {
+ $features: {
+ BCEID_MULTI_ADDRESS: false,
+ },
+ },
+ },
+ };
+ const mountTest = () => {
+ cy.mount(AddressWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "Mailing address",
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ global,
+ });
+ };
+
+ it("renders the AddressWizardStep component", () => {
+ mountTest();
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ // Assert that the first field is displayed
+ cy.get("#addr_0").should("exist");
+ });
+
+ it("should not render the button 'Add another address'", () => {
+ mountTest();
+ cy.contains("Add another address").should("not.exist");
+ });
+
+ });
+
+});
diff --git a/frontend/tests/components/pages/bceidform/BusinessInformationWizardStep.cy.ts b/frontend/tests/components/pages/bceidform/BusinessInformationWizardStep.cy.ts
new file mode 100644
index 0000000000..52b77107f9
--- /dev/null
+++ b/frontend/tests/components/pages/bceidform/BusinessInformationWizardStep.cy.ts
@@ -0,0 +1,523 @@
+import BusinessInformationWizardStep from "@/pages/bceidform/BusinessInformationWizardStep.vue";
+import type { FormDataDto } from "@/dto/ApplyClientNumberDto";
+
+const user = {
+ userId: "bceid\\mockUserId",
+ firstName: "John",
+ lastName: "Doe",
+};
+
+const global = {
+ config: {
+ globalProperties: {
+ $session: {
+ user,
+ },
+ $features: {
+ BCEID_MULTI_ADDRESS: false,
+ },
+ },
+ },
+};
+
+let individualStatusCode: number;
+
+describe('', () => {
+
+ beforeEach(() => {
+ individualStatusCode = 200;
+
+ cy.intercept("/api/clients/name/*", {
+ fixture: "business.json",
+ }).as("searchCompany");
+
+ cy.intercept("GET", "/api/clients/BC1234567", {
+ statusCode: 406,
+ body: "Client type BC is not supported at the moment",
+ });
+
+ cy.intercept("GET", "/api/clients/SP1234567", {
+ statusCode: 422,
+ body: "Unable to process request. This sole proprietor is not owner by a person",
+ });
+
+ cy.intercept("GET", "/api/clients/SP2", {
+ statusCode: 200,
+ body: "Unable to process request. This sole proprietor is not owner by a person",
+ });
+
+ cy.intercept("GET", "/api/clients/XX9016140", {
+ statusCode: 200,
+ body: {
+ name: "Anyone",
+ id: "XX9016140",
+ goodStanding: true,
+ addresses: [{}],
+ contacts: [
+ {
+ lastName: "Else",
+ },
+ ],
+ },
+ delay: 10,
+ });
+
+ cy.intercept("GET", "/api/codes/client-types/C", {
+ statusCode: 200,
+ body: {
+ code: "C",
+ name: "Corporation",
+ },
+ }).as("getClientType");
+
+ cy.intercept("GET", "/api/clients/individual/mockUserId?lastName=Doe", (req) => {
+ req.reply({
+ statusCode: individualStatusCode,
+ delay: 10,
+ });
+ }).as("checkIndividualUser");
+
+ cy.intercept("GET", "/api/clients/individual/mockUserId?lastName=Else", (req) => {
+ req.reply({
+ statusCode: individualStatusCode,
+ delay: 10,
+ });
+ }).as("checkIndividualElse");
+ });
+
+ it('renders the BusinessInformationWizardStep component and interacts with elements', () => {
+
+ cy.fixture('districts.json').then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "",
+ legalType: "",
+ clientType: "",
+ registrationNumber: "",
+ businessName: "",
+ goodStandingInd: "",
+ birthdate: "",
+ address: ""
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ },
+ global,
+ });
+ });
+
+ cy.get('#businessTyperbR').click();
+
+ cy.get('#bcRegistryEmailId').should('exist');
+
+ });
+
+ it('shows "Client type not supported"', () => {
+ cy.fixture('districts.json').then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "",
+ legalType: "",
+ clientType: "",
+ registrationNumber: "",
+ businessName: "",
+ goodStandingInd: "",
+ birthdate: "",
+ address: "",
+ },
+ location: {
+ contacts: [
+ {
+ email: "john@doe.com",
+ firstName: "John",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ },
+ global,
+ });
+ });
+
+ cy.get("#businessTyperbR").click();
+
+ cy.get("#business")
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type("Unsupported");
+ cy.wait("@searchCompany");
+
+ cy.get('cds-combo-box-item[data-id="BC1234567"]').click();
+
+ cy.get("cds-inline-notification")
+ .shadow()
+ .contains("Client type not supported")
+ .should("be.visible");
+
+ // The name of the client type
+ cy.contains("cds-inline-notification", "Corporation").should("be.visible");
+ });
+
+ const showsUnknownSoleProprietor = () => {
+ cy.fixture('districts').then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "",
+ legalType: "",
+ clientType: "",
+ registrationNumber: "",
+ businessName: "",
+ goodStandingInd: "",
+ birthdate: "",
+ address: ""
+ },
+ location: {
+ contacts: [
+ {
+ email: "john@doe.com",
+ firstName: "John",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ },
+ global,
+ });
+ });
+
+ cy.get("#businessTyperbR").click();
+
+ cy.get("#business")
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type("Unknown");
+ cy.wait("@searchCompany");
+
+ cy.get('cds-combo-box-item[data-id="SP1234567"]').click();
+
+ cy.get("cds-inline-notification")
+ .shadow()
+ .contains("Unknown sole proprietor")
+ .should("be.visible");
+ };
+
+ it('shows "Unknown sole proprietor"', () => {
+ showsUnknownSoleProprietor();
+ });
+
+ it('clears the error when Type of business changes', () => {
+ showsUnknownSoleProprietor();
+
+ cy.get("#businessTyperbU").click();
+
+ cy.get("cds-inline-notification").should("not.exist");
+ });
+
+ it('clears the error when the business name gets cleared', () => {
+ showsUnknownSoleProprietor();
+
+ cy.get("#business")
+ .should("be.visible")
+ .shadow()
+ .find("#selection-button") // The X clear button
+ .click();
+
+ cy.get("cds-inline-notification").should("not.exist");
+ });
+
+ describe("individual validation", () => {
+ let callsSetIndividualValidInd = [];
+ const individualValidWrapper = {
+ individualValidInd: false,
+ };
+ const functionWrapper = {
+ setIndividualValidInd: (value: boolean) => {
+ individualValidWrapper.individualValidInd = value;
+ callsSetIndividualValidInd.push(value);
+ },
+ };
+ const { setIndividualValidInd } = functionWrapper;
+ beforeEach(() => {
+ individualValidWrapper.individualValidInd = false;
+ callsSetIndividualValidInd = [];
+
+ cy.fixture("districts").then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "",
+ legalType: "",
+ clientType: "",
+ registrationNumber: "",
+ businessName: "",
+ goodStandingInd: "",
+ birthdate: "",
+ address: "",
+ },
+ location: {
+ contacts: [
+ {
+ email: "john@doe.com",
+ firstName: "John",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ individualValidInd: individualValidWrapper.individualValidInd,
+ setIndividualValidInd,
+ },
+ global,
+ });
+ });
+ });
+
+ interface Scenario {
+ statusCode: number;
+ valid: boolean;
+ };
+ const scenarios: Scenario[] = [
+ { statusCode: 200, valid: true },
+ { statusCode: 404, valid: true },
+ { statusCode: 409, valid: false },
+ { statusCode: 400, valid: false },
+ { statusCode: 403, valid: false },
+ { statusCode: 500, valid: false },
+ { statusCode: 503, valid: false },
+ ];
+ scenarios.forEach((scenario) => {
+ describe(`when response is ${scenario.statusCode}`, () => {
+ beforeEach(() => {
+ individualStatusCode = scenario.statusCode;
+ });
+ it(`should set valid to: ${scenario.valid}`, () => {
+ cy.get("#businessTyperbU").click();
+ cy.wait("@checkIndividualUser");
+ cy.wrap(individualValidWrapper).should(({ individualValidInd }) => {
+ expect(individualValidInd).to.equal(scenario.valid);
+ });
+ })
+ });
+ });
+ });
+
+ describe("when a Registered individual business gets selected", () => {
+ let callsSetIndividualValidInd = [];
+ const functionWrapper = {
+ setIndividualValidInd: (value: boolean) => {
+ callsSetIndividualValidInd.push(value);
+ },
+ };
+ const { setIndividualValidInd } = functionWrapper;
+ beforeEach(() => {
+ callsSetIndividualValidInd = [];
+ cy.fixture('districts').then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "",
+ legalType: "",
+ clientType: "",
+ registrationNumber: "",
+ businessName: "",
+ goodStandingInd: "",
+ birthdate: "",
+ address: "",
+ },
+ location: {
+ contacts: [
+ {
+ email: "john@doe.com",
+ firstName: "John",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ individualValidInd: false,
+ setIndividualValidInd,
+ },
+ global,
+ });
+ });
+
+ cy.get("#businessTyperbR").click();
+
+ cy.get("#business").should("be.visible").shadow().find("input").type("Valid");
+ cy.wait("@searchCompany");
+
+ cy.get("cds-combo-box-item[data-id='XX9016140']").click();
+ cy.wrap(callsSetIndividualValidInd).should((value) => {
+ const lastCall = value.slice(-1)[0];
+ expect(lastCall).to.equal(true);
+ });
+ });
+
+ describe("and type of business is changed to Unregistered", () => {
+ beforeEach(() => {
+ callsSetIndividualValidInd = [];
+ cy.get("#businessTyperbU").click();
+ })
+ it("should re-check with user's last name", () => {
+ cy.wait("@checkIndividualUser");
+ cy.wrap(callsSetIndividualValidInd).should((value) => {
+ const lastCall = value.slice(-1)[0];
+ expect(lastCall).to.equal(true);
+ });
+ });
+ });
+ });
+
+ describe("when props.individualValue is true", () => {
+ const individualValidInd = true;
+ let callsSetIndividualValidInd = [];
+ const functionWrapper = {
+ setIndividualValidInd: (value: boolean) => {
+ callsSetIndividualValidInd.push(value);
+ },
+ };
+ const { setIndividualValidInd } = functionWrapper;
+ describe("and type of business is Registered", () => {
+ beforeEach(() => {
+ callsSetIndividualValidInd = [];
+ cy.fixture('districts').then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "R",
+ legalType: "",
+ clientType: "RSP",
+ registrationNumber: "",
+ businessName: "abc",
+ goodStandingInd: "",
+ birthdate: "2000-01-01",
+ address: "",
+ },
+ location: {
+ contacts: [
+ {
+ email: "john@doe.com",
+ firstName: "John",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ individualValidInd,
+ setIndividualValidInd,
+ },
+ global,
+ });
+ });
+ });
+
+ describe("and type of business is changed to Unregistered", () => {
+ beforeEach(() => {
+ cy.get("#businessTyperbU").click();
+ })
+ it("should re-check individual validation", () => {
+ cy.wait("@checkIndividualUser");
+ cy.wrap(callsSetIndividualValidInd).should((value) => {
+ const lastCall = value.slice(-1)[0];
+ expect(lastCall).to.equal(true);
+ });
+ });
+ });
+ describe("and a different individual business gets selected", () => {
+ beforeEach(() => {
+ cy.get("#business").should("be.visible").shadow().find("input").type("Valid");
+ cy.wait("@searchCompany");
+
+ cy.get("cds-combo-box-item[data-id='XX9016140']").click();
+ });
+ it("should re-check individual validation", () => {
+ cy.wait("@checkIndividualElse");
+ cy.wrap(callsSetIndividualValidInd).should((value) => {
+ const lastCall = value.slice(-1)[0];
+ expect(lastCall).to.equal(true);
+ });
+ });
+ });
+ });
+
+ describe("and type of business is Unregistered", () => {
+ beforeEach(() => {
+ callsSetIndividualValidInd = [];
+ cy.fixture('districts').then((districts) => {
+ cy.mount(BusinessInformationWizardStep, {
+ props: {
+ data: {
+ businessInformation: {
+ businessType: "U",
+ legalType: "",
+ clientType: "USP",
+ registrationNumber: "",
+ businessName: "abc",
+ goodStandingInd: "",
+ birthdate: "2000-01-01",
+ address: "",
+ },
+ location: {
+ contacts: [
+ {
+ email: "john@doe.com",
+ firstName: "John",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ districtsList: districts,
+ active: false,
+ individualValidInd,
+ setIndividualValidInd,
+ },
+ global,
+ });
+ });
+ });
+
+ describe("and type of business is changed to Registered", () => {
+ beforeEach(() => {
+ cy.get("#businessTyperbR").click();
+ });
+ describe("and an indivual business gets selected", () => {
+ beforeEach(() => {
+ cy.get("#business").should("be.visible").shadow().find("input").type("Valid");
+ cy.wait("@searchCompany");
+
+ cy.get("cds-combo-box-item[data-id='XX9016140']").click();
+ });
+ it("should re-check individual validation", () => {
+ cy.wait("@checkIndividualElse");
+ cy.wrap(callsSetIndividualValidInd).should((value) => {
+ const lastCall = value.slice(-1)[0];
+ expect(lastCall).to.equal(true);
+ });
+ });
+ });
+ });
+ });
+ });
+
+});
\ No newline at end of file
diff --git a/frontend/tests/components/pages/bceidform/ContactWizardStep.cy.ts b/frontend/tests/components/pages/bceidform/ContactWizardStep.cy.ts
new file mode 100644
index 0000000000..856f4960f8
--- /dev/null
+++ b/frontend/tests/components/pages/bceidform/ContactWizardStep.cy.ts
@@ -0,0 +1,75 @@
+import ContactWizardStep from "@/pages/bceidform/ContactWizardStep.vue";
+import type { Contact, FormDataDto } from "@/dto/ApplyClientNumberDto";
+import { emptyContact } from "@/dto/ApplyClientNumberDto";
+
+const globalDefault = {
+ config: {
+ globalProperties: {
+ $features: {
+ BCEID_MULTI_ADDRESS: false,
+ },
+ },
+ },
+};
+
+describe('', () => {
+
+ beforeEach(() => {
+ cy.fixture("contact.json").as("contactFixture");
+ cy.fixture("roles.json").as("rolesFixture");
+ cy.fixture("addresses.json").as("addressesFixture");
+ });
+
+ it('renders the ContactWizardStep component', () => {
+ cy.mount(ContactWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [],
+ contacts: [
+ {
+ ...emptyContact,
+ firstName: "John",
+ lastName: "Doe",
+ } as Contact,
+ {
+ ...emptyContact,
+ firstName: null,
+ lastName: null,
+ } as unknown as Contact,
+ ],
+ },
+ } as unknown as FormDataDto,
+ active: false,
+ },
+ global: globalDefault,
+ });
+
+ // Assert that the main component is rendered
+ cy.get('.frame-01').should('exist');
+
+ // Assert that the element with v-if condition is displayed when the condition is true
+ cy.get('.body-compact-01').should('exist');
+
+ // Check when 5 contacts are reached
+ cy.get('@contactFixture').then((contact: Contact) => {
+ const contactsArray = Array.from({ length: 5 }, (_, index) => ({ ...contact, firstName: `Contact${index + 1}` }));
+ cy.mount(ContactWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [],
+ contacts: contactsArray,
+ },
+ } as unknown as FormDataDto,
+ active: false,
+ },
+ global: globalDefault,
+ });
+
+ // Assert that the element with v-if condition is displayed when the condition is met
+ cy.get('#maxAdditionalContsReachedLblId').should('exist');
+ });
+ });
+
+});
\ No newline at end of file
diff --git a/frontend/tests/components/pages/staffform/ContactsWizardStep.cy.ts b/frontend/tests/components/pages/staffform/ContactsWizardStep.cy.ts
new file mode 100644
index 0000000000..f4e39000da
--- /dev/null
+++ b/frontend/tests/components/pages/staffform/ContactsWizardStep.cy.ts
@@ -0,0 +1,242 @@
+import ContactsWizardStep from "@/pages/staffform/ContactsWizardStep.vue";
+import type { Contact, Address, FormDataDto } from "@/dto/ApplyClientNumberDto";
+import type { ModalNotification } from "@/dto/CommonTypesDto";
+import { useEventBus } from "@vueuse/core";
+
+describe("", () => {
+ let bus: ReturnType> =
+ useEventBus("modal-notification");
+
+ const individualFormData: FormDataDto = {
+ businessInformation: {
+ district: "",
+ businessType: "U",
+ legalType: "SP",
+ clientType: "I",
+ registrationNumber: "",
+ businessName: "Jhonathan James Wick",
+ goodStandingInd: "Y",
+ birthdate: "1985-07-17",
+ firstName: "Jhonathan",
+ middleName: "James",
+ lastName: "Wick",
+ identificationType: {
+ value: "CDDL",
+ text: "Canadian driver's licence",
+ countryCode: "CA"
+ },
+ identificationProvince: "NB",
+ identificationCountry: "CA",
+ clientIdentification: "99999999",
+ },
+ location: {
+ addresses: [
+ {
+ locationName: "Main Address",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ streetAddress: "3925 Dieppe Ave",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "NS", text: "Nova Scotia" },
+ city: "Lumsden",
+ postalCode: "M2W5E5",
+ businessPhoneNumber: "",
+ secondaryPhoneNumber: "",
+ faxNumber: "",
+ emailAddress: "",
+ notes: "",
+ index: 0,
+ } as Address,
+ ],
+ contacts: [
+ {
+ locationNames: [{ value: "0", text: "Mailing address" }],
+ contactType: { value: "", text: "" },
+ firstName: "Jhonathan",
+ lastName: "James Wick",
+ phoneNumber: "",
+ email: "",
+ index: 0,
+ } as Contact,
+ ],
+ },
+ };
+
+ const baseData = [
+ {
+ mail: "contact1@mail.ca",
+ phone1: "1234567890",
+ phone2: "1234567890",
+ fax: "1234567890",
+ role: "Person",
+ address: individualFormData.location.addresses[0].locationName,
+ },
+ ];
+
+ const fillFormEntry = (field: string, value: string) => {
+ cy.get(field)
+ .should("exist")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(value);
+
+ cy.get(field).shadow().find("input").blur();
+ };
+
+ const selectFormEntry = (field: string, value: string, box: boolean) => {
+ cy.get(field).find("[part='trigger-button']").click();
+
+ if (!box) {
+ cy.get(field).find(`cds-combo-box-item[data-value="${value}"]`).click();
+ } else {
+ cy.get(field)
+ .find(`cds-multi-select-item[data-value="${value}"]`)
+ .click();
+ cy.get(field).click();
+ }
+ };
+
+ const addContact = (addressId: number, name: string) => {
+ cy.get(".body-02").should(
+ "have.text",
+ "Contacts can be added to the applicant's account"
+ );
+ cy.contains("Add another contact").should("be.visible").click();
+
+ // Focus accordion title
+ // TODO: uncomment next line when the following issue is fixed: https://github.com/cypress-io/cypress/issues/26383
+ // cy.focused().should("contain.text", "Additional contact");
+
+ cy.get(`#firstName_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(name);
+ };
+
+ beforeEach(() => {
+ cy.viewport(1056, 768);
+
+ cy.intercept("GET", "/api/codes/contact-types?page=0&size=250", {
+ fixture: "roles.json",
+ }).as("getContactTypes");
+
+ bus.on((payload) => payload.handler());
+ });
+
+ afterEach(() => bus.reset());
+
+ it("renders the ContactsWizardStep component for individual", () => {
+ // render the component
+ cy.mount(ContactsWizardStep, {
+ props: {
+ data: individualFormData,
+ active: true,
+ },
+ });
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ cy.wait("@getContactTypes");
+
+ // Assert that the first field is displayed
+ cy.get(".text-fullName_0")
+ .should("exist")
+ .should("have.text", "Jhonathan James Wick");
+ });
+
+ it("fill the first contact information for individual", () => {
+ // render the component
+ cy.mount(ContactsWizardStep, {
+ props: {
+ data: individualFormData,
+ active: true,
+ },
+ });
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ cy.wait("@getContactTypes");
+
+ // Fill the first contact information
+ fillFormEntry("#emailAddress_0", baseData[0].mail);
+ fillFormEntry("#businessPhoneNumber_0", baseData[0].phone1);
+ fillFormEntry("#secondaryPhoneNumber_0", baseData[0].phone2);
+ fillFormEntry("#faxNumber_0", baseData[0].fax);
+
+ selectFormEntry("#role_0", baseData[0].role, false);
+ selectFormEntry("#addressname_0", baseData[0].address, true);
+ });
+
+ it("add extra contacts until max", () => {
+ // Set the maximum number of contacts
+ const maxContacts = 5;
+
+ // render the component
+ cy.mount(ContactsWizardStep, {
+ props: {
+ data: individualFormData,
+ active: true,
+ maxContacts,
+ },
+ });
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ // Wait for the contact types to be loaded
+ cy.wait("@getContactTypes");
+
+ // The add contact button should be visible
+ cy.contains("Add another contact").should("be.visible");
+
+ // Add contacts until the maximum is reached
+ for (let index = 1; index < maxContacts; index++) {
+ addContact(index, `Contact${index}`);
+ }
+
+ // The add contact button should be hidden
+ cy.contains("Add another contact").should("not.exist");
+ // The message should be displayed
+ cy.get(".body-02").should(
+ "have.text",
+ `You can only add a maximum of ${maxContacts} contacts.`
+ );
+ });
+
+ it("remove contacts", () => {
+ //Set a maximum of 5 contacts
+ const maxContacts = 5;
+
+ // render the component
+ cy.mount(ContactsWizardStep, {
+ props: {
+ data: individualFormData,
+ active: true,
+ maxContacts,
+ },
+ });
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ // Wait for the contact types to be loaded
+ cy.wait("@getContactTypes");
+
+ // The delete button group should be visible
+ cy.get(".grouping-06").should("be.visible");
+
+ // Remove each contact and check to see if it was removed
+ for (let index = 1; index < maxContacts; index++) {
+ cy.get(".grouping-06")
+ .find(`cds-button#deleteContact_${index}`)
+ .should("be.visible")
+ .click();
+ cy.get(`#firstName_${index}`).should("not.exist");
+ }
+ });
+});
diff --git a/frontend/tests/components/pages/staffform/IndividualClientInformationWizardStep.cy.ts b/frontend/tests/components/pages/staffform/IndividualClientInformationWizardStep.cy.ts
new file mode 100644
index 0000000000..d29911b357
--- /dev/null
+++ b/frontend/tests/components/pages/staffform/IndividualClientInformationWizardStep.cy.ts
@@ -0,0 +1,473 @@
+import IndividualClientInformationWizardStep from "@/pages/staffform/IndividualClientInformationWizardStep.vue";
+import type { FormDataDto } from "@/dto/ApplyClientNumberDto";
+
+describe("", () => {
+ beforeEach(() => {
+ cy.intercept("GET", "/api/codes/countries/CA/provinces?page=0&size=250", {
+ fixture: "provinces.json",
+ }).as("getProvinces");
+
+ cy.intercept("GET", "/api/codes/countries/US/provinces?page=0&size=250", {
+ fixture: "states.json",
+ }).as("getStates");
+
+ cy.intercept("GET", "/api/codes/identification-types", {
+ fixture: "identificationTypes.json",
+ }).as("getIdentificationTypes");
+ });
+
+ const getDefaultProps = () => ({
+ data: {
+ businessInformation: {
+ businessType: "",
+ legalType: "",
+ clientType: "",
+ registrationNumber: "",
+ businessName: "",
+ goodStandingInd: "",
+ birthdate: "",
+ address: "",
+ },
+ location: {
+ contacts: [
+ {
+ firstName: "",
+ lastName: "",
+ },
+ ],
+ },
+ } as unknown as FormDataDto,
+ });
+
+ let currentProps = null;
+ const mount = (props = getDefaultProps()) => {
+ currentProps = props;
+ return cy
+ .mount(IndividualClientInformationWizardStep, {
+ props,
+ })
+ .its("wrapper")
+ .as("vueWrapper");
+ };
+
+ it("renders the IndividualClientInformationWizardStep component", () => {
+ mount();
+
+ cy.get("#firstName").should("be.visible");
+ cy.get("#middleName").should("be.visible");
+ cy.get("#lastName").should("be.visible");
+ cy.get("#birthdate").should("be.visible");
+ cy.get("#identificationType").should("be.visible");
+ cy.get("#clientIdentification").should("be.visible");
+ });
+
+ describe('when ID type is "Canadian driver\'s licence"', () => {
+ beforeEach(() => {
+ mount();
+
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "")
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="CDDL"]')
+ .should("be.visible")
+ .click();
+ });
+ it("displays the Issuing province field with label 'Issuing province'", () => {
+ cy.get("#identificationProvince").contains("Issuing province");
+ });
+ it("displays the Issuing province field with option 'British Columbia' selected by default", () => {
+ cy.get("#identificationProvince").should("be.visible").and("have.value", "British Columbia");
+ });
+
+ describe('and ID type is changed to "US driver\'s licence"', () => {
+ beforeEach(() => {
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "Canadian driver's licence") // initial value
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="USDL"]')
+ .should("be.visible")
+ .and("have.value", "US driver's licence") // new value
+ .click();
+ });
+ it("should clear the value on identificationProvince", () => {
+ cy.get("#identificationProvince").should("be.visible").and("have.value", "");
+ });
+ });
+ });
+
+ describe('when ID type is "US driver\'s licence"', () => {
+ beforeEach(() => {
+ mount();
+
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "")
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="USDL"]')
+ .should("be.visible")
+ .click();
+ });
+
+ it("displays the Issuing province field with label 'Issuing state'", () => {
+ cy.get("#identificationProvince").contains("Issuing state");
+ });
+ it("displays the Issuing province field with option 'British Columbia' selected by default", () => {
+ cy.get("#identificationProvince").should("be.visible").and("have.value", "");
+ });
+ });
+
+ describe("validation", () => {
+ describe("ID number according to the current ID type (and identificationProvince)", () => {
+ beforeEach(() => {
+ mount();
+ });
+ const valueNumeric13 = "1234567890123";
+ const valueAlphanumeric13 = "1234567890ABC";
+ const valueNumeric8 = "12345678";
+ const valueAlphanumeric8 = "12345ABC";
+
+ const isValid = () => {
+ cy.get("#clientIdentification").shadow().find("[name='invalid-text']").should("not.exist");
+ };
+
+ const isInvalid = () => {
+ cy.get("#clientIdentification")
+ .shadow()
+ .find("[name='invalid-text']")
+ .invoke("text")
+ .should("not.be.empty");
+ };
+
+ describe("When ID type is 'BRTH'", () => {
+ beforeEach(() => {
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "")
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="BRTH"]')
+ .should("be.visible")
+ .click();
+ });
+ it("allows up to 13 digits", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueNumeric13);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isValid();
+ });
+ it("displays error message if the value contains letters", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueAlphanumeric13);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isInvalid();
+ });
+ });
+ describe("when ID type is 'PASS'", () => {
+ beforeEach(() => {
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "")
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="PASS"]')
+ .should("be.visible")
+ .click();
+ });
+ it("displays error message if the value has more than 8 digits", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueNumeric13);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isInvalid();
+ });
+ it("allows numbers and letters", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueAlphanumeric8);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isValid();
+ });
+ });
+ describe("when ID type is 'CDDL'", () => {
+ beforeEach(() => {
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "")
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="CDDL"]')
+ .should("be.visible")
+ .click();
+ });
+ describe("and issuing province is 'BC' (default value)", () => {
+ it("displays error message if the value has more than 8 digits", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueNumeric13);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isInvalid();
+ });
+ it("displays error message if the value contains letters", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueAlphanumeric8);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isInvalid();
+ });
+ it("allows 8-digit numeric value", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueNumeric8);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isValid();
+ });
+ });
+ describe("and issuing province is something other than 'BC' (for example, 'AB')", () => {
+ beforeEach(() => {
+ cy.get("#identificationProvince")
+ .should("be.visible")
+ .and("have.value", "British Columbia")
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationProvince")
+ .find('cds-combo-box-item[data-id="AB"]')
+ .should("be.visible")
+ .click();
+ });
+ it("allows up to 20 digits", () => {
+ cy.get("#clientIdentification").shadow().find("input").type("12345678901234567890");
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isValid();
+ });
+ it("allows numbers and letters", () => {
+ cy.get("#clientIdentification").shadow().find("input").type(valueAlphanumeric8);
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isValid();
+ });
+ it("displays error message if the value has more than 20 digits", () => {
+ cy.get("#clientIdentification").shadow().find("input").type("123456789012345678901");
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+
+ isInvalid();
+ });
+ });
+ });
+ });
+ });
+
+ describe("businessInformation.businessName", () => {
+ beforeEach(() => {
+ mount();
+
+ cy.get("#firstName").shadow().find("input").type("John");
+ cy.get("#lastName").shadow().find("input").type("Silver");
+ });
+ describe("when middleName is not provided", () => {
+ it("sets the businessName in the businessInformation to ' '", () => {
+ cy.wrap(currentProps.data.businessInformation)
+ .its("businessName")
+ .should("equal", "John Silver");
+ });
+ });
+ describe("when middleName is provided", () => {
+ beforeEach(() => {
+ cy.get("#middleName").shadow().find("input").type("Michael");
+ });
+ it("sets the businessName in the businessInformation to ' '", () => {
+ cy.wrap(currentProps.data.businessInformation)
+ .its("businessName")
+ .should("equal", "John Michael Silver");
+ });
+ });
+ });
+
+ describe("when all required fields are properly filled in", () => {
+ beforeEach(() => {
+ mount();
+
+ cy.get("#firstName").shadow().find("input").type("John");
+
+ cy.get("#lastName").shadow().find("input").type("Silver");
+
+ cy.get("#birthdateYear").shadow().find("input").type("2001");
+ cy.get("#birthdateMonth").shadow().find("input").type("05");
+ cy.get("#birthdateDay").shadow().find("input").type("30");
+
+ cy.get("#identificationType").find("[part='trigger-button']").click();
+
+ cy.get("#identificationType").find('cds-combo-box-item[data-id="BRTH"]').click();
+
+ cy.get("#clientIdentification").shadow().find("input").type("1234567890123");
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+ });
+ it("emits valid true", () => {
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(true);
+ });
+ });
+ describe("when the middle name is also filled in", () => {
+ beforeEach(() => {
+ cy.get("#middleName").shadow().find("input").type("Michael");
+
+ cy.get("#middleName").shadow().find("input").blur();
+ cy.wait(1);
+ });
+ it("should not emit valid false even if the middle name gets cleared", () => {
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(true);
+ });
+
+ cy.get("#middleName").shadow().find("input").clear();
+
+ cy.get("#middleName").shadow().find("input").blur();
+ cy.wait(1);
+
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(true);
+ });
+ });
+ });
+ describe("when the step is invalid due to an invalid middle name", () => {
+ beforeEach(() => {
+ cy.get("#middleName").shadow().find("input").type("é");
+
+ cy.get("#middleName").shadow().find("input").blur();
+ cy.wait(1);
+
+ // Asserting the step is currently invalid
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(false);
+ });
+ });
+ describe("and the middle name gets cleared", () => {
+ beforeEach(() => {
+ cy.get("#middleName").shadow().find("input").clear();
+ });
+ it("should emit valid true even without blurring the input", () => {
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(true);
+ });
+ });
+ });
+ });
+
+ describe('when ID type is "Canadian driver\'s licence"', () => {
+ beforeEach(() => {
+ cy.get("#identificationType").should("be.visible").find("[part='trigger-button']").click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="CDDL"]')
+ .should("be.visible")
+ .click();
+ });
+
+ describe("and the Issuing province gets cleared", () => {
+ beforeEach(() => {
+ cy.get("#identificationProvince")
+ .should("be.visible")
+ .and("have.value", "British Columbia")
+ .find("#selection-button") // The X clear button
+ .click();
+ });
+
+ it("should emit valid false", () => {
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(false);
+ });
+ });
+
+ describe("and the ID type gets changed to one that does not display the Issuing province/state", () => {
+ beforeEach(() => {
+ cy.get("#identificationType")
+ .should("be.visible")
+ .and("have.value", "Canadian driver's licence") // initial value
+ .find("[part='trigger-button']")
+ .click();
+
+ cy.get("#identificationType")
+ .find('cds-combo-box-item[data-id="PASS"]')
+ .and("have.value", "Canadian passport") // new value
+ .should("be.visible")
+ .click();
+ });
+ describe("and the ID number is properly filled in", () => {
+ beforeEach(() => {
+ cy.get("#clientIdentification").shadow().find("input").type("12345678");
+
+ cy.get("#clientIdentification").shadow().find("input").blur();
+ cy.wait(1);
+ });
+ it("should emit valid true", () => {
+ /*
+ This test makes sure the impact of clearing the province (and thus making the
+ province field invalid) does not matter anymore after we get to a situation where the
+ province field is not used.
+ */
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // Last event (in)"valid" emitted
+ expect(lastValid[0]).to.equal(true);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/frontend/tests/components/pages/staffform/LocationsWizardStep.cy.ts b/frontend/tests/components/pages/staffform/LocationsWizardStep.cy.ts
new file mode 100644
index 0000000000..715c856e34
--- /dev/null
+++ b/frontend/tests/components/pages/staffform/LocationsWizardStep.cy.ts
@@ -0,0 +1,383 @@
+import LocationsWizardStep from "@/pages/staffform/LocationsWizardStep.vue";
+import { emptyAddress } from "@/dto/ApplyClientNumberDto";
+import type { Address, FormDataDto } from "@/dto/ApplyClientNumberDto";
+import type { ModalNotification } from "@/dto/CommonTypesDto";
+import { useEventBus } from "@vueuse/core";
+
+describe("", () => {
+ beforeEach(() => {
+ cy.intercept("GET", `/api/addresses?country=CA&maxSuggestions=10&searchTerm=*`, {
+ fixture: "addressSearch.json",
+ });
+
+ cy.intercept("GET", "/api/codes/countries/CA/provinces?page=0&size=250", {
+ fixture: "provinces.json",
+ });
+
+ });
+
+ it("renders the LocationsWizardStep component", () => {
+ cy.mount(LocationsWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "Mailing address",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ });
+
+ // Assert that the main component is rendered
+ cy.get(".frame-01").should("exist");
+
+ // Assert that the first field is displayed
+ cy.get("#addr_0").should("exist");
+ });
+
+ describe("additional delivery information", () => {
+ let bus: ReturnType>;
+
+ beforeEach(() => {
+ bus = useEventBus("modal-notification");
+ bus.on((payload) => {
+ payload.handler(); // automatically proceed with the deletion
+ });
+
+ cy.mount(LocationsWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ });
+ });
+
+ afterEach(() => {
+ bus.reset();
+ });
+
+ it("should add the Additional delivery information and then remove it", () => {
+ // should not display the Additional delivery information input initially
+ cy.get("#complementaryAddressTwo_0").should("not.exist");
+
+ // click to add it
+ cy.contains("Add more delivery information").should("be.visible").click();
+
+ // should display the Additional delivery information input
+ cy.get("#complementaryAddressTwo_0").should("be.visible");
+
+ // should hide the button
+ cy.contains("Add more delivery information").should("not.exist");
+
+ // click to remove it
+ cy.get("#deleteAdditionalDeliveryInformation_0").click();
+
+ // should hide the Additional delivery information input again
+ cy.get("#complementaryAddressTwo_0").should("not.exist");
+
+ // the button to add it is visible again
+ cy.contains("Add more delivery information").should("be.visible");
+ });
+
+ it("should display an error on the Delivery information when it's empty and Additional delivery information is displayed", () => {
+ cy.contains("Add more delivery information").click();
+
+ cy.get("#complementaryAddressTwo_0").should("be.visible");
+
+ // the error arrises
+ cy.get("#complementaryAddressOne_0")
+ .find("input")
+ .should("have.class", "cds--text-input--invalid");
+
+ // click to remove it
+ cy.get("#deleteAdditionalDeliveryInformation_0").click();
+
+ // the error goes away
+ cy.get("#complementaryAddressOne_0")
+ .find("input")
+ .should("not.have.class", "cds--text-input--invalid");
+
+ cy.contains("Add more delivery information").click();
+
+ cy.get("#complementaryAddressTwo_0").should("be.visible");
+
+ // the error is back
+ cy.get("#complementaryAddressOne_0")
+ .find("input")
+ .should("have.class", "cds--text-input--invalid");
+
+ cy.get("#complementaryAddressOne_0").find("input").type("anything");
+
+ // the error goes away
+ cy.get("#complementaryAddressOne_0")
+ .find("input")
+ .should("not.have.class", "cds--text-input--invalid");
+ });
+ });
+
+ const addAddress = (addressId: number, name: string) => {
+ cy.contains("Add another location").should("be.visible").click();
+
+ // Focus accordion title
+ // TODO: uncomment next line when the following issue is fixed: https://github.com/cypress-io/cypress/issues/26383
+ // cy.focused().should("contain.text", "Additional location");
+
+ cy.get(`#name_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(name);
+ };
+
+ describe("when an address which is not the last one gets deleted", () => {
+ const otherAddressNames = ["Sales Office", "Beach Office"];
+
+ const fillAddress = (
+ addressId: number,
+ { streetAddress, postalCode }: { streetAddress: string; postalCode: string },
+ ) => {
+ cy.get(`#addr_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(streetAddress);
+
+ cy.get(`#city_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type("Victoria");
+
+ cy.get(`#postalCode_${addressId}`)
+ .should("be.visible")
+ .shadow()
+ .find("input")
+ .should("have.value", "")
+ .type(postalCode);
+ };
+
+ let bus: ReturnType>;
+
+ const mountTest = (includeOtherAddressesInProps: boolean) => {
+ cy.mount(LocationsWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "Mailing address",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ...(includeOtherAddressesInProps ? otherAddressNames : []).map(
+ (locationName) => ({
+ ...emptyAddress(),
+ locationName,
+ }),
+ ),
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ })
+ .its("wrapper")
+ .as("vueWrapper");
+ };
+
+ // Multi-scenario test
+ [
+ { includeOtherAddressesInProps: true, predicate: "are provided in the props" },
+ { includeOtherAddressesInProps: false, predicate: "are added manually" },
+ ].forEach(({ includeOtherAddressesInProps, predicate }) =>
+ describe(`when other addresses ${predicate}`, () => {
+ beforeEach(() => {
+ bus = useEventBus("modal-notification");
+ bus.on((payload) => {
+ payload.handler(); // automatically proceed with the deletion
+ });
+
+ mountTest(includeOtherAddressesInProps);
+
+ if (!includeOtherAddressesInProps) {
+ otherAddressNames.forEach((name, index) => {
+ addAddress(index + 1, name);
+ });
+ }
+ });
+
+ afterEach(() => {
+ bus.reset();
+ });
+
+ it("removes the intended address from the DOM", () => {
+ cy.get("#deleteAddress_1").click();
+ cy.wait(150);
+ cy.get("#name_1").should("not.exist");
+ cy.get("#name_2").should("exist");
+ });
+
+ it("can submit the form (regardless of the deleted address being invalid)", () => {
+ cy.get("#deleteAddress_1").click();
+ cy.wait(150);
+
+ fillAddress(2, {
+ streetAddress: "456 Lumber Street",
+ postalCode: "B0B0B0",
+ });
+
+ cy.get("@vueWrapper").should((vueWrapper) => {
+ const lastValid = vueWrapper.emitted("valid").slice(-1)[0];
+
+ // The last valid event was emitted with true.
+ expect(lastValid[0]).to.equal(true);
+ });
+ });
+ }),
+ );
+ });
+
+ it("should display error messages when two locations have the same name", () => {
+ cy.mount(LocationsWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "My Office",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ streetAddress: "",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "",
+ postalCode: "",
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ });
+
+ cy.contains("Add another location").should("be.visible").click();
+
+ cy.get("#name_1").should("be.visible").find("input").type("my office");
+
+ cy.get("#name_0").find("input").should("have.class", "cds--text-input--invalid");
+ cy.get("#name_1").find("input").should("have.class", "cds--text-input--invalid");
+ });
+
+ it("should not display any error when two locations have the same address data", () => {
+ const address = {
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address;
+ cy.mount(LocationsWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "My Office",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ ...address,
+ } as Address,
+ {
+ locationName: "My Store",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ ...address,
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ },
+ });
+
+ cy.get("#addr_1").find("div").should("not.have.class", "cds--dropdown--invalid");
+ cy.get("#city_1").find("input").should("not.have.class", "cds--text-input--invalid");
+ });
+
+ it("prevents from having more locations than the provided maxLocations", () => {
+ const maxLocations = 5;
+
+ cy.mount(LocationsWizardStep, {
+ props: {
+ data: {
+ location: {
+ addresses: [
+ {
+ locationName: "Mailing address",
+ complementaryAddressOne: "",
+ complementaryAddressTwo: null,
+ streetAddress: "123 Forest Street",
+ country: { value: "CA", text: "Canada" },
+ province: { value: "BC", text: "British Columbia" },
+ city: "Victoria",
+ postalCode: "A0A0A0",
+ } as Address,
+ ],
+ contacts: [],
+ },
+ } as FormDataDto,
+ active: false,
+ maxLocations,
+ },
+ });
+
+ // The button is visible
+ cy.contains("Add another location").should("be.visible");
+
+ for (let index = 1; index < maxLocations; index++) {
+ addAddress(index, `${index + 1}`);
+ }
+
+ // The button gets hidden
+ cy.contains("Add another location").should("not.exist");
+ });
+});