CSR-803: several unit tests

This commit is contained in:
Adam Caouette 2022-11-17 14:28:40 -05:00
parent c17d3d9194
commit c286f748b6
14 changed files with 1759 additions and 262 deletions

View file

@ -13,12 +13,9 @@ module.exports = {
"!src/router/**/*.js",
"!src/helpers/unit-test-helper.js",
"!src/layouts/vehicle-damage/windshield-options/windshield-options.vue",
"!src/layouts/molding-questions/**/*.vue",
"!src/layouts/capability-questions/**/*.vue",
"!src/layouts/part-questions/**/*.vue",
"!src/layouts/reveal/**/*.vue",
"!src/ux-components/text-link/**/*.vue",
"!src/common-components/question-chain/**/*.vue",
"!src/common-components/date-picker/**/*.vue",
"!src/layouts/vin-lookup/**/*.vue", //Temporary for Quote page testing
"!src/common-components/funnel-header/menu-modal/**/*.vue",
// END

View file

@ -2,7 +2,7 @@ import { mount } from "@vue/test-utils";
import funnelFooter from "./funnel-footer";
describe("funnel-footer.vue", () => {
it("Should emit ForwardClicked on button click", async () => {
test("Should emit ForwardClicked on button click", async () => {
// Act
const wrapper = mount(funnelFooter, {
mixins: [mockMixin],
@ -12,7 +12,7 @@ describe("funnel-footer.vue", () => {
expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled;
});
it("Should emit BackClicked on link click", async () => {
test("Should emit BackClicked on link click", async () => {
// Act
const wrapper = mount(funnelFooter, {
mixins: [mockMixin],
@ -22,7 +22,7 @@ describe("funnel-footer.vue", () => {
expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled;
});
it("Should change button text when update button text is called", async () => {
test("Should change button text when update button text is called", async () => {
// Act
const wrapper = mount(funnelFooter, {
mixins: [mockMixin],
@ -32,6 +32,23 @@ describe("funnel-footer.vue", () => {
// Assert
expect(wrapper.componentVM.customButtontext).toBe("newText");
});
test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => {
// Arrange
const wrapper = mount(funnelFooter, {
mixins: [mockMixin],
});
// Act
wrapper.vm.$refs.buttonMain.removeLoader = jest.fn();
wrapper.vm.removeLoader();
const spy = jest.spyOn(document, "onkeydown");
document.onkeydown();
// Assert
expect(wrapper.vm.$refs.buttonMain.removeLoader).toHaveBeenCalled();
expect(spy).toReturnWith(true);
});
});
const mockMixin = {

View file

@ -0,0 +1,322 @@
import { shallowMount } from "@vue/test-utils";
import questionChain from "@/common-components/question-chain/question-chain.vue";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
jest.mock(
"@/store",
() => {
return {};
},
{ virtual: true }
);
describe("Question Chain component", () => {
describe("on create...", () => {
test("Should populate questions data array", async () => {
//Arrange
const { wrapper } = setupMocks({});
const expectedFirstQuestionAnswer = {
answerResult: "DB09410",
buttonLabel: "Yes",
nextQuestionSequence: null,
questionSequence: 1,
questionType: "answer",
value: "1|answer|DB09410|Yes",
};
//Act
await nextTick();
//Assert
expect(wrapper.vm.questions[0].answers[0]).toMatchObject(expectedFirstQuestionAnswer);
});
test("Should not include suppressed questions on questions data array", async () => {
//Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
questionData: [
{
questionSequence: 1,
questionText: "Question here?",
answers: [
{
answerResult: "DB09410",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "DB10840",
answerText: "No",
nextQuestionSequence: null,
},
],
suppressThisQuestion: true,
},
],
});
//Act
await nextTick();
//Assert
expect(wrapper.vm.questions[0]).toBeFalsy();
});
});
describe("method handleAnswer...", () => {
test("should run getQuestionChainAnswerIfComplete", () => {
//Arrange
const { wrapper } = setupMocks({});
const testQuestion = {};
const testReturnedAnswer = "aReturnedAnswer";
wrapper.vm.getQuestionChainAnswerIfComplete = jest.fn();
//Act
wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);
//Assert
expect(wrapper.vm.getQuestionChainAnswerIfComplete).toBeCalled();
});
test("should emit update:modelValue if returnedAnswer contains 'answer'", () => {
//Arrange
const { wrapper } = setupMocks({});
const testQuestion = {};
const testReturnedAnswer = "1|answer|DB10840|No";
//Act
wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);
//Assert
expect(wrapper.emitted()).toHaveProperty("update:modelValue");
expect(wrapper.emitted()["update:modelValue"][0][0]).toMatchObject({
answerResult: "DB10840",
});
});
test("should NOT emit update:modelValue if no returnedAnswer", () => {
//Arrange
const { wrapper } = setupMocks({});
const testQuestion = {};
//Act
wrapper.vm.handleAnswer(testQuestion);
//Assert
expect(wrapper.emitted()).not.toHaveProperty("update:modelValue");
});
test("should NOT emit update:modelValue if returnedAnswer contains 'nextQuestion'", () => {
//Arrange
const { wrapper } = setupMocks({});
const testQuestion = {};
const testReturnedAnswer = "1|nextQuestion|DB10840|No";
//Act
wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);
//Assert
expect(wrapper.emitted()).not.toHaveProperty("update:modelValue");
});
});
describe("method getQuestionChainAnswerIfComplete...", () => {
test("should return false if no returned answer", () => {
//Arrange
const { wrapper } = setupMocks({});
//Act
const result = wrapper.vm.getQuestionChainAnswerIfComplete();
//Assert
expect(result).toBeFalsy();
});
test("should set the answerSelected to match the answered one", async () => {
//Arrange
const { wrapper } = setupMocks({});
const testReturnedAnswer = "1|answer|DB10840|No";
await wrapper.setData({
questionData: [
{
questionSequence: 1,
questionText: "Question here?",
answers: [
{
answerResult: "DB09410",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "DB10840",
answerText: "No",
nextQuestionSequence: null,
},
],
},
],
});
//Act
wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
//Assert
expect(wrapper.vm.questions[0].answerSelected).toBe("1|answer|DB10840|No");
});
test("should remove answers of questions after the answered one", async () => {
//Arrange
const { wrapper } = setupMocks({});
const testReturnedAnswer = "1|answer|DB10840|No";
await wrapper.setData({
questionData: [
{
questionSequence: 1,
questionText: "Question here?",
answers: [
{
answerResult: "DB09410",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "DB10840",
answerText: "No",
nextQuestionSequence: null,
},
],
},
{
questionSequence: 2,
questionText: "Question 2",
answers: [
{
answerResult: "2-yes",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "2-no",
answerText: "No",
nextQuestionSequence: null,
},
],
answerSelected: "previously selected answer",
},
],
});
//Act
wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
//Assert
expect(wrapper.vm.questions[1].answerSelected).toBeUndefined;
});
test("should return false if returnedAnswer is a nextQuestion (not a final answer)", async () => {
//Arrange
const { wrapper } = setupMocks({});
const testReturnedAnswer = "1|nextQuestion|DB10840|No";
//Act
const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
//Assert
expect(result).toBeFalsy();
});
test("should trigger scroll to .current-question if returnedAnswer is a nextQuestion (not a final answer)", async () => {
//Arrange
const { wrapper } = setupMocks({});
const testReturnedAnswer = "1|nextQuestion|DB10840|No";
//Act
wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
await nextTick();
//Assert
expect(Element.prototype.scrollIntoView).toHaveBeenCalled();
});
test("should return answer object if returnedAnswer is a final matching answer", async () => {
//Arrange
const { wrapper } = setupMocks({});
const testReturnedAnswer = "1|answer|DB10840|No";
await wrapper.setData({
questions: [
{
questionSequence: 1,
questionText: "Question here?",
answers: [
{
answerResult: "DB09410",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "DB10840",
answerText: "No",
nextQuestionSequence: null,
},
],
},
],
index: 0,
});
//Act
const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);
//Assert
expect(result).toMatchObject({
answerResult: "DB10840",
answeredQuestions: [
{ questionNum: 1, questionText: "Question here?", selectedAnswerText: "No" },
{
questionNum: 1,
questionText: "Does only your center sliding piece need to be replaced?",
selectedAnswerText: "No",
},
],
index: 0,
});
});
});
});
function setupMocks({
questionDataProp = [
{
questionSequence: 1,
questionText: "Does only your center sliding piece need to be replaced?",
answers: [
{
answerResult: "DB09410",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "DB10840",
answerText: "No",
nextQuestionSequence: null,
},
],
},
],
}) {
Element.prototype.scrollIntoView = jest.fn();
const mountOptions = getMountOptions({});
mountOptions.propsData = {
questionData: questionDataProp,
};
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(questionChain, mountOptions);
return { wrapper };
}

View file

@ -1,241 +0,0 @@
import { shallowMount } from "@vue/test-utils";
import questionChain from "@/common-components/question-chain/question-chain.vue";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
jest.mock("@/store",()=>{return{};},{virtual:true});
describe("Question Chain component", () => {
it("Should not emit a modelValue change when setting selectedValue if isNewModelValueComplete is false", () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: [] });
wrapper.vm.currentQuestion = 6;
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
const localThis = {
$emit: jest.fn(),
getNewModelValue: jest.fn(() => { return false })
}
//Act
questionChain.computed.selectedValue.set.call(localThis, answerReturned);
//Assert
expect(localThis.$emit).not.toBeCalled();
});
it("Should emit a modelValue change when setting selectedValue if isNewModelValueComplete is true", () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: [] });
wrapper.vm.currentQuestion = 6;
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
const localThis = {
$emit: jest.fn(),
getNewModelValue: jest.fn(() => { return true })
}
//Act
questionChain.computed.selectedValue.set.call(localThis, answerReturned);
//Assert
expect(localThis.$emit).toBeCalledWith("update:modelValue", true);
});
it("should return false if no returned answer is given", () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: [] });
wrapper.vm.currentQuestion = 1;
const answerReturned = null;
//Act
const result = wrapper.vm.getNewModelValue(answerReturned);
//Assert
expect(result).toEqual(false);
});
it("should return false if the user's answer on the current question leads to another question", () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: [] });
wrapper.vm.currentQuestion = 1;
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
//Act
const result = wrapper.vm.getNewModelValue(answerReturned);
//Assert
expect(result).toEqual(false);
});
it("should return an object with the final answer if the user's answer on the current question is a part number", () => {
//Arrange
const { wrapper } = setupMocks({ modelValueProp: [] });
wrapper.vm.currentQuestion = 6;
const answerReturned = [wrapper.vm.questions[wrapper.vm.currentQuestion].answers[0].Name.toString()];
//Act
const result = wrapper.vm.getNewModelValue(answerReturned);
//Assert
expect(result).toEqual(
{
answerResult: 'DW02102',
answeredQuestions: [
{
questionText: 'Is your vehicle equipped with heated seats?',
selectedAnswerText: 'Yes'
}
]
}
);
});
});
function setupMocks({
modelValueProp = "",
questionDataProp = {
"glassName": "Single",
"glassLocation": "Windshield",
"parts": null,
"partQuestions": [
{
"questionSequence": 1,
"questionText": "Is your Cherokee the Overland edition which can be identified by having a wood and leather wrapped steering wheel?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": 2,
"answerResult": ""
},
{
"answerText": "No",
"nextQuestionSequence": 3,
"answerResult": ""
}
]
},
{
"questionSequence": 2,
"questionText": "Is your vehicle equipped with rain sensing wipers that adjust their speed automatically when it rains?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW02270"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW02264"
}
]
},
{
"questionSequence": 3,
"questionText": "Is your vehicle equipped with rain sensing wipers that adjust their speed automatically when it rains?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW02268"
},
{
"answerText": "No",
"nextQuestionSequence": 4,
"answerResult": ""
}
]
},
{
"questionSequence": 4,
"questionText": "Is your vehicle equipped with automatic climate control which will change the fan speed automatically in order to maintain a set temperature?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": 5,
"answerResult": ""
},
{
"answerText": "No",
"nextQuestionSequence": 6,
"answerResult": ""
}
]
},
{
"questionSequence": 5,
"questionText": "Is your vehicle equipped with heated seats?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW02104"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW02103"
}
]
},
{
"questionSequence": 6,
"questionText": "Is your vehicle equipped with heated seats?",
"answers": [
{
"answerText": "Yes",
"nextQuestionSequence": null,
"answerResult": "DW02102"
},
{
"answerText": "No",
"nextQuestionSequence": null,
"answerResult": "DW02101"
}
]
}
],
},
methodsToMock = [],
}) {
//Mock store
store.dispatch = jest.fn(() => dataFromStoreApi);
store.getters = { vehicle: {year: 2019, make: 'honda', model: 'civc', style: '2 Door', category: 'CAR'} };
const mountOptions = getMountOptions({
store: {
dispatch: store.dispatch,
getters: store.getters,
},
});
//Mock props
const mockMixin = {
methods: {
getCmsContent: jest.fn()
}
}
mountOptions.propsData = {
modelValue: modelValueProp,
questionData: questionDataProp,
};
mountOptions.mixins = [mockMixin];
//Mock methods
methodsToMock.forEach((methodName) => {
questionChain.methods[methodName] = jest.fn();
});
const wrapper = shallowMount(questionChain, mountOptions);
//Mock CMS content
const cmsContent = {
};
return { wrapper, cmsContent };
}

