From 61e1a973b3df48f8c69a30969df1f08a2cf3f343 Mon Sep 17 00:00:00 2001 From: alice-sevin <59559689+alice-sevin@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:22:41 +0100 Subject: [PATCH] fix(date-inputs): use correct variables delimiters for default variables [TCTC-8076] (#2037) * fix(dates): use correct delimiters for variables in date input * chore: update changelog * chore: fix lint * fix: cover uncovered new code --- ui/CHANGELOG.md | 3 + .../widgets/DateComponents/DateRangeInput.vue | 21 ++++- .../widgets/DateComponents/NewDateInput.vue | 22 +++++- ui/tests/unit/date-range-input.spec.ts | 76 ++++++++++++++----- ui/tests/unit/new-date-input.spec.ts | 58 +++++++++++--- 5 files changed, 146 insertions(+), 34 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index fba7e5165a..07fb118982 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +### Fixed +- DateForms: use correct delimiters for default date variables + ## [0.111.2] - 2024-01-10 ### Fixed diff --git a/ui/src/components/stepforms/widgets/DateComponents/DateRangeInput.vue b/ui/src/components/stepforms/widgets/DateComponents/DateRangeInput.vue index 128e747636..624b5569ae 100644 --- a/ui/src/components/stepforms/widgets/DateComponents/DateRangeInput.vue +++ b/ui/src/components/stepforms/widgets/DateComponents/DateRangeInput.vue @@ -127,6 +127,7 @@ import t, { LocaleIdentifier } from '@/lib/internationalization'; import { AvailableVariable, extractVariableIdentifier, + isTrustedVariable, VariableDelimiters, VariablesBucket, } from '@/lib/variables'; @@ -374,8 +375,26 @@ export default class DateRangeInput extends Vue { this.isEditorOpened = false; } + setVariableDelimiters(value: string): string { + const retrieveVariableDelimiters = ( + variableIdentifier: string, + ): VariableDelimiters | undefined => { + const variable = this.availableVariables.find((v) => v.identifier === variableIdentifier); + if (!variable) { + return; // if variable is unfound we don't want to display any delimiters + } else if (isTrustedVariable(variable)) { + return this.trustedVariableDelimiters; + } + return this.variableDelimiters; + }; + + const delimiters = retrieveVariableDelimiters(value); + if (!delimiters) return value; + return `${delimiters.start}${value}${delimiters.end}`; + } + selectVariable(value: string): void { - const variableWithDelimiters = `${this.variableDelimiters.start}${value}${this.variableDelimiters.end}`; + const variableWithDelimiters = this.setVariableDelimiters(value); this.$emit('input', variableWithDelimiters); this.closeEditor(); } diff --git a/ui/src/components/stepforms/widgets/DateComponents/NewDateInput.vue b/ui/src/components/stepforms/widgets/DateComponents/NewDateInput.vue index 06577fa932..3eb555ee00 100644 --- a/ui/src/components/stepforms/widgets/DateComponents/NewDateInput.vue +++ b/ui/src/components/stepforms/widgets/DateComponents/NewDateInput.vue @@ -122,7 +122,7 @@ import Tabs from '@/components/Tabs.vue'; import { dateToString, isRelativeDate, relativeDateToString } from '@/lib/dates'; import type { CustomDate, DateRange } from '@/lib/dates'; import { sendAnalytics } from '@/lib/send-analytics'; -import { extractVariableIdentifier } from '@/lib/variables'; +import { extractVariableIdentifier, isTrustedVariable } from '@/lib/variables'; import type { AvailableVariable, VariableDelimiters, VariablesBucket } from '@/lib/variables'; import CustomVariableList from './CustomVariableList.vue'; @@ -283,8 +283,26 @@ export default class NewDateInput extends Vue { this.isEditingCustomVariable = false; } + setVariableDelimiters(value: string): string { + const retrieveVariableDelimiters = ( + variableIdentifier: string, + ): VariableDelimiters | undefined => { + const variable = this.availableVariables.find((v) => v.identifier === variableIdentifier); + if (!variable) { + return; // if variable is unfound we don't want to display any delimiters + } else if (isTrustedVariable(variable)) { + return this.trustedVariableDelimiters; + } + return this.variableDelimiters; + }; + + const delimiters = retrieveVariableDelimiters(value); + if (!delimiters) return value; + return `${delimiters.start}${value}${delimiters.end}`; + } + selectVariable(value: string): void { - const variableWithDelimiters = `${this.variableDelimiters.start}${value}${this.variableDelimiters.end}`; + const variableWithDelimiters = this.setVariableDelimiters(value); this.$emit('input', variableWithDelimiters); this.closeEditor(); sendAnalytics({ name: 'Date input - Select variable', value }); diff --git a/ui/tests/unit/date-range-input.spec.ts b/ui/tests/unit/date-range-input.spec.ts index 334c08746c..d2edf6caf6 100644 --- a/ui/tests/unit/date-range-input.spec.ts +++ b/ui/tests/unit/date-range-input.spec.ts @@ -16,31 +16,37 @@ const SAMPLE_VARIABLES = [ identifier: 'dates.last_7_days', label: 'Last 7 days', value: '', + trusted: true, }, { identifier: 'dates.last_14_days', label: 'Last 14 days', value: { start: new Date(2020, 11), end: new Date(2020, 11) }, + trusted: true, }, { identifier: 'dates.last_30_days', label: 'Last 30 days', value: '', + trusted: true, }, { identifier: 'dates.last_3_months', label: 'Last 3 Months', value: '', + trusted: true, }, { identifier: 'dates.last_12_months', label: 'Last 12 Months', value: '', + trusted: true, }, { identifier: 'dates.month_to_date', label: 'Month to date', value: '', + trusted: true, }, { identifier: 'dates.quarter_to_date', @@ -51,6 +57,7 @@ const SAMPLE_VARIABLES = [ identifier: 'dates.all_time', label: 'All time', value: '', + trusted: true, }, ]; @@ -59,16 +66,19 @@ const RELATIVE_SAMPLE_VARIABLES = [ label: 'Today', identifier: 'today', value: new Date(2020, 11), + trusted: true, }, { label: 'Last month', identifier: 'last_month', value: '', + trusted: true, }, { label: 'Last year', identifier: 'last_year', value: '', + trusted: true, }, ]; @@ -90,7 +100,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: 'anythingnotokay', }); }); @@ -159,16 +170,26 @@ describe('Date range input', () => { }); }); - describe('when selecting a variable in CustomVariableList', () => { - const selectedVariable = SAMPLE_VARIABLES[1].identifier; - beforeEach(async () => { - wrapper.find('CustomVariableList-stub').vm.$emit('input', selectedVariable); + describe('when choosing a variable', () => { + it('should emit the new value with correct delimiters (trusted variable)', async () => { + wrapper.find('CustomVariableList-stub').vm.$emit('input', 'dates.last_7_days'); await wrapper.vm.$nextTick(); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('input')[0]).toEqual(['{{dates.last_7_days}}']); + expect(wrapper.find('popover-stub').props().visible).toBe(false); }); - it('should emit the selected variable identifier with delimiters', () => { - expect(wrapper.emitted().input[0][0]).toBe(`{{${selectedVariable}}}`); + it('should emit the new value with correct delimiters (untrusted variable)', async () => { + wrapper.find('CustomVariableList-stub').vm.$emit('input', 'dates.quarter_to_date'); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('input')[0]).toEqual(['<%=dates.quarter_to_date%>']); + expect(wrapper.find('popover-stub').props().visible).toBe(false); }); - it('should hide editor', () => { + it('should emit the correct value (undefined variable)', async () => { + wrapper.find('CustomVariableList-stub').vm.$emit('input', 'noop'); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('input')[0]).toEqual(['noop']); expect(wrapper.find('popover-stub').props().visible).toBe(false); }); }); @@ -202,7 +223,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, }); }); @@ -285,7 +307,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: initialValue, }); await wrapper.setProps({ @@ -351,7 +374,8 @@ describe('Date range input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: `{{${selectedVariable.identifier}}}`, }); }); @@ -372,7 +396,8 @@ describe('Date range input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value, }); }); @@ -420,7 +445,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value, }); }); @@ -449,7 +475,8 @@ describe('Date range input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, enableRelativeDate: false, }); }); @@ -468,7 +495,8 @@ describe('Date range input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, enableCustom: false, }); }); @@ -484,7 +512,8 @@ describe('Date range input', () => { beforeEach(async () => { createWrapper({ availableVariables: [{ label: 'Hidden', identifier: 'hidden', category: 'hidden' }], - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, }); wrapper.find('.widget-date-input__container').trigger('click'); await wrapper.vm.$nextTick(); @@ -505,7 +534,8 @@ describe('Date range input', () => { { label: 'Available', identifier: 'available' }, ], bounds: '{{hidden}}', // hidden variables can be used as variable reference for bounds or presets - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, }); wrapper.find('.widget-date-input__container').trigger('click'); await wrapper.vm.$nextTick(); @@ -528,7 +558,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: { start: new Date('2020/2/1'), end: new Date('2020/3/1') }, bounds, }); @@ -573,7 +604,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, compactMode: true, }); }); @@ -602,7 +634,8 @@ describe('Date range input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: { start: new Date(), end: new Date(1) }, compactMode: true, }); @@ -624,7 +657,8 @@ describe('Date range input', () => { createWrapper({ availableVariables: SAMPLE_VARIABLES, relativeAvailableVariables: RELATIVE_SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, hidePlaceholder: true, }); }); diff --git a/ui/tests/unit/new-date-input.spec.ts b/ui/tests/unit/new-date-input.spec.ts index ba33a9988d..f4722a7c34 100644 --- a/ui/tests/unit/new-date-input.spec.ts +++ b/ui/tests/unit/new-date-input.spec.ts @@ -16,6 +16,7 @@ const RELATIVE_SAMPLE_VARIABLES = [ label: 'Today', identifier: 'today', value: new Date(2020, 11), + trusted: true, }, ]; @@ -23,26 +24,32 @@ const SAMPLE_VARIABLES = [ { identifier: 'dates.last_7_days', label: 'Last 7 days', + trusted: true, }, { identifier: 'dates.last_14_days', label: 'Last 14 days', + trusted: true, }, { identifier: 'dates.last_30_days', label: 'Last 30 days', + trusted: true, }, { identifier: 'dates.last_3_months', label: 'Last 3 Months', + trusted: true, }, { identifier: 'dates.last_12_months', label: 'Last 12 Months', + trusted: true, }, { identifier: 'dates.month_to_date', label: 'Month to date', + trusted: true, }, { identifier: 'dates.quarter_to_date', @@ -51,6 +58,7 @@ const SAMPLE_VARIABLES = [ { identifier: 'dates.all_time', label: 'All time', + trusted: true, }, ...RELATIVE_SAMPLE_VARIABLES, ]; @@ -74,7 +82,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: 'anythingnotokay', }); }); @@ -165,6 +174,27 @@ describe('Date input', () => { }); }); + describe('when choosing a variable', () => { + it('should emit the new value with correct delimiters (trusted variable)', async () => { + wrapper.find('CustomVariableList-stub').vm.$emit('input', 'dates.last_7_days'); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('input')[0]).toEqual(['{{dates.last_7_days}}']); + }); + it('should emit the new value with correct delimiters (untrusted variable)', async () => { + wrapper.find('CustomVariableList-stub').vm.$emit('input', 'dates.quarter_to_date'); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('input')[0]).toEqual(['<%=dates.quarter_to_date%>']); + }); + it('should emit the correct value (undefined variable)', async () => { + wrapper.find('CustomVariableList-stub').vm.$emit('input', 'noop'); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted('input')).toHaveLength(1); + expect(wrapper.emitted('input')[0]).toEqual(['noop']); + }); + }); + describe('when closing the advanced variable modal', () => { beforeEach(async () => { wrapper.find('AdvancedVariableModal-stub').vm.$emit('closed'); @@ -184,7 +214,7 @@ describe('Date input', () => { it('should emit the new value with delimiters', () => { expect(wrapper.emitted('input')).toHaveLength(1); - expect(wrapper.emitted('input')[0]).toEqual(['{{ Test }}']); + expect(wrapper.emitted('input')[0]).toEqual(['<%= Test %>']); }); it('should send analytics event', () => { expect(sendAnalyticsSpy).toHaveBeenCalledWith({ @@ -199,7 +229,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, }); }); @@ -346,7 +377,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: `{{${selectedVariable.identifier}}}`, }); }); @@ -366,7 +398,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value: advancedVariable, }); }); @@ -405,7 +438,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value, }); }); @@ -438,7 +472,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, value, }); }); @@ -459,7 +494,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, enableCustom: false, }); }); @@ -475,7 +511,8 @@ describe('Date input', () => { beforeEach(async () => { createWrapper({ availableVariables: [], - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, }); wrapper.find('.widget-date-input__container').trigger('click'); await wrapper.vm.$nextTick(); @@ -493,7 +530,8 @@ describe('Date input', () => { beforeEach(() => { createWrapper({ availableVariables: SAMPLE_VARIABLES, - variableDelimiters: { start: '{{', end: '}}' }, + variableDelimiters: { start: '<%=', end: '%>' }, + trustedVariableDelimiters: { start: '{{', end: '}}' }, bounds, value: new Date('2020/2/1'), });