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"); + }); +});