View file

@ -29,7 +29,7 @@ export default {
};
},
props: {
questionData: Object,
questionData: Array,
validationRules: String,
modelValue: Object,
index: Number,
@ -84,11 +84,7 @@ export default {
handleAnswer(question, returnedAnswer) {
/*
returnedAnswer example format:
{
"checkValue": "1|answer|DD11132|Yes",
"value": "1|answer|DD11132|Yes",
"buttonId": "Driver-Front-1-1|answer|DD11132|Yes"
}
"1|answer|DD11132|Yes"
*/
question.answerSelected = returnedAnswer;

View file

@ -0,0 +1,253 @@
// Components
import questionsPageLayout from "@/common-components/questions-page-layout/questions-page-layout";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import baseMixin from "../../mixins/base-mixin";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
// 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(),
}));
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateToHeritageFunnel: jest.fn(),
}));
describe("questionsPageLayout.vue", () => {
describe("method showThisQuestionChain...", () => {
test("Should return true if index prop and passed index match", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({ index: 0 });
const testGlassPiece = {
questions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
answers: [],
},
],
};
const testIndex = 0;
// Act
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
//Assert
expect(result).toBe(true);
wrapper.unmount();
});
test("Should return true if answerResult exists", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({ index: 0 });
const testGlassPiece = {
questions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
answers: [],
},
],
answerData: {
answerResult: "test",
},
};
const testIndex = 1;
// Act
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
//Assert
expect(result).toBe(true);
wrapper.unmount();
});
test("Should return false if indexes don't match and answerResult is missing", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({ index: 0 });
const testGlassPiece = {
questions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
answers: [],
},
],
};
const testIndex = 1;
// Act
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
//Assert
expect(result).toBe(false);
wrapper.unmount();
});
test("Should return false if no questions", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({ index: 0 });
const testGlassPiece = {};
const testIndex = 0;
// Act
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
//Assert
expect(result).toBe(false);
wrapper.unmount();
});
test("Should return false if suppressed", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({ index: 0 });
const testGlassPiece = {
isSuppressedPart: true,
questions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
answers: [],
},
],
answerData: {
answerResult: "test",
},
};
const testIndex = 0;
// Act
const result = wrapper.vm.showThisQuestionChain(testGlassPiece, testIndex);
//Assert
expect(result).toBe(false);
wrapper.unmount();
});
});
describe("method handleForwardButtonAction...", () => {
test("Should emit forwardButtonAction", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({});
// Act
wrapper.vm.handleForwardButtonAction();
//Assert
expect(wrapper.emitted()).toHaveProperty("forwardButtonAction");
wrapper.unmount();
});
});
describe("method handleBackButtonAction...", () => {
test("Should emit backButtonAction", async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setProps({});
// Act
wrapper.vm.handleBackButtonAction();
//Assert
expect(wrapper.emitted()).toHaveProperty("back-click");
wrapper.unmount();
});
});
});
function setupMocks() {
const baseStoreGettersPageData = () => {
return {
partsOrQuestions: [
{
parts: null,
partQuestions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
answers: [
{
answerResult: "",
answerText: "Yes",
nextQuestionSequence: 2,
},
{
answerResult: "",
answerText: "No",
nextQuestionSequence: 3,
},
],
},
],
glassLocation: "Windshield",
glassName: "Single",
answerKey: "Windshield-Single",
answerData: null,
},
],
};
};
const baseStoreGettersDamage = () => {
return {
partsQuestionAnswers: [
{
glassLocation: "Windshield",
glassName: "Single",
result: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
},
],
};
};
const mountOptions = getMountOptions({
mixins: [baseMixin, vehicleQuestionsMixin],
});
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(questionsPageLayout, mountOptions);
return { wrapper };
}

