diff --git a/package-lock.json b/package-lock.json index 93875c8b..f7197f64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1794,6 +1794,14 @@ "fastq": "^1.6.0" } }, + "@pinia/testing": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.0.14.tgz", + "integrity": "sha512-ZmZwVNd/NnKYLIfjfuKl0zlJ3UdiXFpsHzSlL6wCeezSlyrqGMxsIQKv0J6fleu38gyCNTPBEipfxrt8V4+VIg==", + "requires": { + "vue-demi": "*" + } + }, "@polka/url": { "version": "1.0.0-next.21", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", diff --git a/package.json b/package.json index 9b586f69..e9250297 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "test:unit:lite": "vue-cli-service test:unit --ci" }, "dependencies": { + "@pinia/testing": "0.0.14", "@popperjs/core": "^2.10.2", "axios": "^0.27.2", "bootstrap": "^5.2.2", diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index c54bbf01..87ed9f4c 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -1,144 +1,46 @@ import { storeActions } from "@/constants/store-actions"; -import { storeMutations } from "@/constants/store-mutations.js"; import { navigationScenarios } from "@/router/router-constants/navigation-scenarios.js"; import { vehicleCategories } from "@/constants/vehicle-categories.js"; -import { fmgPageValues } from "@/router/router-constants/fmgPage-values"; -import { cookieNames } from "@/constants/cookie-names"; +import { issPageValues } from "@/router/router-constants/issPage-values"; import { Form } from "vee-validate"; -import baseMixin from "@/mixins/base-mixin"; -import { - getCookieDomainValue, - setCookieProperties, -} from "@/helpers/heritage-integration/cookie-helper"; -import { - analyticsPageEvents, - GaCategories, - GaActions, - GaLabels, - GaEvents, - ValueToLogTypes, -} from "@/constants/analytics"; import { queryStrings } from "@/constants/query-strings"; -import { routerParams } from "@/router/router-constants/router-params"; +import { useMainStore } from "@/store"; +import { mapStores } from "pinia"; +import { createTestingPinia } from '@pinia/testing'; + +const pinia = createTestingPinia(); +useMainStore(pinia); + +const mockMixin = { + methods: { + getCmsContent: jest.fn() + }, + computed: { + ...mapStores(useMainStore), + } +}; + // Common methods export function getMountOptions(mockData) { - // Define our mocks to attached to the 'global' object for Vue/Jest. - const mocks = {}; + // Define our mocks to attached to the 'global' object for Vue/Jest. + const mocks = {}; - //this is mocking if you use the mixin directly(baseMixin.methods.dispatchStoreAction) vs this.dispatchStoreAction - setupBaseMixinDispatchStoreAction(mockData); - mocks.pushEventToGA = jest.fn(); - mocks.pushPageViewToGA = jest.fn(); - mocks.logEvent = jest.fn(); - mocks.pushExperimentsToDataLayer = jest.fn(); - mocks.prependActionToMethod = jest.fn(); - mocks.dispatchStoreAction = jest.fn(); - mocks.dispatchStoreAction.mockImplementation((actionName) => { - let actionFilterResult = mockData.actionList?.filter((x) => x.actionName == actionName); + // Mock const files + mocks.storeActions = storeActions; + mocks.navigationScenarios = navigationScenarios; + mocks.vehicleCategories = vehicleCategories; + mocks.issPageValues = issPageValues; + mocks.queryStrings = queryStrings; - if (actionFilterResult?.length === 1) { - return Promise.resolve({ - data: actionFilterResult[0].data, - }); - } - }); - // Mock const files - mocks.storeActions = storeActions; - mocks.storeMutations = storeMutations; - mocks.navigationScenarios = navigationScenarios; - mocks.vehicleCategories = vehicleCategories; - mocks.fmgPageValues = fmgPageValues; - mocks.analyticsPageEvents = analyticsPageEvents; - mocks.GaCategories = GaCategories; - mocks.GaActions = GaActions; - mocks.GaLabels = GaLabels; - mocks.GaEvents = GaEvents; - mocks.ValueToLogTypes = ValueToLogTypes; - mocks.queryStrings = queryStrings; - mocks.routerParams = routerParams; + const global = { + mocks: mocks, + mixins: [mockMixin], + plugins: [pinia], + stubs: { Form } + }; - // Mock $store and $router when accessing this.$store/$router - mocks.$store = mockData.store; - mocks.$router = mockData.router; - mocks.$route = mockData.route; - mocks.$loadScript = mockData.loadScript; - - const global = { - mocks: mocks, - mixins: mockData.mixins, - stubs: { Form }, - }; - - return { global }; -} - -export function setupMocksForJsFiles(mockData = {}) { - setupBaseMixinDispatchStoreAction(mockData); - - return { baseMixin }; -} - -// Heritage integration common methods -export const cookies = { - [cookieNames.FUNNEL_SESSION_INFO]: `{"ReferralNumber":"1566818","ReferralDate":"2022-03-15T10:56:24.597","ReferralCorrelationId":"404d2b04-f86e-45c3-b373-127b6217b060","ShouldResetState":false,"DidHeritageFunnelUpdateLast":true}`, - UNIQUE_SESSION_ID: "33756020-b58e-4ec7-b8b8-3f1576719c40", - anotherCookie: "{}", - someOtherCookie: "{}", - dxdev: "did=21b9b94a-ec23-42c1-aaac-e2ae4e4dbffe", - sid: "cba0c3d1-3c1b-4305-bb56-31aa50f58e27", - skey: "12345", -}; - -// Removes test cookies for testing cookie-helper and order-helper -export function removeAllTestCookies() { - Object.keys(cookies).forEach((key) => { - document.cookie = `${key}=;Max-Age=0;`; - document.cookie = `${key}=;Max-Age=0;path=/;${getCookieDomainValue()}`; - }); -} - -export function getMockOrderInfo( - mockReferralNumber, - mockCorrelationId, - mockReferralDate, - accountNumber = "0", - savedSessionId, - crmCustomerId -) { - return { - referralNumber: mockReferralNumber, - referralCorrelationId: mockCorrelationId, - referralDate: mockReferralDate, - accountNumber: accountNumber, - savedSessionId: savedSessionId, - crmCustomerId: crmCustomerId, - }; -} - -export function setupCookies({ funnelCookieValue = "", includeHeritageCookie = true }) { - Object.keys(cookies).forEach((key) => { - const cookieValue = - key == cookieNames.FUNNEL_SESSION_INFO ? funnelCookieValue : cookies[key]; - if (includeHeritageCookie || key != cookieNames.FUNNEL_SESSION_INFO) - setCookieProperties({ [key]: cookieValue }, { isSecure: false }); - }); -} - -// Private methods -function setupBaseMixinDispatchStoreAction(mockData) { - if (mockData.actionList !== undefined) { - baseMixin.methods.dispatchStoreAction = jest.fn(); - baseMixin.methods.dispatchStoreAction.mockImplementation((actionName) => { - let actionFilterResult = mockData.actionList.filter((x) => x.actionName == actionName); - - if (actionFilterResult.length > 0 && actionFilterResult.length === 1) { - return Promise.resolve({ - data: actionFilterResult[0].data, - }); - } - }); - } + return { global }; } diff --git a/src/layouts/vehicle-year/vehicle-year.spec.js b/src/layouts/vehicle-year/vehicle-year.spec.js new file mode 100644 index 00000000..21200c1b --- /dev/null +++ b/src/layouts/vehicle-year/vehicle-year.spec.js @@ -0,0 +1,87 @@ +import { shallowMount } from "@vue/test-utils"; +import { settleAllPromises } from "@/helpers/layout-helper.js"; +import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; +import vehicleYear from "@/layouts/vehicle-year/vehicle-year.vue"; +import yearQuestion from "@/layouts/vehicle-year/year-question/year-question"; +import baseMixin from "@/mixins/base-mixin.js"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; + + +// Mock our module for promises. +jest.mock("@/helpers/layout-helper.js", () => ({ + settleAllPromises: jest.fn(), +})); + +// Mock fetchCmsContentForPage +jest.mock("@/helpers/cms-content-helper", () => ({ + fetchCmsContentForPage: jest.fn(), +})); + +describe("vehicle-year.vue", () => { + test("Year question component is initized with api data", async() => { + //Arrange + const yearQuestionInitialData = ["2023", "2022", "2021"]; + const { wrapper, apiPromise } = setupMocks({ + yearQuestionInitialData: yearQuestionInitialData, + }); + + + //Act + vehicleYear.beforeRouteEnter.call( + wrapper.vm, + { query: { issPage: "vehicle-year" } }, + undefined, + (c) => c(wrapper.vm) + ); + + //Assert + apiPromise.finally(() => { + expect(yearQuestion.methods.initializeComponent).toHaveBeenCalledWith( + yearQuestionInitialData + ); + }); + }); +}); + +function setupMocks({ + vehicleYearQuestionCmsContent = {}, + yearQuestionInitialData = {}, + pageHeaderWidgetHeaderText = {}, + mountOptionsMockData = {}, +}) { + //Mock api responses + const apiResponses = { + cmsContent: { + SiteSubHeaderWidget: { HeaderText: pageHeaderWidgetHeaderText }, + VehicleYearQuestion: vehicleYearQuestionCmsContent, + VehicleBannerWidget: { + GenericVehicleImage: + "https://digitalisscms.dev.safelite.io/images/default-source/default-album/blurred-image.jpg", + }, + SiteHeaderWidget: { + LogoImage: + "https://digitalisscms.dev.safelite.io/images/default-source/default-album/logos/insuranceLogo.jpg", + }, + }, + yearQuestionInitialData: yearQuestionInitialData, + }; + const apiPromise = Promise.resolve(apiResponses); + + settleAllPromises.mockImplementation(() => apiPromise); + fetchCmsContentForPage.mockImplementation(() => Promise.resolve()); + + //Mock year question methods + yearQuestion.methods = { + loadInitialData: jest.fn(), + initializeComponent: jest.fn(), + }; + + const mountOptions = getMountOptions(mountOptionsMockData); + const wrapper = shallowMount(vehicleYear, mountOptions); + + const yearQuestionWrapper = wrapper.findComponent({ name: "yearQuestion" }); + yearQuestionWrapper.vm.initializeComponent = yearQuestion.methods.initializeComponent; + wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent; + + return { wrapper, apiPromise }; +} diff --git a/src/layouts/vehicle-year/year-question/year-question.spec.js b/src/layouts/vehicle-year/year-question/year-question.spec.js new file mode 100644 index 00000000..c6e17547 --- /dev/null +++ b/src/layouts/vehicle-year/year-question/year-question.spec.js @@ -0,0 +1,53 @@ +import yearQuestion from "@/layouts/vehicle-year/year-question/year-question"; +import { shallowMount } from "@vue/test-utils"; +import { getMountOptions } from "@/helpers/unit-test-helper.js"; +import { useMainStore } from "@/store"; + +describe("year-question.vue", () => { + test("Data from store api are used as radio question answers.", async () => { + //Arrange + const { wrapper, cmsContent } = setupMocks({ + dataFromStoreApi: ["2023", "2022", "2021"], + }); + + //Act + const initialData = yearQuestion.methods.loadInitialData.call(wrapper.vm); + yearQuestion.methods.initializeComponent.call( + wrapper.vm, + initialData + ); + + //Assert + const buttonQuestionComponent = await wrapper.findComponent({ + name: "buttonQuestion", + }); + expect(buttonQuestionComponent.attributes("answers")).toBe( + "2023,2022,2021" + ); + }); +}); + + +function setupMocks({ + modelValueProp = "1900", + cmsQuestionText = "CMS text goes here", + dataFromStoreApi = [], +}) { + + const mountOptions = getMountOptions(); + + const store = useMainStore(); + store.getVehicleYears = jest.fn(() => dataFromStoreApi); + //Mock props + mountOptions.propsData = { + modelValue: modelValueProp, + }; + + const wrapper = shallowMount(yearQuestion, mountOptions); + + //Mock CMS content + const cmsContent = { + QuestionText: cmsQuestionText, + }; + return { wrapper, cmsContent }; +} diff --git a/src/router/router.spec.js b/src/router/router.spec.js index 8c15c36c..521b382e 100644 --- a/src/router/router.spec.js +++ b/src/router/router.spec.js @@ -1,5 +1,5 @@ -import router from "@/router/" -import { navigationScenarios } from "@/router/router-constants/navigation-scenarios" +import router from "@/router/"; +import { navigationScenarios } from "@/router/router-constants/navigation-scenarios"; import { issPageValues } from "@/router/router-constants/issPage-values"; import { createApp } from 'vue';