fix: correct isMobileStaticRecalibrationApplicable in schedule.vue to gate on MSR part conditions
The schedule.vue isMobileStaticRecalibrationApplicable computed property had
broken operator precedence, making isCashItacNoComp and mobileFeePart?.isInsurable
standalone OR branches instead of being gated behind displayMSR and the
MOBILE_STATIC_RECAL_FEE part check.
This meant any self-pay (cash/ITAC/NoComp) order always evaluated
isMobileStaticRecalibrationApplicable as true, regardless of whether the
DISPLAY_MSR experiment was enabled or whether the order even had a
MOBILE_STATIC_RECAL_FEE part. In turn, isServiceableMobile returned true
even when isRecalibrationServiceableMobile === false (recalibration cannot
be done mobile), causing GET_MOBILE_TIME_SLOTS to be fetched for orders
where mobile service should not be offered.
Fix aligns the logic with service-location.vue:
- require displayMSR AND mobileFeePart.partNumber === MOBILE_STATIC_RECAL_FEE
AND (isCashItacNoComp OR mobileFeePart.isInsurable)
Also removes the now-unused enableMSRSplitPay computed property.
Adds unit tests covering isMobileStaticRecalibrationApplicable and
isServiceableMobile for the recal-cannot-be-done-mobile scenario.
Co-authored-by: Mark Harris <mark.harris@safelite.com>
This commit is contained in:
parent
292b626267
commit
6f09cd3e78
2 changed files with 158 additions and 12 deletions
|
|
@ -7,6 +7,22 @@ import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
|||
import { routeData } from "@/router/constants/routes";
|
||||
import store from "@/store";
|
||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
import { partNumberStrings } from "@/constants/part-number-strings";
|
||||
|
||||
let mockDisplayMSR = false;
|
||||
jest.mock("@/mixins/experiment-mixin.js", () => ({
|
||||
methods: {
|
||||
getSettingValue(settingName) {
|
||||
// "DisplayMSR" is experimentSettings.DISPLAY_MSR
|
||||
if (settingName === "DisplayMSR") {
|
||||
return mockDisplayMSR ? "true" : "false";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
hasSettingEqualTo: jest.fn(),
|
||||
hasSetting: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const storeMocked = {
|
||||
getters: {
|
||||
|
|
@ -231,6 +247,145 @@ describe("schedule.vue", () => {
|
|||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("computed: isMobileStaticRecalibrationApplicable", () => {
|
||||
beforeEach(() => {
|
||||
mockDisplayMSR = false;
|
||||
});
|
||||
|
||||
test("returns false when displayMSR experiment is off, even for cash orders", async () => {
|
||||
mockDisplayMSR = false;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
mobileFeePart: { partNumber: partNumberStrings.MOBILE_STATIC_RECAL_FEE, isInsurable: false },
|
||||
});
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isMobileStaticRecalibrationApplicable).toBe(false);
|
||||
});
|
||||
|
||||
test("returns false when mobileFeePart is null, even for cash orders with DISPLAY_MSR on", async () => {
|
||||
mockDisplayMSR = true;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({ mobileFeePart: null });
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isMobileStaticRecalibrationApplicable).toBe(false);
|
||||
});
|
||||
|
||||
test("returns false when mobileFeePart is not MOBILE_STATIC_RECAL_FEE, even for cash orders", async () => {
|
||||
mockDisplayMSR = true;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
mobileFeePart: { partNumber: "SOME_OTHER_PART", isInsurable: false },
|
||||
});
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isMobileStaticRecalibrationApplicable).toBe(false);
|
||||
});
|
||||
|
||||
test("returns true when DISPLAY_MSR is on, part is MOBILE_STATIC_RECAL_FEE, and order is cash", async () => {
|
||||
mockDisplayMSR = true;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
mobileFeePart: { partNumber: partNumberStrings.MOBILE_STATIC_RECAL_FEE, isInsurable: false },
|
||||
});
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isMobileStaticRecalibrationApplicable).toBe(true);
|
||||
});
|
||||
|
||||
test("returns true when DISPLAY_MSR is on, part is MOBILE_STATIC_RECAL_FEE, and part is insurable (insurance order)", async () => {
|
||||
mockDisplayMSR = true;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
mobileFeePart: { partNumber: partNumberStrings.MOBILE_STATIC_RECAL_FEE, isInsurable: true },
|
||||
});
|
||||
store.getters.order.payment.isInsurance = true;
|
||||
|
||||
expect(wrapper.vm.isMobileStaticRecalibrationApplicable).toBe(true);
|
||||
});
|
||||
|
||||
test("returns false when DISPLAY_MSR is on, part is MOBILE_STATIC_RECAL_FEE, insurance order, and part is NOT insurable", async () => {
|
||||
mockDisplayMSR = true;
|
||||
store.getters.payment.isInsurance = true;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
mobileFeePart: { partNumber: partNumberStrings.MOBILE_STATIC_RECAL_FEE, isInsurable: false },
|
||||
});
|
||||
|
||||
expect(wrapper.vm.isMobileStaticRecalibrationApplicable).toBe(false);
|
||||
|
||||
store.getters.payment.isInsurance = false;
|
||||
});
|
||||
});
|
||||
|
||||
describe("computed: isServiceableMobile — recalibration cannot be done mobile", () => {
|
||||
beforeEach(() => {
|
||||
mockDisplayMSR = false;
|
||||
});
|
||||
|
||||
test("returns false when recal is NOT mobile serviceable and MSR is not applicable (cash order, no MSR part)", async () => {
|
||||
const { wrapper } = setupMocks();
|
||||
// Cash order, no MSR feature, no MOBILE_STATIC_RECAL_FEE part
|
||||
await wrapper.setData({
|
||||
isGlassServiceableMobile: true,
|
||||
isRecalibrationServiceableMobile: false,
|
||||
mobileFeePart: null,
|
||||
});
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isServiceableMobile).toBe(false);
|
||||
});
|
||||
|
||||
test("returns false when recal is NOT mobile serviceable and MSR experiment is off (cash order)", async () => {
|
||||
mockDisplayMSR = false;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
isGlassServiceableMobile: true,
|
||||
isRecalibrationServiceableMobile: false,
|
||||
mobileFeePart: { partNumber: partNumberStrings.MOBILE_STATIC_RECAL_FEE, isInsurable: false },
|
||||
});
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isServiceableMobile).toBe(false);
|
||||
});
|
||||
|
||||
test("returns true when both glass and recal ARE mobile serviceable", async () => {
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
isGlassServiceableMobile: true,
|
||||
isRecalibrationServiceableMobile: true,
|
||||
mobileFeePart: null,
|
||||
});
|
||||
|
||||
expect(wrapper.vm.isServiceableMobile).toBe(true);
|
||||
});
|
||||
|
||||
test("returns true when recal is NOT mobile serviceable but MSR is applicable (DISPLAY_MSR on, MSR part, cash)", async () => {
|
||||
mockDisplayMSR = true;
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
isGlassServiceableMobile: true,
|
||||
isRecalibrationServiceableMobile: false,
|
||||
mobileFeePart: { partNumber: partNumberStrings.MOBILE_STATIC_RECAL_FEE, isInsurable: false },
|
||||
});
|
||||
store.getters.order.payment.isInsurance = false;
|
||||
|
||||
expect(wrapper.vm.isServiceableMobile).toBe(true);
|
||||
});
|
||||
|
||||
test("falls back to isGlassServiceableMobile when isRecalibrationServiceableMobile is null", async () => {
|
||||
const { wrapper } = setupMocks();
|
||||
await wrapper.setData({
|
||||
isGlassServiceableMobile: true,
|
||||
isRecalibrationServiceableMobile: null,
|
||||
mobileFeePart: null,
|
||||
});
|
||||
|
||||
expect(wrapper.vm.isServiceableMobile).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupMocksForArePagePrerequisitesValid() {
|
||||
|
|
|
|||
|
|
@ -705,11 +705,9 @@ export default {
|
|||
},
|
||||
isMobileStaticRecalibrationApplicable() {
|
||||
return (
|
||||
(this.displayMSR &&
|
||||
this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE &&
|
||||
this.enableMSRSplitPay) ||
|
||||
this.isCashItacNoComp ||
|
||||
this.mobileFeePart?.isInsurable
|
||||
this.displayMSR &&
|
||||
this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE &&
|
||||
(this.isCashItacNoComp || this.mobileFeePart?.isInsurable)
|
||||
);
|
||||
},
|
||||
displayMSR() {
|
||||
|
|
@ -719,13 +717,6 @@ export default {
|
|||
?.toLowerCase() === "true"
|
||||
);
|
||||
},
|
||||
enableMSRSplitPay() {
|
||||
return (
|
||||
experimentMixin.methods
|
||||
.getSettingValue(experimentSettings.ENABLE_MSR_SPLIT_PAY)
|
||||
?.toLowerCase() === "true"
|
||||
);
|
||||
},
|
||||
isMSRFeeNotCoveredByInsurance() {
|
||||
return (
|
||||
this.isMobileSelected &&
|
||||
|
|
|
|||
Loading…
Reference in a new issue