View file

@ -51,7 +51,7 @@ export default {
alertFewMoreQuestionsCopy: String,
questionsData: Array,
validationRules: String,
modelValue: Array,
modelValue: Object,
index: Number,
},
computed: {
@ -66,9 +66,10 @@ export default {
},
methods: {
showThisQuestionChain(glass, i) {
// return false if no questions or if suppressed
if (!glass.questions || glass.questions?.length < 1 || glass.isSuppressedPart) {
return false;
} // return false if no questions or if suppressed
}
return this.index === i || glass.answerData?.answerResult?.length > 0;
},
handleForwardButtonAction() {

View file

@ -0,0 +1,404 @@
// Components
import capabilityQuestions from "@/layouts/capability-questions/capability-questions";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
import baseMixin from "../../mixins/base-mixin";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { nextTick } from "vue";
// 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(),
}));
jest.mock(
"@/store",
() => {
return {};
},
{ virtual: true }
);
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateToHeritageFunnel: jest.fn(),
}));
const baseStoreGettersPageData = () => {
return {
partsOrQuestions: [
{
parts: [
{
childPartQuestions: [],
},
],
capabilityQuestions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the optional Lane-Keeping System which tugs on the steering wheel and/or beeps to alert you if you drift too close to the edge of the lane?",
answers: [
{
answerResult1: "DYNAMIC",
answerResult2: "1",
answerText: "Yes",
nextQuestionSequence: null,
answerResult: "DYNAMIC",
},
{
answerResult1: "Unknown",
answerResult2: "0",
answerText: "No",
nextQuestionSequence: null,
answerResult: "Unknown",
},
],
},
],
partQuestions: [],
questions: [],
glassLocation: "Windshield",
glassName: "Single",
answerKey: "Windshield-Single",
answerData: null,
},
],
};
};
const baseStoreGettersDamage = () => {
return {
partsQuestionAnswers: [
{
glassLocation: "Windshield",
glassName: "Single",
result: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
},
],
};
};
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
};
store.commit = jest.fn();
afterEach(() => {
// reset store after each test
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
};
});
describe("capabilityQuestions.vue", () => {
describe("method arePagePrerequisitesValid...", () => {
test("Should return true for valid page requisites if pageData exists", () => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBe(true);
wrapper.unmount();
});
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
// Arrange
const { wrapper } = setupMocks({});
store.getters.pageData = jest.fn(() => {
return undefined;
});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
test("Should be at least one item in partsOrQuestions", () => {
// Arrange
store.getters = {
pageData: jest.fn(() => {
return {
partsOrQuestions: [],
};
}),
damage: baseStoreGettersDamage,
};
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
});
describe("watch on selectedAnswers should be set up...", () => {
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
// Arrange
const { wrapper } = setupMocks({});
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
// Act
wrapper.setData({
selectedAnswers: {
"Windshield-Single": {
answerResult: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
index: 0,
},
},
});
await nextTick();
//Assert
expect(spy).toHaveBeenCalled();
wrapper.unmount();
});
});
describe("forwardButtonAction", () => {
test("Should clear out answerData", () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
questions: [],
parts: [
{
childPartQuestions: [{}],
},
],
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
// Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
wrapper.unmount();
});
test("Should save to Vuex store", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
questions: [],
parts: [
{
childPartQuestions: [],
},
],
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(spy).toHaveBeenNthCalledWith(
1,
"saveCapabilityQuestionAnswers",
[
{
answeredQuestions: [],
glassLocation: "Windshield",
glassName: "Single",
isSuppressedPart: undefined,
result: "FW04848",
result1: "FW04848",
result2: undefined,
},
],
false
);
wrapper.unmount();
});
test("Should call GET_PART_FROM_CAPABILITY_QUESTION_ANSWER API", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
questions: [],
parts: [
{
childPartQuestions: [],
},
],
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(spy).toHaveBeenNthCalledWith(
2,
"getPartFromCapabilityQuestionAnswer",
"Windshield",
false
);
wrapper.unmount();
});
test("Should trigger navigateForward", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
questions: [],
parts: [
{
childPartQuestions: [],
},
],
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
wrapper.vm.navigateForward = jest.fn();
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
wrapper.unmount();
});
});
});
function setupMocks({
mountOptionsMockData = {
router: {
navigate: jest.fn(),
navigateWithSaving: jest.fn(),
navigateWithoutSaving: jest.fn(),
},
store: {
getters: store.getters,
commit: store.commit,
},
route: {
query: {
fmgPage: "capability-questions",
},
},
},
}) {
const mountOptions = getMountOptions({
...mountOptionsMockData,
mixins: [baseMixin, vehicleQuestionsMixin],
});
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(capabilityQuestions, mountOptions);
return { wrapper };
}

