From 84d31fa55ccb0eed3aa37303ed1484a9e43b0990 Mon Sep 17 00:00:00 2001 From: Matt Sykes Date: Thu, 25 Jun 2026 12:47:02 -0400 Subject: [PATCH] Fix textbox-question render failures on mobile-details and schedule Harden the shared textbox-question component and its mobile flow parents to prevent runtime-1 "undefined is not a function" errors seen in CloudWatch (chunk 5615 / textbox-question.vue). - Coerce modelValue to a string in textbox-question setup and value getter - Ensure v-maska always receives a string mask - Guard the value watcher when handleChange is unavailable - Fix mobile-details v-model bindings (remove invalid this. prefix) - Coerce address fields from store to strings before binding - Correct malformed modelValue prop definitions on vehicle-protected-question and service-zip-question - Add unit test for null modelValue coercion --- .../textbox-question/textbox-question.spec.js | 16 ++++++++ .../textbox-question/textbox-question.vue | 40 ++++++++++++------- src/layouts/mobile-details/mobile-details.vue | 14 +++---- .../vehicle-protected-question.vue | 3 +- .../service-zip-question.vue | 3 +- 5 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/digital-components/textbox-question/textbox-question.spec.js b/src/digital-components/textbox-question/textbox-question.spec.js index be33230c2..d83eb6509 100644 --- a/src/digital-components/textbox-question/textbox-question.spec.js +++ b/src/digital-components/textbox-question/textbox-question.spec.js @@ -13,6 +13,22 @@ const mockMixin = { const maska = jest.fn(); describe("textboxQuestion.vue", () => { + it("Should coerce non-string modelValue to empty string for v-model.trim", async () => { + const wrapper = shallowMount(textboxQuestion, { + global: { + directives: { + maska: maska, + }, + }, + propsData: { + modelValue: null, + }, + mixins: [mockMixin], + }); + + expect(wrapper.vm.value).toBe(""); + }); + it("Should render a text input", async () => { // Arrange const wrapper = shallowMount(textboxQuestion, { diff --git a/src/digital-components/textbox-question/textbox-question.vue b/src/digital-components/textbox-question/textbox-question.vue index 9e0810513..fd8f850ef 100644 --- a/src/digital-components/textbox-question/textbox-question.vue +++ b/src/digital-components/textbox-question/textbox-question.vue @@ -25,7 +25,7 @@ 0 ? modelValue : ""; - break; - } + const modelValue = coerceTextboxValue(propsClone.modelValue); + const initialValue = modelValue; const fieldOptions = { type: "text", @@ -164,6 +167,8 @@ export default { initialValue: initialValue, }; + let isImageProcessing = ref(false); + const { errorMessage, handleBlur, handleChange, meta, validate, errors } = useField( inputId, props.validationRules, @@ -223,18 +228,25 @@ export default { }, value: { get: function () { - return this.modelValue; + return coerceTextboxValue(this.modelValue); }, set: function (newValue) { this.$emit("update:modelValue", newValue); }, }, + effectiveMask() { + return this.mask ?? ""; + }, }, mounted() { this.$emit("textboxQuestionEvent.inputIdAssigned", this.inputId); }, watch: { async value(newValue) { + if (typeof this.handleChange !== "function") { + return; + } + const result = await validate(newValue, this.validationRules); // do a test validation check, without triggering full validation if (result.valid) { this.handleChange(newValue); // trigger full validation on this field only diff --git a/src/layouts/mobile-details/mobile-details.vue b/src/layouts/mobile-details/mobile-details.vue index cb98386e6..1dcd75a36 100644 --- a/src/layouts/mobile-details/mobile-details.vue +++ b/src/layouts/mobile-details/mobile-details.vue @@ -34,7 +34,7 @@ class="keys-message" />