Skip to content

Commit 2147c8c

Browse files
Anurudra Shuklaclaude
authored andcommitted
FORMS-25983 Address PR #1910 review comments
- Move new min/max Cypress tests to separate spec files (numberinput.minmax.authoring.cy.js, textinput.minmax.authoring.cy.js) so validate_test_files CI check no longer scans files with pre-existing it.skip entries - Remove redirect URL validator scope creep from container v1 editDialog.js and the validation attribute from v1/v2 dialog XML — unrelated to min/max - In handleMinMaxValidation validate(), clear errorMessage in the valid branch and add comment explaining why direct mutation is used instead of event dispatch (avoids infinite recursion via jQuery trigger) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 371cad3 commit 2147c8c

8 files changed

Lines changed: 182 additions & 110 deletions

File tree

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/af-commons/v1/clientlibs/editor/utils/utils.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,17 @@
344344
function validate() {
345345
var minVal = minField.value, maxVal = maxField.value;
346346
var invalid = !!(minVal && maxVal && compare(minVal, maxVal));
347+
// Direct property mutation avoids dispatching change events.
348+
// Using jQuery.trigger() would re-enter this listener via native DOM
349+
// event propagation, causing infinite recursion.
347350
minField.invalid = invalid;
348351
maxField.invalid = invalid;
349352
if (invalid) {
350353
minField.errorMessage = Granite.I18n.getMessage(minMsg);
351354
maxField.errorMessage = Granite.I18n.getMessage(maxMsg);
355+
} else {
356+
minField.errorMessage = "";
357+
maxField.errorMessage = "";
352358
}
353359
}
354360
validate();

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v1/container/_cq_dialog/.content.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
fieldLabel="Redirect URL/Path"
9393
rootPath="/content"
9494
name="./redirect"
95-
validation="forms.redirect.absolutepath"
9695
filter="nosystem"/>
9796
<thankYouMessage
9897
jcr:primaryType="nt:unstructured"

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v1/container/clientlibs/editor/js/editDialog.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,18 +256,6 @@
256256
});
257257
}
258258

259-
$(window).adaptTo("foundation-registry").register("foundation.validation.validator", {
260-
selector: "[data-validation~='forms.redirect.absolutepath']",
261-
validate: function(el) {
262-
var value = el.value;
263-
if (value && !value.startsWith("/") && !/^https?:\/\/.+$/i.test(value)) {
264-
return Granite.I18n.getMessage(
265-
"Please enter an absolute path (starting with '/') or an absolute URL (starting with 'http://' or 'https://')."
266-
);
267-
}
268-
}
269-
});
270-
271259
Utils.initializeEditDialog(EDIT_DIALOG_FORM)(handleAsyncSubmissionAndThankYouOption, handleSubmitAction,
272260
registerSubmitActionSubDialogClientLibs, registerRestEndPointDialogClientlibs, registerFDMDialogClientlibs, registerEmailDialogClientlibs, initialiseDataModel, registerAutoSaveDialogAction);
273261

ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/_cq_dialog/.content.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@
300300
fieldLabel="Redirect URL/Path"
301301
rootPath="/content"
302302
name="./redirect"
303-
validation="forms.redirect.absolutepath"
304303
filter="nosystem"/>
305304
<thankYouMessage
306305
jcr:primaryType="nt:unstructured"

ui.tests/test-module/specs/numberinput/numberinput.authoring.cy.js

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -132,54 +132,6 @@ describe('Page - Authoring', function () {
132132
});
133133
});
134134