View file

@ -106,7 +106,10 @@ export default {
fmgPageValues.CAPABILITY_QUESTIONS
);
return (
capabilityQuestionsPageData && Object.keys(capabilityQuestionsPageData).length > 0
capabilityQuestionsPageData &&
capabilityQuestionsPageData.partsOrQuestions.some(
(el) => el.capabilityQuestions.length > 0
)
);
},
async forwardButtonAction() {

View file

@ -0,0 +1,351 @@
// Components
import moldingQuestions from "@/layouts/molding-questions/molding-questions";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
import baseMixin from "../../mixins/base-mixin";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { nextTick } from "vue";
// 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(),
}));
jest.mock(
"@/store",
() => {
return {};
},
{ virtual: true }
);
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateToHeritageFunnel: jest.fn(),
}));
const baseStoreGettersPageData = () => {
return {
partsOrQuestions: [
{
parts: [
{
childPartQuestions: [
{
questionSequence: 1,
questionText:
"Does the rubber seal around your windshield have a chrome strip running through it?",
answers: [
{
answerResult: "WKT D1106 C",
answerText: "Yes",
nextQuestionSequence: null,
},
{
answerResult: "WKT D1106 B",
answerText: "No",
nextQuestionSequence: null,
},
],
},
],
basePartNumber: "DW01105",
color: "Green Tint, Blue Shade",
requiresRecalibration: false,
recalibrationType: "",
canSafeliteRecalibrate: false,
requiresCapabilityQuestions: false,
childParts: null,
partNumber: "DW01105GBNN",
description: "solar",
partType: "WINDSHIELD",
},
],
partQuestions: [],
glassLocation: "Windshield",
glassName: "Single",
answerKey: "Windshield-Single",
answerData: null,
},
],
};
};
const baseStoreGettersDamage = () => {
return {
partsQuestionAnswers: [
{
glassLocation: "Windshield",
glassName: "Single",
result: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
},
],
};
};
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
};
store.commit = jest.fn();
afterEach(() => {
// reset store after each test
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
};
});
describe("moldingQuestions.vue", () => {
describe("method arePagePrerequisitesValid...", () => {
test("Should return true for valid page requisites if pageData exists", () => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBe(true);
wrapper.unmount();
});
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
// Arrange
const { wrapper } = setupMocks({});
store.getters.pageData = jest.fn(() => {
return undefined;
});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
test("Should be at least one item in partsOrQuestions", () => {
// Arrange
store.getters = {
pageData: jest.fn(() => {
return {
partsOrQuestions: [],
};
}),
damage: baseStoreGettersDamage,
};
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
});
describe("watch on selectedAnswers should be set up...", () => {
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
// Arrange
const { wrapper } = setupMocks({});
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
// Act
wrapper.setData({
selectedAnswers: {
"Windshield-Single": {
answerResult: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
index: 0,
},
},
});
await nextTick();
//Assert
expect(spy).toHaveBeenCalled();
wrapper.unmount();
});
});
describe("forwardButtonAction", () => {
test("Should clear out answerData", () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
wrapper.unmount();
});
test("Should save to Vuex store", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(spy).toHaveBeenNthCalledWith(
1,
"saveMoldingQuestionAnswers",
[
{
answeredQuestions: [],
glassLocation: "Windshield",
glassName: "Single",
isSuppressedPart: undefined,
partNum: "FW04848",
},
],
false
);
wrapper.unmount();
});
test("Should trigger navigateForward", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
wrapper.vm.navigateForward = jest.fn();
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
wrapper.unmount();
});
});
});
function setupMocks({
mountOptionsMockData = {
router: {
navigate: jest.fn(),
navigateWithSaving: jest.fn(),
navigateWithoutSaving: jest.fn(),
},
store: {
getters: store.getters,
commit: store.commit,
},
route: {
query: {
fmgPage: "molding-questions",
},
},
},
}) {
const mountOptions = getMountOptions({
...mountOptionsMockData,
mixins: [baseMixin, vehicleQuestionsMixin],
});
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(moldingQuestions, mountOptions);
return { wrapper };
}

