diff --git a/src/common-components/button-question/button-question.spec.js b/src/common-components/button-question/button-question.spec.js index 591b34317..2ef0ee422 100644 --- a/src/common-components/button-question/button-question.spec.js +++ b/src/common-components/button-question/button-question.spec.js @@ -1,9 +1,9 @@ import { shallowMount } from "@vue/test-utils"; import buttonQuestion from "@/common-components/button-question/button-question"; -import { nextTick } from "vue"; import { getMountOptions } from "@/helpers/unit-test-helper.js"; -import store from "@/store"; -jest.mock("@/store",()=>{return{};},{virtual:true}); +import analyticsMixIn from "@/mixins/analytics-mixin"; + +jest.mock("@/store", () => { return {}; }, { virtual: true }); describe("buttonQuestion.vue", () => { it("Should show overflow classes on fieldset if isOverflowScrollable is true", () => { @@ -76,7 +76,7 @@ describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => { it("getColLength should return '' if prop isWide is set to false", () => { // Act - const localThis = { + const localThis = { isWide: false, answers: ['a', 'b'] } @@ -110,12 +110,12 @@ describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => { it("Should trigger event modelValue change to new value on when radio button selected", async () => { // Act - const wrapper = shallowMount(buttonQuestion); + const wrapper = shallowMount(buttonQuestion, setupMocks({})); await wrapper.setProps({ answers: ["2022", "2021", "2020"], isMultiSelect: false }); - const val = {checkValue: true, value: "2021", } + const val = { checkValue: true, value: "2021", } wrapper.vm.handleCheckedChanged(val); // Assert expect(wrapper.emitted()["update:modelValue"][0]).toEqual([["2021"]]); @@ -125,13 +125,13 @@ describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => { it("Should add values to array on checkbox click", () => { // Act - const wrapper = shallowMount(buttonQuestion, { + const wrapper = shallowMount(buttonQuestion, setupMocks({ propsData: { modelValue: ["2022", "2021", "2020"], isMultiSelect: true, } - }); - const val = {checkValue: true, value: "2019", } + })); + const val = { checkValue: true, value: "2019", } wrapper.vm.handleCheckedChanged(val); // Assert expect(wrapper.emitted()["update:modelValue"][0]).toEqual([["2022", "2021", "2020", "2019"]]); @@ -141,12 +141,12 @@ describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => { it("Should add a value to this.selectedValues if prop isMultiSelect is true, checkValue is true and this.selectedValues already exists", () => { // Act - const wrapper = shallowMount(buttonQuestion, { + const wrapper = shallowMount(buttonQuestion, setupMocks({ propsData: { - isMultiSelect: true, - modelValue: [ 'a', 'b' ] + isMultiSelect: true, + modelValue: ['a', 'b'] } - }); + })); const val = { checkValue: true, value: "2021", } wrapper.vm.handleCheckedChanged(val); @@ -158,12 +158,13 @@ describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => { it("Should remove a value to this.selectedValues if prop isMultiSelect is true, checkValue is false and this.selectedValues already exists", () => { // Act - const wrapper = shallowMount(buttonQuestion, { + const wrapper = shallowMount(buttonQuestion, setupMocks({ propsData: { - isMultiSelect: true, - modelValue: [ 'a', 'b' ] + isMultiSelect: true, + modelValue: ['a', 'b'] } - }); + })); + const val = { checkValue: false, value: "a", } wrapper.vm.handleCheckedChanged(val); @@ -176,12 +177,12 @@ describe("buttonQuestion.vue", () => { describe("buttonQuestion.vue", () => { it("Should do nothing to this.selectedValues if this.selectedValues is not an array", () => { // Act - const wrapper = shallowMount(buttonQuestion, { + const wrapper = shallowMount(buttonQuestion, setupMocks({ propsData: { - isMultiSelect: true, + isMultiSelect: true, modelValue: 'a', } - }); + })); const val = { checkValue: true, value: "c", } wrapper.vm.handleCheckedChanged(val); @@ -189,3 +190,11 @@ describe("buttonQuestion.vue", () => { expect(wrapper.vm.selectedValues).toEqual("a"); }); }); + +function setupMocks(mountOptionsMockData = {}) { + const defaultMountOptions = { route: { query: { fmgPage: 'page-name' } } }; + const baseMountOptions = getMountOptions(Object.assign(defaultMountOptions, mountOptionsMockData)); + const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions); + + return allMountOptions; +} diff --git a/src/global-methods.spec.js b/src/global-methods.spec.js index 59fa15b77..5dcba0ccd 100644 --- a/src/global-methods.spec.js +++ b/src/global-methods.spec.js @@ -1,13 +1,16 @@ import globalMethods from "@/global-methods"; import axios from "axios"; +import analyticsMixIn from "@/mixins/analytics-mixin"; //Mock external dependencies jest.mock("axios"); +jest.mock("@/mixins/analytics-mixin"); it("Global Methods - Call Http Client - Should Resolve Promise", () => { //Arrange const endpoint = "https://mock.safelite.com"; const httpArgs = setupMocksForHttpClient({ endpoint: endpoint }); + analyticsMixIn.methods.pushEventToGA = jest.fn(); //Act globalMethods.callHttpClient(httpArgs).then((response) => { @@ -25,6 +28,7 @@ it("Global Methods - Call Http Client - Should Reject Promise", () => { endpoint: endpoint, isError: true, }); + analyticsMixIn.methods.pushEventToGA = jest.fn(); //Act globalMethods.callHttpClient(httpArgs).catch((err) => { @@ -72,5 +76,6 @@ function setupMocksForHttpClient({ return { endpoint: endpoint, + logApiCall: true }; } diff --git a/src/helpers/unit-test-helper.js b/src/helpers/unit-test-helper.js index 753465886..95777d06b 100644 --- a/src/helpers/unit-test-helper.js +++ b/src/helpers/unit-test-helper.js @@ -7,6 +7,7 @@ import { cookieNames } from "@/constants/cookie-names"; import { Form } from "vee-validate"; import baseMixin from "@/mixins/base-mixin"; import { getCookieDomainValue } from "@/helpers/heritage-integration/cookie-helper"; +import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents } from "@/constants/analytics"; // Common methods export function getMountOptions(mockData) { @@ -16,6 +17,11 @@ export function getMountOptions(mockData) { //this is mocking if you use the mixin directly(baseMixin.methods.dispatchNonBlockingStoreAction) vs this.dispatchNonBlockingStoreAction setupBaseMixinDispatchNonBlockingStoreAction(mockData); + mocks.pushEventToGA = jest.fn(); + mocks.pushPageViewToGA = jest.fn(); + mocks.logEvent = jest.fn(); + mocks.pushExperimentsToDataLayer = jest.fn(); + mocks.dispatchNonBlockingStoreAction = jest.fn(); mocks.dispatchNonBlockingStoreAction.mockImplementation((actionName) => { let actionFilterResult = mockData.actionList.filter( @@ -35,6 +41,11 @@ export function getMountOptions(mockData) { mocks.navigationScenarios = navigationScenarios; mocks.vehicleCategories = vehicleCategories; mocks.fmgPageValues = fmgPageValues; + mocks.analyticsPageEvents = analyticsPageEvents; + mocks.GaCategories = GaCategories; + mocks.GaActions = GaActions; + mocks.GaLabels = GaLabels; + mocks.GaEvents = GaEvents; // Mock $store and $router when accessing this.$store/$router mocks.$store = mockData.store; diff --git a/src/mixins/analytics-mixin.js b/src/mixins/analytics-mixin.js index f6c9222a5..410c39342 100644 --- a/src/mixins/analytics-mixin.js +++ b/src/mixins/analytics-mixin.js @@ -5,8 +5,6 @@ import { experimentSettings } from "@/constants/experiments"; import { analyticsPageEvents, GaCategories, GaActions, GaLabels, GaEvents } from "@/constants/analytics"; import baseMixin from "@/mixins/base-mixin"; -import { applicationConfig } from "@/constants/application-config.js"; -import axios from "axios"; // We will need current page name for multiple methods, define it once to re-use. const currentPageName = getPageNameByQueryString(); diff --git a/src/mixins/analytics-mixin.spec.js b/src/mixins/analytics-mixin.spec.js index aa0cfb022..e79a64882 100644 --- a/src/mixins/analytics-mixin.spec.js +++ b/src/mixins/analytics-mixin.spec.js @@ -9,13 +9,75 @@ describe("analyticsMixin.js", () => { const mockData = { actionList: [{ - actionName: storeActions.LOG_ACTIVITY + actionName: storeActions.LOG_ACTIVITY }], } - var mocks = setupMocksForJsFiles(mockData); + const mocks = setupMocksForJsFiles(mockData); analyticsMixin.methods.logEvent(type, payload); expect(mocks.baseMixin.methods.dispatchNonBlockingStoreAction).toBeCalled(); }); + + test("pushEventToGA, should call logEvent too", () => { + // Arrange + const mockData = { + actionList: [{ + actionName: storeActions.LOG_ACTIVITY + }], + } + const mocks = setupMocksForJsFiles(mockData); + + // Act + analyticsMixin.methods.pushEventToGA('category', 'action', 'label', true); + + // Assert + expect(mocks.baseMixin.methods.dispatchNonBlockingStoreAction).toBeCalled(); + + }); + + test("Experiments, should push to dataLayer with default Google Custom Dimension Index", () => { + // Arrange + window.dataLayer = []; + + const mockExperimentData = { + data: [ + { + settings: {}, + variationName: 'test', + universeName: 'testUniverse' + } + ] + } + + // Act + analyticsMixin.methods.pushExperimentsToDataLayer(mockExperimentData); + + // Assert + expect(window.dataLayer).toEqual([ { settings_99: {}, variationName_99: 'test', universeName_99: 'testUniverse' } ]); + + }); + + test("Experiments, should push to dataLayer with custom Google Custom Dimension Index", () => { + // Arrange + window.dataLayer = []; + + const mockExperimentData = { + data: [ + { + settings: { "Google Custom Dimension Index": "5"}, + variationName: 'test', + universeName: 'testUniverse' + } + ] + } + + // Act + analyticsMixin.methods.pushExperimentsToDataLayer(mockExperimentData); + + // Assert + expect(window.dataLayer).toEqual([ { settings_5: {"Google Custom Dimension Index": "5"}, variationName_5: 'test', universeName_5: 'testUniverse' } ]); + + }); + }); \ No newline at end of file