135-
it('shows inline error when minimum is set greater than maximum', function () {
136-
dropNumberInputInContainer();
137-
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + numberInputEditPathSelector);
138-
cy.invokeEditableAction(editDialogConfigurationSelector);
139-
cy.get(numberInputBlockBemSelector + '__editdialog').contains('Validation').click();
140-
141-
// Set maximum = 5, then minimum = 10 (invalid: min > max)
142-
cy.get(numberInputBlockBemSelector + '__maximum').find('input').clear().type('5');
143-
cy.focused().blur();
144-
cy.get(numberInputBlockBemSelector + '__minimum').find('input').clear().type('10');
145-
cy.focused().blur();
146-
147-
// Both fields should be marked invalid
148-
cy.get(numberInputBlockBemSelector + '__minimum').should('have.attr', 'invalid');
149-
cy.get(numberInputBlockBemSelector + '__maximum').should('have.attr', 'invalid');
150-
151-
// Fix by lowering minimum below maximum
152-
cy.get(numberInputBlockBemSelector + '__minimum').find('input').clear().type('3');
153-
cy.focused().blur();
154-
155-
// Both fields should no longer be invalid
156-
cy.get(numberInputBlockBemSelector + '__minimum').should('not.have.attr', 'invalid');
157-
cy.get(numberInputBlockBemSelector + '__maximum').should('not.have.attr', 'invalid');
158-
159-
cy.get('.cq-dialog-cancel').should('be.visible').click();
160-
cy.deleteComponentByPath(numberInputDrop);
161-
});
162-
163-
it('blocks dialog save when minimum is greater than maximum', function () {
164-
dropNumberInputInContainer();
165-
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + numberInputEditPathSelector);
166-
cy.invokeEditableAction(editDialogConfigurationSelector);
167-
cy.get(numberInputBlockBemSelector + '__editdialog').contains('Validation').click();
168-
169-
// Set an invalid state: minimum > maximum
170-
cy.get(numberInputBlockBemSelector + '__maximum').find('input').clear().type('5');
171-
cy.focused().blur();
172-
cy.get(numberInputBlockBemSelector + '__minimum').find('input').clear().type('10');
173-
cy.focused().blur();
174-
175-
// Attempt to save — dialog should remain open
176-
cy.get('.cq-dialog-submit').click();
177-
cy.get('coral-dialog[open]').should('exist');
178-
179-
cy.get('.cq-dialog-cancel').should('be.visible').click();
180-
cy.deleteComponentByPath(numberInputDrop);
181-
});
182-
183135
// todo: leadDigits and fracDigits are not supported as of today
184136
it.skip('verify editFormat Value Getting saved correctly', function () {
185137
dropNumberInputInContainer();
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*******************************************************************************
2+
* Copyright 2022 Adobe
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
******************************************************************************/
16+
17+
const afConstants = require("../../libs/commons/formsConstants");
18+
const sitesSelectors = require("../../libs/commons/sitesSelectors");
19+
20+
describe('Page - Authoring', function () {
21+
const dropNumberInputInContainer = function () {
22+
const dataPath = "/content/forms/af/core-components-it/blank/jcr:content/guideContainer/*",
23+
responsiveGridDropZoneSelector = sitesSelectors.overlays.overlay.component + "[data-path='" + dataPath + "']";
24+
cy.selectLayer("Edit");
25+
cy.insertComponent(responsiveGridDropZoneSelector, "Adaptive Form Number Input", afConstants.components.forms.resourceType.formnumberinput);
26+
cy.get('body').click(0, 0);
27+
}
28+
29+
context('Open Forms Editor', function () {
30+
const pagePath = "/content/forms/af/core-components-it/blank",
31+
numberInputEditPath = pagePath + afConstants.FORM_EDITOR_FORM_CONTAINER_SUFFIX + "/numberinput",
32+
numberInputEditPathSelector = "[data-path='" + numberInputEditPath + "']",
33+
numberInputDrop = pagePath + afConstants.FORM_EDITOR_FORM_CONTAINER_SUFFIX + "/" + afConstants.components.forms.resourceType.formnumberinput.split("/").pop(),
34+
numberInputBlockBemSelector = '.cmp-adaptiveform-numberinput',
35+
editDialogConfigurationSelector = "[data-action='CONFIGURE']";
36+
37+
beforeEach(function () {
38+
cy.openAuthoring(pagePath);
39+
});
40+
41+
it('shows inline error when minimum is set greater than maximum', function () {
42+
dropNumberInputInContainer();
43+
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + numberInputEditPathSelector);
44+
cy.invokeEditableAction(editDialogConfigurationSelector);
45+
cy.get(numberInputBlockBemSelector + '__editdialog').contains('Validation').click();
46+
47+
// Set maximum = 5, then minimum = 10 (invalid: min > max)
48+
cy.get(numberInputBlockBemSelector + '__maximum').find('input').clear().type('5');
49+
cy.focused().blur();
50+
cy.get(numberInputBlockBemSelector + '__minimum').find('input').clear().type('10');
51+
cy.focused().blur();
52+
53+
// Both fields should be marked invalid
54+
cy.get(numberInputBlockBemSelector + '__minimum').should('have.attr', 'invalid');
55+
cy.get(numberInputBlockBemSelector + '__maximum').should('have.attr', 'invalid');
56+
57+
// Fix by lowering minimum below maximum
58+
cy.get(numberInputBlockBemSelector + '__minimum').find('input').clear().type('3');
59+
cy.focused().blur();
60+
61+
// Both fields should no longer be invalid
62+
cy.get(numberInputBlockBemSelector + '__minimum').should('not.have.attr', 'invalid');
63+
cy.get(numberInputBlockBemSelector + '__maximum').should('not.have.attr', 'invalid');
64+
65+
cy.get('.cq-dialog-cancel').should('be.visible').click();
66+
cy.deleteComponentByPath(numberInputDrop);
67+
});
68+
69+
it('blocks dialog save when minimum is greater than maximum', function () {
70+
dropNumberInputInContainer();
71+
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + numberInputEditPathSelector);
72+
cy.invokeEditableAction(editDialogConfigurationSelector);
73+
cy.get(numberInputBlockBemSelector + '__editdialog').contains('Validation').click();
74+
75+
// Set an invalid state: minimum > maximum
76+
cy.get(numberInputBlockBemSelector + '__maximum').find('input').clear().type('5');
77+
cy.focused().blur();
78+
cy.get(numberInputBlockBemSelector + '__minimum').find('input').clear().type('10');
79+
cy.focused().blur();
80+
81+
// Attempt to save — dialog should remain open
82+
cy.get('.cq-dialog-submit').click();
83+
cy.get('coral-dialog[open]').should('exist');
84+
85+
cy.get('.cq-dialog-cancel').should('be.visible').click();
86+
cy.deleteComponentByPath(numberInputDrop);
87+
});
88+
});
89+
});