View file

@ -104,8 +104,12 @@ export default {
const moldingQuestionsFromPageData = store.getters.pageData(
fmgPageValues.MOLDING_QUESTIONS
);
return (
moldingQuestionsFromPageData && Object.keys(moldingQuestionsFromPageData).length > 0
moldingQuestionsFromPageData &&
moldingQuestionsFromPageData.partsOrQuestions.some((glass) =>
glass.parts?.some((part) => part?.childPartQuestions.length > 0)
)
);
},
async forwardButtonAction() {

View file

@ -0,0 +1,385 @@
// Components
import partQuestions from "@/layouts/part-questions/part-questions";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import store from "@/store";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "../../mixins/base-mixin";
import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { nextTick } from "vue";
// 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(),
}));
jest.mock(
"@/store",
() => {
return {};
},
{ virtual: true }
);
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
navigateToHeritageFunnel: jest.fn(),
}));
const baseStoreGettersPageData = () => {
return {
partsOrQuestions: [
{
parts: null,
partQuestions: [
{
questionSequence: 1,
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
answers: [
{
answerResult: "",
answerText: "Yes",
nextQuestionSequence: 2,
},
{
answerResult: "",
answerText: "No",
nextQuestionSequence: 3,
},
],
},
],
glassLocation: "Windshield",
glassName: "Single",
answerKey: "Windshield-Single",
answerData: null,
},
],
};
};
const baseStoreGettersDamage = () => {
return {
partsQuestionAnswers: [
{
glassLocation: "Windshield",
glassName: "Single",
result: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
},
],
};
};
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
};
store.commit = jest.fn();
afterEach(() => {
// reset store after each test
store.getters = {
pageData: baseStoreGettersPageData,
damage: baseStoreGettersDamage,
};
});
describe("partQuestions.vue...", () => {
describe("method arePagePrerequisitesValid...", () => {
test("Should return true for valid page requisites if pageData exists", () => {
// Arrange
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBe(true);
wrapper.unmount();
});
test("Should return false for valid page requisites if partsOrQuestions in pageData is missing", () => {
// Arrange
const { wrapper } = setupMocks({});
store.getters.pageData = jest.fn(() => {
return undefined;
});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
test("Should be at least one item in partsOrQuestions", () => {
// Arrange
store.getters = {
pageData: jest.fn(() => {
return {
partsOrQuestions: [],
};
}),
damage: baseStoreGettersDamage,
};
const { wrapper } = setupMocks({});
// Act
const result = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(result).toBeFalsy();
wrapper.unmount();
});
});
describe("watch on selectedAnswers should be set up...", () => {
test("Should trigger handleAnswerUpdates if watched data changes", async () => {
// Arrange
const { wrapper } = setupMocks({});
const spy = jest.spyOn(wrapper.vm, "handleAnswerUpdates");
// Act
wrapper.setData({
selectedAnswers: {
"Windshield-Single": {
answerResult: "FW04848",
answeredQuestions: [
{
questionText:
"Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?",
selectedAnswerText: "Yes",
questionNum: 1,
},
{
questionText:
"Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?",
selectedAnswerText: "Yes",
questionNum: 2,
},
],
index: 0,
},
},
});
await nextTick();
//Assert
expect(spy).toHaveBeenCalled();
wrapper.unmount();
});
});
describe("forwardButtonAction", () => {
test("Should clear out answerData", () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
// Act
wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.questionsData[0].answerData).toEqual({});
wrapper.unmount();
});
test("Should save to Vuex store", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(spy).toHaveBeenNthCalledWith(
1,
"savePartQuestionAnswers",
[
{
answeredQuestions: [],
glassLocation: "Windshield",
glassName: "Single",
isSuppressedPart: undefined,
result: "FW04848",
},
],
false
);
wrapper.unmount();
});
test("Should call GET_PARTS API", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
// Act
wrapper.vm.forwardButtonAction();
await nextTick();
//Assert
expect(spy).toHaveBeenNthCalledWith(2, "getParts");
wrapper.unmount();
});
test("Should trigger navigateForward", async () => {
// Arrange
const { wrapper } = setupMocks({});
wrapper.vm.questionsData = [
{
glassLocation: "Windshield",
glassName: "Single",
answerData: {
answerResult: "FW04848",
answeredQuestions: [],
},
},
];
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: {
glassPieceParts: [],
},
};
});
wrapper.vm.navigateForward = jest.fn();
// Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(wrapper.vm.navigateForward).toHaveBeenCalled();
wrapper.unmount();
});
});
});
function setupMocks({
mountOptionsMockData = {
router: {
navigate: jest.fn(),
navigateWithSaving: jest.fn(),
navigateWithoutSaving: jest.fn(),
},
actionList: [
{
actionName: storeActions.SAVE_PART_QUESTION_ANSWERS,
data: {},
},
{
actionName: storeActions.GET_PARTS,
data: {},
},
],
store: {
getters: store.getters,
commit: store.commit,
},
route: {
query: {
fmgPage: "part-questions",
},
},
},
}) {
const mountOptions = getMountOptions({
...mountOptionsMockData,
mixins: [baseMixin, vehicleQuestionsMixin],
});
mountOptions["attachTo"] = document.body;
const wrapper = shallowMount(partQuestions, mountOptions);
return { wrapper };
}

View file

@ -103,22 +103,27 @@ export default {
methods: {
arePagePrerequisitesValid() {
const partQuestionsFromPageData = store.getters.pageData(fmgPageValues.PART_QUESTIONS);
return partQuestionsFromPageData && Object.keys(partQuestionsFromPageData).length > 0;
return (
partQuestionsFromPageData &&
Object.keys(partQuestionsFromPageData.partsOrQuestions).length > 0
);
},
async forwardButtonAction() {
const questionAnswersArray = this.questionsData.map((glass) => {
return {
glassLocation: glass.glassLocation,
glassName: glass.glassName,
result: glass.answerData.answerResult,
answeredQuestions: glass.answerData.answeredQuestions,
result: (glass.answerData && glass.answerData.answerResult) || "",
answeredQuestions: glass.answerData?.answeredQuestions,
isSuppressedPart: glass.isSuppressedPart,
};
});
// clear out answerData for future page loads; must occur prior to store save
this.questionsData.forEach((glass) => {
glass.answerData = {};
if (glass.answerData) {
glass.answerData = {};
}
});
// save to vuex store as order.damage.partQuestionAnswers (array)