From cd2be9c384fc55d2fdf13b60c1a91e65522745d3 Mon Sep 17 00:00:00 2001 From: scottkiener-at-safelite Date: Wed, 15 Jul 2026 08:21:39 -0400 Subject: [PATCH] CASH-2815 | Waitlist working Pre personal tech review --- src/layouts/scheduling/scheduling.spec.js | 3 + src/layouts/scheduling/scheduling.vue | 7 + .../waitlist-question.spec.js | 146 ++++++++++++++++++ .../waitlist-question/waitlist-question.vue | 136 ++++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 src/layouts/scheduling/waitlist-question/waitlist-question.spec.js create mode 100644 src/layouts/scheduling/waitlist-question/waitlist-question.vue diff --git a/src/layouts/scheduling/scheduling.spec.js b/src/layouts/scheduling/scheduling.spec.js index d64ffa779..c76a0985f 100644 --- a/src/layouts/scheduling/scheduling.spec.js +++ b/src/layouts/scheduling/scheduling.spec.js @@ -15,6 +15,9 @@ jest.mock("@/store", () => ({ lineItems: { glassParts: [] }, policy: { isItac: false, isNoComp: false }, }, + applicationUser: { + experiments: [], + }, }, })); diff --git a/src/layouts/scheduling/scheduling.vue b/src/layouts/scheduling/scheduling.vue index 3ace9edf7..2b2a8e803 100644 --- a/src/layouts/scheduling/scheduling.vue +++ b/src/layouts/scheduling/scheduling.vue @@ -48,6 +48,10 @@ @address-clicked="onInshopAddressClicked(provider)" /> + diff --git a/src/layouts/scheduling/waitlist-question/waitlist-question.spec.js b/src/layouts/scheduling/waitlist-question/waitlist-question.spec.js new file mode 100644 index 000000000..e3bcc3e07 --- /dev/null +++ b/src/layouts/scheduling/waitlist-question/waitlist-question.spec.js @@ -0,0 +1,146 @@ +import { mount } from "@vue/test-utils"; +import waitlistQuestion from "./waitlist-question"; +import store from "@/store"; +import { experimentSettings } from "@/constants/experiments"; + +jest.mock("@/store", () => ({ + getters: { + applicationUser: { + experiments: [], + }, + }, +})); + +const MOCK_CMS_CONTENT = { + WaitListLabelWidget: { Text: "Want to be notified sooner?" }, + WaitListQuestionWidget: { QuestionText: "Add me to the waitlist" }, +}; + +function dateStringOffsetFromToday(offsetDays) { + const d = new Date(); + d.setDate(d.getDate() + offsetDays); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String( + d.getDate() + ).padStart(2, "0")}`; +} + +function enableWaitlistExperiment(thresholdDays = 0) { + store.getters.applicationUser.experiments = [ + { + isActive: true, + settings: { + [experimentSettings.DISPLAY_WAITLIST]: "true", + [experimentSettings.WAITLIST_THRESHOLD_DAYS]: String(thresholdDays), + }, + }, + ]; +} + +function mountComponent(props = {}) { + const cmsMixin = { + methods: { + getCmsContent: jest.fn((widgetName, fieldName) => { + return MOCK_CMS_CONTENT[widgetName]?.[fieldName] ?? ""; + }), + }, + }; + + return mount(waitlistQuestion, { + props: { + modelValue: false, + availableDates: [dateStringOffsetFromToday(10)], + ...props, + }, + global: { + mixins: [cmsMixin], + }, + }); +} + +describe("waitlist-question.vue", () => { + beforeEach(() => { + enableWaitlistExperiment(); + }); + + afterEach(() => { + store.getters.applicationUser.experiments = []; + }); + + it("renders the label and checkbox CMS content", () => { + const wrapper = mountComponent(); + + expect(wrapper.text()).toContain("Want to be notified sooner?"); + expect(wrapper.text()).toContain("Add me to the waitlist"); + }); + + it("reflects the modelValue prop on the checkbox", () => { + const wrapper = mountComponent({ modelValue: true }); + + expect(wrapper.find("input[type='checkbox']").element.checked).toBe(true); + }); + + it("emits update:modelValue with true when the checkbox is checked", async () => { + const wrapper = mountComponent({ modelValue: false }); + + const input = wrapper.find("input[type='checkbox']"); + await input.setValue(true); + + expect(wrapper.emitted("update:modelValue")).toEqual([[true]]); + }); + + it("emits update:modelValue with false when the checkbox is unchecked", async () => { + const wrapper = mountComponent({ modelValue: true }); + + const input = wrapper.find("input[type='checkbox']"); + await input.setValue(false); + + expect(wrapper.emitted("update:modelValue")).toEqual([[false]]); + }); + + it("renders nothing when shouldDisplay is false", () => { + store.getters.applicationUser.experiments = []; + + const wrapper = mountComponent(); + + expect(wrapper.find("input[type='checkbox']").exists()).toBe(false); + }); + + describe("shouldDisplay", () => { + it("is false when the DISPLAY_WAITLIST experiment is off", () => { + store.getters.applicationUser.experiments = [ + { + isActive: true, + settings: { [experimentSettings.WAITLIST_THRESHOLD_DAYS]: "3" }, + }, + ]; + + const wrapper = mountComponent({ availableDates: [dateStringOffsetFromToday(10)] }); + + expect(wrapper.vm.shouldDisplay).toBe(false); + }); + + it("is false when the earliest available date is within the threshold", () => { + enableWaitlistExperiment(3); + + const wrapper = mountComponent({ availableDates: [dateStringOffsetFromToday(2)] }); + + expect(wrapper.vm.shouldDisplay).toBe(false); + }); + + it("is true when the experiment is on and the earliest available date exceeds the threshold", () => { + enableWaitlistExperiment(3); + + const wrapper = mountComponent({ availableDates: [dateStringOffsetFromToday(10)] }); + + expect(wrapper.vm.shouldDisplay).toBe(true); + }); + + it("is false when there are no available dates", () => { + enableWaitlistExperiment(0); + + const wrapper = mountComponent({ availableDates: [] }); + + expect(wrapper.vm.shouldDisplay).toBe(false); + }); + }); +}); diff --git a/src/layouts/scheduling/waitlist-question/waitlist-question.vue b/src/layouts/scheduling/waitlist-question/waitlist-question.vue new file mode 100644 index 000000000..aba80f23b --- /dev/null +++ b/src/layouts/scheduling/waitlist-question/waitlist-question.vue @@ -0,0 +1,136 @@ + + + + +