+
+
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/.content.xml
new file mode 100644
index 0000000000..cd3ddd1d64
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/.content.xml
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/.content.xml
new file mode 100644
index 0000000000..f212697391
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/.content.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/README.md b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/README.md
new file mode 100644
index 0000000000..0af3f2df52
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/README.md
@@ -0,0 +1,115 @@
+
+RadioButton (v2)
+====
+Adaptive form Radio Button component written in HTL.
+
+## Features
+
+* Provides the following type of input in form of radio button:
+ * string
+ * boolean
+ * number
+* Alignment of Options (`horizontal` or `vertical`)
+* Styles
+* Allows replacing this component with other component (as mentioned below).
+
+## Changes in v2
+
+- Root element changed from `div` to `fieldset` for better semantics and accessibility.
+- Label and help icon are now rendered inside a native `legend`.
+- Added modifier class `cmp-adaptiveform-radiobutton--v2` on the root block.
+- Extracted options markup to `widget.html` template (no functional change).
+- Documented `cmp-adaptiveform-radiobutton__widget` BEM element.
+- Client library categories remain the same as v1 (runtime/editor).
+
+### Use Object
+The Form Radio Button component uses the `com.adobe.cq.forms.core.components.models.form.RadioButton` Sling Model for its Use-object.
+
+### Edit Dialog Properties
+The following properties are written to JCR for this Radio Button component and are expected to be available as `Resource` properties:
+
+1. `./name` - defines the name of the field, which will be submitted with the form data
+2. `./jcr:title` - defines the label to use for this field
+3. `./hideTitle` - if set to `true`, the label of this field will be hidden
+4. `./type` - defines the type of values(string, boolean, number) which can be accepted
+5. `./enum` - an array[] of type, defines the available values for selection
+6. `./enumNames` - an array[] of strings, defines the display value of the enum
+7. `./default` - defines the default option of the field
+8. `./alignment` - defines how should the options be displayed, horizontally or vertically.
+9. `./description` - defines a help message that can be rendered in the field as a hint for the user
+10. `./required` - if set to `true`, this field will be marked as required, not allowing the form to be submitted until the field has a value
+11. `./requiredMessage` - defines the message displayed as tooltip when submitting the form if the value is left empty
+12. `./readOnly` - if set to `true`, the filed will be read only
+13. `./fieldType` - defines the type of the component
+
+
+## Client Libraries
+The component provides a `core.forms.components.radiobutton.v1.runtime` client library category that contains the Javascript runtime for the component.
+It should be added to a relevant site client library using the `embed` property.
+
+It also provides a `core.forms.components.radiobutton.v1.editor` editor client library category that includes
+JavaScript handling for dialog interaction. It is already included by its edit dialog.
+
+Note: v2 uses the v1 client library categories for both runtime and editor.
+
+## BEM Description
+```
+BLOCK cmp-adaptiveform-radiobutton
+ MODIFIER cmp-adaptiveform-radiobutton--v2
+ ELEMENT cmp-adaptiveform-radiobutton__label
+ ELEMENT cmp-adaptiveform-radiobutton__label-container
+ ELEMENT cmp-adaptiveform-radiobutton__widget
+ ELEMENT cmp-adaptiveform-radiobutton__option
+ ELEMENT cmp-adaptiveform-radiobutton__option-label
+ ELEMENT cmp-adaptiveform-radiobutton__option__widget
+ ELEMENT cmp-adaptiveform-radiobutton__questionmark
+ ELEMENT cmp-adaptiveform-radiobutton__shortdescription
+ ELEMENT cmp-adaptiveform-radiobutton__longdescription
+ ELEMENT cmp-adaptiveform-radiobutton__errormessage
+```
+
+### Note
+By placing the class names `cmp-adaptiveform-radiobutton__label` and `cmp-adaptiveform-radiobutton__questionmark` within the `cmp-adaptiveform-radiobutton__label-container` class, you create a logical grouping of the label and question mark elements. This approach simplifies the process of maintaining a consistent styling for both elements.
+
+## JavaScript Data Attribute Bindings
+
+The following attributes must be added for the initialization of the radio-button component in the form view:
+1. `data-cmp-is="adaptiveFormRadioButton"`
+2. `data-cmp-adaptiveformcontainer-path="${formstructparser.formContainerPath}"`
+
+
+
+The following are optional attributes that can be added to the component in the form view:
+1. `data-cmp-valid` having a boolean value to indicate whether the field is currently valid or not
+2. `data-cmp-required` having a boolean value to indicate whether the field is currently required or not
+3. `data-cmp-readonly` having a boolean value to indicate whether the field is currently readonly or not
+4. `data-cmp-active` having a boolean value to indicate whether the field is currently active or not
+5. `data-cmp-visible` having a boolean value to indicate whether the field is currently visible or not
+6. `data-cmp-enabled` having a boolean value to indicate whether the field is currently enabled or not
+
+## Replace feature:
+We support replace feature that allows replacing Reset Button component to any of the below components:
+
+* Check Box Group
+* Drop down
+
+
+## Information
+* **Vendor**: Adobe
+* **Version**: v2
+* **Compatibility**: Cloud
+* **Status**: production-ready
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/.content.xml
new file mode 100644
index 0000000000..564d04a5c1
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/.content.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/.content.xml
new file mode 100644
index 0000000000..a29e33d085
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/.content.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/js.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/js.txt
new file mode 100644
index 0000000000..b85fb16f9f
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/js.txt
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright 2022 Adobe
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+###############################################################################
+
+#base=js
+radiobuttonview.js
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/js/radiobuttonview.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/js/radiobuttonview.js
new file mode 100644
index 0000000000..472354ab66
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/clientlibs/site/js/radiobuttonview.js
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright 2022 Adobe
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+(function() {
+
+ "use strict";
+ class RadioButton extends FormView.FormOptionFieldBase {
+
+ static NS = FormView.Constants.NS;
+ /**
+ * Each FormField has a data attribute class that is prefixed along with the global namespace to
+ * distinguish between them. If a component wants to put a data-attribute X, the attribute in HTML would be
+ * data-{NS}-{IS}-x=""
+ * @type {string}
+ */
+ static IS = "adaptiveFormRadioButton";
+ static bemBlock = 'cmp-adaptiveform-radiobutton';
+ static selectors = {
+ self: "[data-" + this.NS + '-is="' + this.IS + '"]',
+ widgets: `.${RadioButton.bemBlock}__widget`,
+ widget: `.${RadioButton.bemBlock}__option__widget`,
+ label: `.${RadioButton.bemBlock}__label`,
+ description: `.${RadioButton.bemBlock}__longdescription`,
+ qm: `.${RadioButton.bemBlock}__questionmark`,
+ errorDiv: `.${RadioButton.bemBlock}__errormessage`,
+ tooltipDiv: `.${RadioButton.bemBlock}__shortdescription`,
+ option: `.${RadioButton.bemBlock}__option`,
+ optionLabel: `.${RadioButton.bemBlock}__option-label`
+ };
+
+ constructor(params) {
+ super(params);
+ this.qm = this.element.querySelector(RadioButton.selectors.qm);
+ }
+
+ getWidgets() {
+ return this.element.querySelector(RadioButton.selectors.widgets);
+ }
+
+ getWidget() {
+ return this.element.querySelectorAll(RadioButton.selectors.widget);
+ }
+
+ getDescription() {
+ return this.element.querySelector(RadioButton.selectors.description);
+ }
+
+ getLabel() {
+ return this.element.querySelector(RadioButton.selectors.label);
+ }
+
+ getQuestionMarkDiv() {
+ return this.element.querySelector(RadioButton.selectors.qm);
+ }
+
+ getTooltipDiv() {
+ return this.element.querySelector(RadioButton.selectors.tooltipDiv);
+ }
+
+ getErrorDiv() {
+ return this.element.querySelector(RadioButton.selectors.errorDiv);
+ }
+
+ getOptions() {
+ return this.element.querySelectorAll(RadioButton.selectors.option);
+ }
+
+ #addWidgetListeners(optionWidget) {
+ optionWidget.addEventListener('change', (e) => {
+ this.setModelValue(e.target.value);
+ });
+ optionWidget.addEventListener('focus', (e) => {
+ this.setActive();
+ });
+ optionWidget.addEventListener('blur', (e) => {
+ this.setInactive();
+ });
+ }
+
+ setModel(model) {
+ super.setModel(model);
+ this.widget.forEach(optionWidget => {
+ this.#addWidgetListeners(optionWidget);
+ });
+ }
+
+ updateEnabled(enabled, state) {
+ this.element.setAttribute(FormView.Constants.DATA_ATTRIBUTE_ENABLED, enabled);
+ let widgets = this.widget;
+ widgets.forEach(widget => {
+ if (enabled === false) {
+ if(state.readOnly === false){
+ widget.setAttribute(FormView.Constants.HTML_ATTRS.DISABLED, "disabled");
+ }
+ } else if (state.readOnly === false) {
+ widget.removeAttribute(FormView.Constants.HTML_ATTRS.DISABLED);
+ }
+ });
+ }
+
+ updateReadOnly(readonly) {
+ let widgets = this.widget;
+ this.element.setAttribute(FormView.Constants.DATA_ATTRIBUTE_READONLY, readonly);
+ widgets.forEach(widget => {
+ if (readonly === true) {
+ widget.setAttribute(FormView.Constants.HTML_ATTRS.DISABLED, "disabled");
+ } else {
+ widget.removeAttribute(FormView.Constants.HTML_ATTRS.DISABLED);
+ }
+ });
+ }
+
+ updateValidity(validity) {
+ if(validity.valid === undefined) {
+ this.element.removeAttribute(FormView.Constants.DATA_ATTRIBUTE_VALID);
+ this.widget.forEach(widget => widget.removeAttribute(FormView.Constants.ARIA_INVALID));
+ } else {
+ this.element.setAttribute(FormView.Constants.DATA_ATTRIBUTE_VALID, validity.valid);
+ this.widget.forEach(widget => widget.setAttribute(FormView.Constants.ARIA_INVALID, !validity.valid));
+ }
+ }
+
+ updateValue(modelValue) {
+ this.widget.forEach(widget => {
+ if (modelValue != null && widget.value != null && (modelValue.toString() == widget.value.toString())) {
+ widget.checked = true;
+ widget.setAttribute(FormView.Constants.HTML_ATTRS.CHECKED, FormView.Constants.HTML_ATTRS.CHECKED);
+ } else {
+ widget.checked = false;
+ widget.removeAttribute(FormView.Constants.HTML_ATTRS.CHECKED);
+ }
+ }, this)
+ super.updateEmptyStatus();
+ }
+
+ #createRadioOption(value, itemLabel) {
+ const optionTemplate = `
+
+
+
`;
+
+ const container = document.createElement('div'); // Create a container element to hold the template
+ container.innerHTML = optionTemplate;
+ let addedOptionWidget = container.querySelector(RadioButton.selectors.widget);
+ if(this._model.readOnly === true || this._model.enabled === false) {
+ addedOptionWidget.setAttribute("disabled", true);
+ if(this._model.readOnly === true) {
+ addedOptionWidget.setAttribute("aria-readonly", true);
+ }
+ }
+ this.#addWidgetListeners(addedOptionWidget);
+ return container.firstElementChild; // Return the first child, which is the created option
+ }
+
+ updateEnum(newEnums) {
+ super.updateEnumForRadioButtonAndCheckbox(newEnums, this.#createRadioOption);
+ // refresh the widget references, to dynamically added options
+ this.widget = this.getWidget();
+ }
+
+ updateEnumNames(newEnumNames) {
+ super.updateEnumNamesForRadioButtonAndCheckbox(newEnumNames, this.#createRadioOption);
+ // refresh the widget references, to dynamically added options
+ this.widget = this.getWidget();
+ }
+
+ updateRequired(required, state) {
+ if (this.widget) {
+ this.element.toggleAttribute("required", required);
+ this.element.setAttribute("data-cmp-required", required);
+ }
+ }
+
+ syncMarkupWithModel() {
+ super.syncMarkupWithModel();
+ this.#syncWidgetName();
+ }
+
+ #syncWidgetName() {
+ const name = this.getModel()?.name;
+ this.widget.forEach(widget => {
+ widget.setAttribute("name", `${this.id}_${name}`);
+ });
+ }
+ }
+
+ FormView.Utils.setupField(({element, formContainer}) => {
+ return new RadioButton({element, formContainer});
+ }, RadioButton.selectors.self);
+
+})();
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/radiobutton.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/radiobutton.html
new file mode 100644
index 0000000000..0c4e846a7a
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/radiobutton.html
@@ -0,0 +1,53 @@
+
+
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/radiobutton.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/radiobutton.js
new file mode 100644
index 0000000000..56b6a4e059
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/radiobutton.js
@@ -0,0 +1,36 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2025 Adobe
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+use(function() {
+
+ var clientlibsArr = [ 'core.forms.components.base.v1.editor' ];
+ var labelPath = 'core/fd/components/af-commons/v1/fieldTemplates/label.html';
+ var shortDescriptionPath = "core/fd/components/af-commons/v1/fieldTemplates/shortDescription.html";
+ var longDescriptionPath = "core/fd/components/af-commons/v1/fieldTemplates/longDescription.html";
+ var questionMarkPath = "core/fd/components/af-commons/v1/fieldTemplates/questionMark.html"
+ var errorMessagePath = "core/fd/components/af-commons/v1/fieldTemplates/errorMessage.html";
+ var legendPath = "core/fd/components/af-commons/v1/fieldTemplates/legend.html"
+ return {
+ labelPath : labelPath,
+ shortDescriptionPath : shortDescriptionPath,
+ longDescriptionPath : longDescriptionPath,
+ questionMarkPath : questionMarkPath,
+ errorMessagePath : errorMessagePath,
+ legendPath : legendPath,
+ clientlibs : clientlibsArr
+ }
+});
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/widget.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/widget.html
new file mode 100644
index 0000000000..efd6bd1ba3
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/radiobutton/v2/radiobutton/widget.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui.frontend/src/view/FormFieldBase.js b/ui.frontend/src/view/FormFieldBase.js
index 876441501a..6d117c14ca 100644
--- a/ui.frontend/src/view/FormFieldBase.js
+++ b/ui.frontend/src/view/FormFieldBase.js
@@ -166,8 +166,11 @@ class FormFieldBase extends FormField {
*/
#syncLabel() {
let labelElement = typeof this.getLabel === 'function' ? this.getLabel() : null;
- if (labelElement) {
+ if (labelElement && labelElement.tagName?.toUpperCase() === 'LABEL') {
labelElement.setAttribute('for', this.getWidgetId());
+ } else if (labelElement) {
+ //remove the 'for' attribute if it exists on non-label
+ labelElement.removeAttribute('for');
}
}
diff --git a/ui.tests/test-module/specs/checkboxgroup/checkboxgroup.runtime.cy.js b/ui.tests/test-module/specs/checkboxgroup/checkboxgroup.runtime.cy.js
index f095eca80c..31e7d1bf0c 100644
--- a/ui.tests/test-module/specs/checkboxgroup/checkboxgroup.runtime.cy.js
+++ b/ui.tests/test-module/specs/checkboxgroup/checkboxgroup.runtime.cy.js
@@ -15,7 +15,7 @@
******************************************************************************/
describe("Form Runtime with CheckBoxGroup Input", () => {
- const pagePath = "content/forms/af/core-components-it/samples/checkboxgroup/basic.html"
+ const pagePath = "content/forms/af/core-components-it/samples/checkboxgroup/checkboxgroupv1/basic.html"
const bemBlock = 'cmp-adaptiveform-checkboxgroup'
const IS = "adaptiveFormCheckBoxGroup"
const selectors = {
@@ -253,7 +253,7 @@ describe("Form Runtime with CheckBoxGroup Input", () => {
describe("setFocus on checkboxgroup via rules", () => {
- const pagePath = "content/forms/af/core-components-it/samples/checkboxgroup/focustest.html"
+ const pagePath = "content/forms/af/core-components-it/samples/checkboxgroup/checkboxgroupv1/focustest.html"
let formContainer = null
beforeEach(() => {
diff --git a/ui.tests/test-module/specs/checkboxgroup/checkboxgroupv2.runtime.cy.js b/ui.tests/test-module/specs/checkboxgroup/checkboxgroupv2.runtime.cy.js
new file mode 100644
index 0000000000..fcfb73ed0e
--- /dev/null
+++ b/ui.tests/test-module/specs/checkboxgroup/checkboxgroupv2.runtime.cy.js
@@ -0,0 +1,281 @@
+/*******************************************************************************
+ * Copyright 2022 Adobe
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+describe("Form Runtime with CheckBoxGroup Input", () => {
+
+ const pagePath = "content/forms/af/core-components-it/samples/checkboxgroup/checkboxgroupv2/basic.html"
+ const bemBlock = 'cmp-adaptiveform-checkboxgroup'
+ const IS = "adaptiveFormCheckBoxGroup"
+ const selectors = {
+ checkboxgroup : `[data-cmp-is="${IS}"]`
+ }
+
+ let formContainer = null
+
+ beforeEach(() => {
+ cy.previewForm(pagePath).then(p => {
+ formContainer = p;
+ })
+ });
+
+ const checkHTML = (id, state) => {
+ const visible = state.visible;
+ const passVisibleCheck = `${visible === true ? "" : "not."}be.visible`;
+ const passDisabledAttributeCheck = `${state.enabled === false || state.readOnly === true ? "" : "not."}have.attr`;
+ const value = state.value
+ cy.get(`#${id}`)
+ .should(passVisibleCheck)
+ .invoke('attr', 'data-cmp-visible')
+ .should('eq', visible.toString());
+ cy.get(`#${id}`)
+ .invoke('attr', 'data-cmp-enabled')
+ .should('eq', state.enabled.toString());
+ return cy.get(`#${id}`).within((root) => {
+ cy.get('*').should(passVisibleCheck)
+ cy.get('input')
+ .should('have.length', 4)
+ cy.get('input')
+ .should(passDisabledAttributeCheck, 'disabled');
+ cy.get('input').eq(1).should('be.checked')
+ })
+ }
+
+ it(" should get model and view initialized properly ", () => {
+ expect(formContainer, "formcontainer is initialized").to.not.be.null;
+ expect(formContainer._model.items.length, "model and view elements match").to.equal(Object.keys(formContainer._fields).length);
+ Object.entries(formContainer._fields).forEach(([id, field]) => {
+ expect(field.getId()).to.equal(id)
+ expect(formContainer._model.getElement(id), `model and view are in sync`).to.equal(field.getModel())
+ });
+ })
+
+ it(" model's changes are reflected in the html ", () => {
+ const [id, fieldView] = Object.entries(formContainer._fields)[0]
+ const model = formContainer._model.getElement(id)
+ const val = Array('1','2')
+ model.value = '1'
+ cy.get(`#${id}`).find(".cmp-adaptiveform-checkboxgroup__widget").should('have.class', 'VERTICAL')
+ const [id2, fieldView2] = Object.entries(formContainer._fields)[1]
+ cy.get(`#${id2}`).find(".cmp-adaptiveform-checkboxgroup__widget").should('have.class', 'HORIZONTAL')
+
+
+ checkHTML(model.id, model.getState()).then(() => {
+ model.visible = false
+ return checkHTML(model.id, model.getState())
+ }).then(() => {
+ model.enable = false
+ return checkHTML(model.id, model.getState())
+ })
+ });
+
+ it(" html changes are reflected in model ", () => {
+ const [id, fieldView] = Object.entries(formContainer._fields)[1]
+ const model = formContainer._model.getElement(id)
+
+ cy.log(model.getState().value)
+ cy.get(`#${id}`).find("input").eq(1).click().then(x => {
+ cy.log(model.getState().value)
+ expect(model.getState().value).to.contain('1');
+ })
+
+ cy.get(`#${id}`).find("input").eq(2).click().then(x => {
+ cy.log(model.getState().value)
+ expect(model.getState().value).to.contain('2');
+ })
+ });
+
+ it(" should show error messages in the HTML ", () => {
+ const [id, fieldView] = Object.entries(formContainer._fields)[1]
+ const model = formContainer._model.getElement(id)
+
+ cy.get(`#${id}`).find("input").eq(1).click().then(x => {
+ cy.log(model.getState().value)
+ expect(model.getState().value).to.contain('1');
+ })
+
+ cy.get(`#${id}`).find("input").eq(1).click().then(x => {
+ cy.get(`#${id}`).find(".cmp-adaptiveform-checkboxgroup__errormessage").should('have.text',"This is a custom required checkboxgroup")
+ })
+
+ cy.get(`#${id}`).find("input").eq(1).click().then(x => {
+ cy.get(`#${id}`).find(".cmp-adaptiveform-checkboxgroup__errormessage").should('have.text',"")
+ })
+ });
+
+ it("should toggle description and tooltip", () => {
+ cy.toggleDescriptionTooltip(bemBlock, 'tooltip_scenario_test');
+ })
+
+ it("should show and hide components on certain checkbox input", () => {
+ // Rule on checkbox2: When checkbox2 has Item 1 AND Item 3 selected => Show checkbox3 and Hide checkBox4
+
+ const [checkBox2, checkBox2FieldView] = Object.entries(formContainer._fields)[1];
+ const [checkBox3, checkBox3FieldView] = Object.entries(formContainer._fields)[2];
+ const [checkBox4, checkBox4FieldView] = Object.entries(formContainer._fields)[3];
+
+ cy.get(`#${checkBox2}`).find("input").check(["0","3"]).then(x => {
+ cy.get(`#${checkBox3}`).should('be.visible')
+ cy.get(`#${checkBox4}`).should('not.be.visible')
+ })
+ })
+
+ it("Checkbox group should not have aria-disabled attribute if enable is false", () => {
+ const [id, fieldView] = Object.entries(formContainer._fields)[0];
+ cy.get(`#${id}`).find(".cmp-adaptiveform-checkboxgroup__widget").should('not.have.attr', 'aria-disabled');
+ })
+
+ it("should enable and disable components on certain checkbox input", () => {
+ // Rule on checkbox4: When checkbox4 has Item 3 selected => Enable checkbox1 and Disable checkBox2
+
+ const [checkBox1, checkBox1FieldView] = Object.entries(formContainer._fields)[0];
+ const [checkBox2, checkBox2FieldView] = Object.entries(formContainer._fields)[1];
+ const [checkBox4, checkBox4FieldView] = Object.entries(formContainer._fields)[3];
+
+ cy.get(`#${checkBox4}`).find("input").check(["2"]).then(x => {
+ cy.get(`#${checkBox1}`).find("input").should('be.enabled')
+ cy.get(`#${checkBox2}`).find("input").should('not.be.enabled')
+ })
+ })
+
+ it("should show validation error messages based on expression rules", () => {
+ // Rule on checkBox5: Validate checkBox using Expression: checkBox5 === checkBox3
+
+ const [checkBox2, checkBox2FieldView] = Object.entries(formContainer._fields)[1];
+ const [checkBox3, checkBox3FieldView] = Object.entries(formContainer._fields)[2];
+ const [checkBox5, checkBox5FieldView] = Object.entries(formContainer._fields)[4];
+
+ // Making checkBox3 visible
+ cy.get(`#${checkBox2}`).find("input").check(["0","3"])
+
+ cy.get(`#${checkBox3}`).find("input").uncheck().check(["0"]).blur().then(x => {
+ cy.get(`#${checkBox5}`).find("input").uncheck().check(["1"])
+ cy.get(`#${checkBox5}`).find(".cmp-adaptiveform-checkboxgroup__errormessage").should('have.text',"Please enter a valid value.")
+ cy.get(`#${checkBox5}`).should('have.attr', 'data-cmp-valid', 'false')
+ cy.get(`#${checkBox5}`).find(".cmp-adaptiveform-checkboxgroup__widget").should('not.have.attr', 'aria-checked')
+ cy.get(`#${checkBox5}`).find(".cmp-adaptiveform-checkboxgroup__widget").should('have.attr', 'aria-describedby', `${checkBox5}__errormessage`)
+ })
+
+ cy.get(`#${checkBox3}`).find("input").uncheck().check(["0"]).blur().then(x => {
+ cy.get(`#${checkBox5}`).find("input").uncheck().check(["0"])
+ cy.get(`#${checkBox5}`).find(".cmp-adaptiveform-checkboxgroup__errormessage").should('have.text',"")
+ cy.get(`#${checkBox5}`).should('have.attr', 'data-cmp-valid', 'true')
+ cy.get(`#${checkBox5}`).find(".cmp-adaptiveform-checkboxgroup__option__widget").should('have.attr', 'aria-invalid', 'false');
+ cy.get(`#${checkBox5}`).find(".cmp-adaptiveform-checkboxgroup__widget").should('have.attr', 'aria-describedby', '');
+ })
+ })
+
+ it("should set and clear value based on rules", () => {
+ // Rule on checkBox3: When input has Item2 selected, set value of checkBox5 to Item 1 and clear value of checkBox2
+
+ const [checkBox2, checkBox2FieldView] = Object.entries(formContainer._fields)[1];
+ const [checkBox3, checkBox3FieldView] = Object.entries(formContainer._fields)[2];
+ const [checkBox5, checkBox5FieldView] = Object.entries(formContainer._fields)[4];
+
+ // Make checkbox3 visible
+ cy.get(`#${checkBox2}`).find("input").check(["0", "3"])
+ cy.get(`#${checkBox3}`).find("input").check("1").blur().then(x => {
+ cy.get(`#${checkBox5}`).find("input").should('be.checked')
+ cy.get(`#${checkBox2}`).find("input").should('not.be.checked')
+ })
+ })
+
+ it("should update enum values on providing duplicate enums", () => {
+
+ const [checkBox6, checkBox6FieldView] = Object.entries(formContainer._fields)[5];
+ cy.get(`#${checkBox6}`).find(".cmp-adaptiveform-checkboxgroup-item").should('have.length', 2);
+ cy.get(`#${checkBox6}`).find(".cmp-adaptiveform-checkboxgroup__option-label").contains('Item 3');
+ cy.get(`#${checkBox6}`).find(".cmp-adaptiveform-checkboxgroup__option-label").contains('Item 2');
+ cy.get(`#${checkBox6}`).find(".cmp-adaptiveform-checkboxgroup__option-label").contains('Item 1').should('not.exist');
+
+ })
+
+ it("rich text should render correctly", () => {
+ const [checkBox7, checkBox7FieldView] = Object.entries(formContainer._fields)[6];
+ cy.get(`#${checkBox7}`).find(".cmp-adaptiveform-checkboxgroup-item").should('have.length', 2);
+ cy.get(`#${checkBox7}`).find(".cmp-adaptiveform-checkboxgroup__label").contains('Select Animal').should('have.css', 'font-weight', '700');
+ cy.get(`#${checkBox7}`).find(".cmp-adaptiveform-checkboxgroup__option-label span").contains('Dog').should('have.css', 'font-style', 'italic');
+ cy.get(`#${checkBox7}`).find(".cmp-adaptiveform-checkboxgroup__option-label span").contains('Cat').should('have.css', 'text-decoration', 'underline solid rgb(50, 50, 50)');
+ });
+
+ it("decoration element should not have same class name", () => {
+ expect(formContainer, "formcontainer is initialized").to.not.be.null;
+ cy.wrap().then(() => {
+ const id = formContainer._model._children[0].id;
+ cy.get(`#${id}`).parent().should("not.have.class", bemBlock);
+ })
+
+ })
+
+ it(" should add filled/empty class at container div ", () => {
+ const [id, fieldView] = Object.entries(formContainer._fields)[2]
+ cy.get(`#${id}`).should('have.class', 'cmp-adaptiveform-checkboxgroup--empty');
+ cy.get(`#${id}`).invoke('attr', 'data-cmp-required').should('eq', 'false');
+ cy.get(`#${id}`).invoke('attr', 'data-cmp-readonly').should('eq', 'false');
+ const [checkBox2, checkBox2FieldView] = Object.entries(formContainer._fields)[1];
+ cy.get(`#${checkBox2}`).find("input").check(["0","3"])
+ cy.get(`#${id}`).find("input").eq(1).click().then(x => {
+ cy.get(`#${id}`).should('have.class', 'cmp-adaptiveform-checkboxgroup--filled');
+ });
+ });
+
+ it("test if required property updated in model is reflected in view", () => {
+ const [id, checkboxview] = Object.entries(formContainer._fields)[5];
+ cy.get(`#${id}`).invoke('attr', 'data-cmp-required').should('eq', 'false').then(() => {
+ checkboxview._model.required = true;
+ })
+ cy.get(`#${id}`).invoke('attr', 'data-cmp-required').should('eq', 'true');
+ });
+
+ it("reset of checkbox group resulting in invalidation", () => {
+ expect(formContainer, "formcontainer is initialized").to.not.be.null;
+ const [resetButton, resetButtonView] = Object.entries(formContainer._fields)[7];
+ const [checkBox2, checkBox2FieldView] = Object.entries(formContainer._fields)[1];
+ cy.get(`#${checkBox2}`).find("input").check(["0","3"]);
+ cy.get(`#${checkBox2}`).invoke('attr', 'data-cmp-valid').should('eq', 'true');
+ cy.get(`#${resetButton} button`).click().then(() => {
+ cy.get(`#${checkBox2}`).find("input").should('not.be.checked');
+ cy.get(`#${checkBox2}`).invoke('attr', 'data-cmp-valid').should('not.exist');
+ });
+ })
+
+ it("checkbox group MUST be wrapped in a