ui.tests/test-module/specs/textinput/textinput.authoring.cy.js

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -211,54 +211,6 @@ describe('Page - Authoring', function () {
211211
});
212212
});
213213

214-
it('shows inline error when minLength is set greater than maxLength', function () {
215-
dropTextInputInContainer();
216-
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + textInputEditPathSelector);
217-
cy.invokeEditableAction("[data-action='CONFIGURE']");
218-
cy.get('.cmp-adaptiveform-textinput__editdialog').contains('Validation').click({force: true});
219-
220-
// Set maxLength = 5, then minLength = 10 (invalid: min > max)
221-
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').find('input').clear().type('5');
222-
cy.focused().blur();
223-
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').find('input').clear().type('10');
224-
cy.focused().blur();
225-
226-
// Both fields should be marked invalid
227-
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').should('have.attr', 'invalid');
228-
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').should('have.attr', 'invalid');
229-
230-
// Fix by lowering minLength below maxLength
231-
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').find('input').clear().type('3');
232-
cy.focused().blur();
233-
234-
// Both fields should no longer be invalid
235-
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').should('not.have.attr', 'invalid');
236-
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').should('not.have.attr', 'invalid');
237-
238-
cy.get('.cq-dialog-cancel').should('be.visible').click();
239-
cy.deleteComponentByPath(textInputDrop);
240-
});
241-
242-
it('blocks dialog save when minLength is greater than maxLength', function () {
243-
dropTextInputInContainer();
244-
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + textInputEditPathSelector);
245-
cy.invokeEditableAction("[data-action='CONFIGURE']");
246-
cy.get('.cmp-adaptiveform-textinput__editdialog').contains('Validation').click({force: true});
247-
248-
// Set an invalid state: minLength > maxLength
249-
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').find('input').clear().type('5');
250-
cy.focused().blur();
251-
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').find('input').clear().type('10');
252-
cy.focused().blur();
253-
254-
// Attempt to save — dialog should remain open
255-
cy.get('.cq-dialog-submit').click();
256-
cy.get('coral-dialog[open]').should('exist');
257-
258-
cy.get('.cq-dialog-cancel').should('be.visible').click();
259-
cy.deleteComponentByPath(textInputDrop);
260-
});
261-
262214
it('should switch validation pattern dropdown to "Custom" when an unmapped regex is authored', function () {
263215
const customValidationFormatValue = '^custom-regex-[0-9]{3}$';
264216

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2022 Adobe Systems Incorporated
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
const sitesSelectors = require('../../libs/commons/sitesSelectors'),
18+
afConstants = require('../../libs/commons/formsConstants');
19+
20+
describe('Page - Authoring', function () {
21+
const dropTextInputInContainer = function () {
22+
const dataPath = "/content/forms/af/core-components-it/blank/jcr:content/guideContainer/*",
23+
responsiveGridDropZoneSelector = sitesSelectors.overlays.overlay.component + "[data-path='" + dataPath + "']";
24+
cy.selectLayer("Edit");
25+
cy.insertComponent(responsiveGridDropZoneSelector, "Adaptive Form Text Box", afConstants.components.forms.resourceType.formtextinput);
26+
cy.get('body').click(0, 0);
27+
}
28+
29+
context('Open Forms Editor', function () {
30+
const pagePath = "/content/forms/af/core-components-it/blank",
31+
textInputEditPath = pagePath + afConstants.FORM_EDITOR_FORM_CONTAINER_SUFFIX + "/textinput",
32+
textInputEditPathSelector = "[data-path='" + textInputEditPath + "']",
33+
textInputDrop = pagePath + afConstants.FORM_EDITOR_FORM_CONTAINER_SUFFIX + "/" + afConstants.components.forms.resourceType.formtextinput.split("/").pop();
34+
35+
beforeEach(function () {
36+
cy.openAuthoring(pagePath);
37+
});
38+
39+
it('shows inline error when minLength is set greater than maxLength', function () {
40+
dropTextInputInContainer();
41+
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + textInputEditPathSelector);
42+
cy.invokeEditableAction("[data-action='CONFIGURE']");
43+
cy.get('.cmp-adaptiveform-textinput__editdialog').contains('Validation').click({force: true});
44+
45+
// Set maxLength = 5, then minLength = 10 (invalid: min > max)
46+
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').find('input').clear().type('5');
47+
cy.focused().blur();
48+
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').find('input').clear().type('10');
49+
cy.focused().blur();
50+
51+
// Both fields should be marked invalid
52+
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').should('have.attr', 'invalid');
53+
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').should('have.attr', 'invalid');
54+
55+
// Fix by lowering minLength below maxLength
56+
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').find('input').clear().type('3');
57+
cy.focused().blur();
58+
59+
// Both fields should no longer be invalid
60+
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').should('not.have.attr', 'invalid');
61+
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').should('not.have.attr', 'invalid');
62+
63+
cy.get('.cq-dialog-cancel').should('be.visible').click();
64+
cy.deleteComponentByPath(textInputDrop);
65+
});
66+
67+
it('blocks dialog save when minLength is greater than maxLength', function () {
68+
dropTextInputInContainer();
69+
cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + textInputEditPathSelector);
70+
cy.invokeEditableAction("[data-action='CONFIGURE']");
71+
cy.get('.cmp-adaptiveform-textinput__editdialog').contains('Validation').click({force: true});
72+
73+
// Set an invalid state: minLength > maxLength
74+
cy.get('.cmp-adaptiveform-textinput__maxlength coral-numberinput').find('input').clear().type('5');
75+
cy.focused().blur();
76+
cy.get('.cmp-adaptiveform-textinput__minlength coral-numberinput').find('input').clear().type('10');
77+
cy.focused().blur();
78+
79+
// Attempt to save — dialog should remain open
80+
cy.get('.cq-dialog-submit').click();
81+
cy.get('coral-dialog[open]').should('exist');
82+
83+
cy.get('.cq-dialog-cancel').should('be.visible').click();
84+
cy.deleteComponentByPath(textInputDrop);
85+
});
86+
});
87+
});

0 commit comments

Comments
 (0)