diff --git a/.github/workflows/exporter-validate-pr.yml b/.github/workflows/exporter-validate-pr.yml
index 0907dd8f64..87c035df5e 100644
--- a/.github/workflows/exporter-validate-pr.yml
+++ b/.github/workflows/exporter-validate-pr.yml
@@ -48,10 +48,10 @@ jobs:
exit 1
fi
- # Check for changed values
- for key in $base_keys; do
- base_value=$(echo "$base_file" | jq -r --arg key "$key" '.[$key]')
- head_value=$(echo "$head_file" | jq -r --arg key "$key" '.[$key]')
+ # Check for changed values
+ for key in $base_keys; do
+ base_value=$(echo "$base_file" | jq -r ".$key")
+ head_value=$(echo "$head_file" | jq -r ".$key")
if [ "$base_value" != "$head_value" ]; then
echo "Backward incompatibility change detected in $file. The value of key '$key' was changed from '$base_value' to '$head_value'."
@@ -64,4 +64,4 @@ jobs:
done
echo "All exporter JSON files have only additions. No backward incompatibility changes detected."
- shell: bash
+ shell: bash
\ No newline at end of file
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java
index 2944ee3f6c..72689244d3 100644
--- a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/form/FormConstants.java
@@ -142,4 +142,6 @@ private FormConstants() {
/* The resource type for the pre-selected the linked panel */
public final static String RT_FD_FORM_REVIEW_DATASOURCE_V1 = RT_FD_FORM_PREFIX + "review/v1/datasource";
+
+ public static final String RT_FD_FORM_PASSWORD_V1 = RT_FD_FORM_PREFIX + "password/v1/password";
}
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/PasswordImpl.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/PasswordImpl.java
new file mode 100644
index 0000000000..cca55ae28c
--- /dev/null
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/internal/models/v1/form/PasswordImpl.java
@@ -0,0 +1,90 @@
+/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2024 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+package com.adobe.cq.forms.core.components.internal.models.v1.form;
+
+import javax.annotation.Nullable;
+import javax.annotation.PostConstruct;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Exporter;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy;
+import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
+
+import com.adobe.cq.export.json.ComponentExporter;
+import com.adobe.cq.export.json.ExporterConstants;
+import com.adobe.cq.forms.core.components.internal.form.FormConstants;
+import com.adobe.cq.forms.core.components.models.form.FieldType;
+import com.adobe.cq.forms.core.components.models.form.Password;
+import com.adobe.cq.forms.core.components.util.AbstractFieldImpl;
+import com.adobe.cq.forms.core.components.util.ComponentUtils;
+
+@Model(
+ adaptables = { SlingHttpServletRequest.class, Resource.class },
+ adapters = { Password.class, ComponentExporter.class },
+ resourceType = { FormConstants.RT_FD_FORM_PASSWORD_V1 })
+@Exporter(
+ name = ExporterConstants.SLING_MODEL_EXPORTER_NAME,
+ extensions = ExporterConstants.SLING_MODEL_EXTENSION)
+public class PasswordImpl extends AbstractFieldImpl implements Password {
+
+ private Object exclusiveMinimumVaue;
+ private Object exclusiveMaximumValue;
+
+ @ValueMapValue(injectionStrategy = InjectionStrategy.OPTIONAL)
+ @Nullable
+ private String pattern;
+
+ @Override
+ public String getFieldType() {
+ return getFieldType(FieldType.PASSWORD);
+ }
+
+ @Override
+ public Integer getMinLength() {
+ return minLength;
+ }
+
+ @Override
+ public Integer getMaxLength() {
+ return maxLength;
+ }
+
+ @Override
+ public String getFormat() {
+ return displayFormat;
+ }
+
+ @Override
+ public String getPattern() {
+ return pattern;
+ }
+
+ @PostConstruct
+ private void initPassword() {
+ exclusiveMaximumValue = ComponentUtils.getExclusiveValue(exclusiveMaximum, maximum, null);
+ exclusiveMinimumVaue = ComponentUtils.getExclusiveValue(exclusiveMinimum, minimum, null);
+ // in json either, exclusiveMaximum or maximum should be present
+ if (exclusiveMaximumValue != null) {
+ maximum = null;
+ }
+ if (exclusiveMinimumVaue != null) {
+ minimum = null;
+ }
+ }
+}
diff --git a/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Password.java b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Password.java
new file mode 100644
index 0000000000..f97bf94926
--- /dev/null
+++ b/bundles/af-core/src/main/java/com/adobe/cq/forms/core/components/models/form/Password.java
@@ -0,0 +1,29 @@
+/**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2024 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+package com.adobe.cq.forms.core.components.models.form;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Interface for {@code Password} Sling Model used for the {@code /apps/core/fd/components/form/password/v1/password} component.
+ *
+ * @since com.adobe.cq.forms.core.components.models.form 5.11.0
+ */
+@ConsumerType
+public interface Password extends Field, StringConstraint {
+
+}
diff --git a/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/PasswordImplTest.java b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/PasswordImplTest.java
new file mode 100644
index 0000000000..c4b669e726
--- /dev/null
+++ b/bundles/af-core/src/test/java/com/adobe/cq/forms/core/components/internal/models/v1/form/PasswordImplTest.java
@@ -0,0 +1,176 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2024 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.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+package com.adobe.cq.forms.core.components.internal.models.v1.form;
+
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mockito;
+
+import com.adobe.cq.forms.core.Utils;
+import com.adobe.cq.forms.core.components.datalayer.FormComponentData;
+import com.adobe.cq.forms.core.components.internal.form.FormConstants;
+import com.adobe.cq.forms.core.components.models.form.FieldType;
+import com.adobe.cq.forms.core.components.models.form.Password;
+import com.adobe.cq.forms.core.context.FormsCoreComponentTestContext;
+import io.wcm.testing.mock.aem.junit5.AemContext;
+import io.wcm.testing.mock.aem.junit5.AemContextExtension;
+
+import static org.junit.Assert.assertEquals;
+
+@ExtendWith(AemContextExtension.class)
+public class PasswordImplTest {
+
+ private static final String BASE = "/form/password";
+ private static final String CONTENT_ROOT = "/content";
+ private static final String PATH_PASSWORD_DATALAYER = CONTENT_ROOT + "/password-datalayer";
+ private static final String PATH_PASSWORD_CUSTOMIZED = CONTENT_ROOT + "/password-customized";
+
+ private static final String PATH_PASSWORD = CONTENT_ROOT + "/password";
+
+ private static final String PATH_PASSWORD_PATTERN = CONTENT_ROOT + "/password-pattern";
+
+ private final AemContext context = FormsCoreComponentTestContext.newAemContext();
+
+ @BeforeEach
+ void setUp() {
+ context.load().json(BASE + FormsCoreComponentTestContext.TEST_CONTENT_JSON, CONTENT_ROOT);
+ }
+
+ @Test
+ void testExportedType() throws Exception {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(FormConstants.RT_FD_FORM_PASSWORD_V1, password.getExportedType());
+ Password passwordMock = Mockito.mock(Password.class);
+ Mockito.when(passwordMock.getExportedType()).thenCallRealMethod();
+ assertEquals("", passwordMock.getExportedType());
+ }
+
+ @Test
+ void testJSONExport() throws Exception {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_PATTERN, Password.class, context);
+ Utils.testJSONExport(password, Utils.getTestExporterJSONPath(BASE, PATH_PASSWORD));
+ }
+
+ @Test
+ void testFieldType() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(FieldType.PASSWORD.getValue(), password.getFieldType());
+ }
+
+ @Test
+ void testGetLabel() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals("pwd", password.getLabel().getValue());
+ }
+
+ @Test
+ void testPlaceholder() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals("Enter valid password", password.getPlaceHolder());
+ }
+
+ @Test
+ void testGetName() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals("password", password.getName());
+
+ }
+
+ @Test
+ void testDorProperties() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(true, password.getDorProperties().get("dorExclusion"));
+ assertEquals("4", password.getDorProperties().get("dorColspan"));
+ assertEquals("Text1", password.getDorProperties().get("dorBindRef"));
+
+ }
+
+ @Test
+ void testGetDescription() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals("password field", password.getDescription());
+ }
+
+ @Test
+ void testGetRequired() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(true, password.isRequired());
+ }
+
+ @Test
+ void testIsEnabled() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(true, password.isEnabled());
+ }
+
+ @Test
+ void testIsEnabledForCustomized() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(true, password.isEnabled());
+ }
+
+ @Test
+ void testIsReadOnly() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(false, password.isReadOnly());
+ }
+
+ @Test
+ void testIsReadOnlyForCustomized() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(false, password.isReadOnly());
+ }
+
+ @Test
+ void testMinLength() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(5, password.getMinLength().intValue());
+ }
+
+ @Test
+ void testMaxLength() {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals(10, password.getMaxLength().intValue());
+ }
+
+ @Test
+ void testGetDisplayFormat() throws Exception {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_CUSTOMIZED, Password.class, context);
+ assertEquals("password", password.getFormat());
+ }
+
+ @Test
+ void testGetPattern() throws Exception {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_PATTERN, Password.class, context);
+ assertEquals("^(?=.*\\d.*\\d)[A-Za-z\\d!@]+$", password.getPattern());
+ }
+
+ @Test
+ void testDataLayerProperties() throws IllegalAccessException {
+ Password password = Utils.getComponentUnderTest(PATH_PASSWORD_DATALAYER, Password.class, context);
+ FieldUtils.writeField(password, "dataLayerEnabled", true, true);
+ FormComponentData dataObject = (FormComponentData) password.getData();
+ assert (dataObject != null);
+ assert (dataObject.getId()).equals("password-1c7bc238a6");
+ assert (dataObject.getType()).equals("core/fd/components/form/password/v1/password");
+ assert (dataObject.getTitle()).equals("Full Name");
+ assert (dataObject.getFieldType()).equals("password");
+ assert (dataObject.getDescription()).equals("Enter Full Name");
+ }
+}
diff --git a/bundles/af-core/src/test/resources/form/password/exporter-password-customized.json b/bundles/af-core/src/test/resources/form/password/exporter-password-customized.json
new file mode 100644
index 0000000000..ff9c746dfc
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/password/exporter-password-customized.json
@@ -0,0 +1,43 @@
+{
+ "id": "password-477c777f4e",
+ "fieldType": "password",
+ "name": "password1708629052628",
+ "visible": true,
+ "description": "
long desc
\r\n",
+ "tooltip": "short desc
\r\n",
+ "type": "string",
+ "required": true,
+ "enabled": true,
+ "constraintMessages": {
+ "required": "Password is required",
+ "minLength": "min chars",
+ "maxLength": "max chars",
+ "pattern": "Invalid pwd"
+ },
+ "readOnly": false,
+ "minLength": 5,
+ "maxLength": 10,
+ "exclusiveMinimum" : 8,
+ "exclusiveMaximum" : 16,
+ "pattern": "/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/",
+ "label": {
+ "value": "Password",
+ "visible": true
+ },
+ "properties": {
+ "afs:layout": {
+ "tooltipVisible": false
+ },
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/password-customized"
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "placeholder": "Enter valid password",
+ ":type": "core/fd/components/form/password/v1/password"
+}
\ No newline at end of file
diff --git a/bundles/af-core/src/test/resources/form/password/exporter-password-datalayer.json b/bundles/af-core/src/test/resources/form/password/exporter-password-datalayer.json
new file mode 100644
index 0000000000..6dafe57656
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/password/exporter-password-datalayer.json
@@ -0,0 +1,38 @@
+{
+ "id": "password-1c7bc238a6",
+ "fieldType": "password",
+ "name": "password1732094911597",
+ "visible": true,
+ "description": "Enter Full Name",
+ "tooltip": "Full Name",
+ "type": "string",
+ "required": true,
+ "enabled": true,
+ "readOnly": false,
+ "label": {
+ "value": "Full Name"
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ "afs:layout": {
+ "tooltipVisible": false
+ },
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/password-datalayer"
+ },
+ ":type": "core/fd/components/form/password/v1/password",
+ "dataLayer": {
+ "password-1c7bc238a6": {
+ "dc:title": "Full Name",
+ "dc:description": "Enter Full Name",
+ "@type": "core/fd/components/form/password/v1/password",
+ "fieldType": "password"
+ }
+ }
+}
\ No newline at end of file
diff --git a/bundles/af-core/src/test/resources/form/password/exporter-password.json b/bundles/af-core/src/test/resources/form/password/exporter-password.json
new file mode 100644
index 0000000000..148a0b951e
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/password/exporter-password.json
@@ -0,0 +1,26 @@
+{
+ "id": "password-91417957c6",
+ "fieldType": "password",
+ "name": "password1732174214265",
+ "visible": true,
+ "type": "string",
+ "enabled": true,
+ "readOnly": false,
+ "pattern": "^(?=.*\\d.*\\d)[A-Za-z\\d!@]+$",
+ "label": {
+ "value": ""
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ ":type": "forms-components-examples/components/form/password",
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/password-pattern"
+ },
+ ":type": "nt:unstructured"
+}
\ No newline at end of file
diff --git a/bundles/af-core/src/test/resources/form/password/test-content.json b/bundles/af-core/src/test/resources/form/password/test-content.json
new file mode 100644
index 0000000000..8b85cd1773
--- /dev/null
+++ b/bundles/af-core/src/test/resources/form/password/test-content.json
@@ -0,0 +1,146 @@
+{
+ "password" : {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "name" : "abc",
+ "jcr:title" : "def",
+ "fieldType": "password"
+ },
+ "password-customized" : {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "name" : "password",
+ "jcr:title" : "pwd",
+ "hideTitle" : false,
+ "dorExclusion": true,
+ "dorColspan": "4",
+ "dorBindRef": "Text1",
+ "description" : "password field",
+ "visible" : false,
+ "readOnly": false,
+ "enabled": true,
+ "required": true,
+ "minLength": 5,
+ "maxLength": 10,
+ "displayFormat" : "password",
+ "assistPriority" : "custom",
+ "dataRef" : "a.b",
+ "custom" : "Custom screen reader text",
+ "typeMessage" : "incorrect type",
+ "tooltip": "test-short-description",
+ "placeholder": "Enter valid password",
+ "pattern": "/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/",
+ "default" : "password",
+ "fieldType": "password",
+ "label": {
+ "value": "Password",
+ "visible": true
+ }
+ },
+ "password-pattern" : {
+ "id": "password-91417957c6",
+ "fieldType": "password",
+ "name": "password1732174214265",
+ "visible": true,
+ "type": "string",
+ "enabled": true,
+ "constraintMessages": {
+ "pattern": "Enter valid password"
+ },
+ "readOnly": false,
+ "pattern": "^(?=.*\\d.*\\d)[A-Za-z\\d!@]+$",
+ "label": {
+ "visible": true,
+ "value": "Password"
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/forms/af/testcheckboaf2/jcr:content/guideContainer/password"
+ },
+ ":type": "forms-components-examples/components/form/password"
+ },
+
+ "password-format" : {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "name" : "abc",
+ "jcr:title" : "def",
+ "hideTitle" : false,
+ "description" : "dummy",
+ "visible" : false,
+ "assistPriority" : "custom",
+ "dataRef" : "a.b",
+ "custom" : "Custom screen reader text",
+ "typeMessage" : "incorrect type",
+ "tooltip": "test-short-description",
+ "default" : "abc",
+ "fieldType": "password",
+ "readOnly": false,
+ "enabled": true,
+ "displayFormat" : "password"
+ },
+ "password-datalayer" : {
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "id": "password-1c7bc238a6",
+ "fieldType": "password",
+ "name": "Full Name",
+ "jcr:title" : "Full Name",
+ "visible": true,
+ "description": "Enter Full Name",
+ "tooltip": "Full Name",
+ "type": "string",
+ "required": true,
+ "enabled": true,
+ "readOnly": false,
+ "label": {
+ "value": "Full Name"
+ },
+ "events": {
+ "custom:setProperty": [
+ "$event.payload"
+ ]
+ },
+ "properties": {
+ "afs:layout": {
+ "tooltipVisible": false
+ },
+ "fd:dor": {
+ "dorExclusion": false
+ },
+ "fd:path": "/content/forms/af/af2/jcr:content/guideContainer/password"
+ },
+ ":type": "forms-components-examples/components/form/password"
+ },
+ "password_unboundFormElement" : {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "name" : "abc",
+ "jcr:title" : "def",
+ "fieldType": "password",
+ "unboundFormElement": true,
+ "dataRef": "$.h"
+ },
+ "password-blank-dataref" : {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "name" : "abc",
+ "jcr:title" : "def",
+ "fieldType": "password",
+ "dataRef": ""
+ },
+ "password-blank-validationExpression" : {
+ "jcr:primaryType": "nt:unstructured",
+ "sling:resourceType" : "core/fd/components/form/password/v1/password",
+ "name" : "abc",
+ "jcr:title" : "def",
+ "fieldType": "password",
+ "validationExpression": ""
+ }
+}
diff --git a/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/clientlibs/forms-clientlib-site/styles/components/adaptive-form/password.less b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/clientlibs/forms-clientlib-site/styles/components/adaptive-form/password.less
new file mode 100644
index 0000000000..070e26a5da
--- /dev/null
+++ b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/clientlibs/forms-clientlib-site/styles/components/adaptive-form/password.less
@@ -0,0 +1,3 @@
+.cmp-adaptiveform-password {
+ .inputMixin();
+ }
\ No newline at end of file
diff --git a/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/password/.content.xml b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/password/.content.xml
new file mode 100644
index 0000000000..acb1cd0182
--- /dev/null
+++ b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/password/.content.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/password/_cq_template.xml b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/password/_cq_template.xml
new file mode 100644
index 0000000000..359c182ba3
--- /dev/null
+++ b/examples/ui.apps/src/main/content/jcr_root/apps/forms-components-examples/components/form/password/_cq_template.xml
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/ui.content/src/main/content/jcr_root/content/core-components-examples/library/adaptive-form/password/.content.xml b/examples/ui.content/src/main/content/jcr_root/content/core-components-examples/library/adaptive-form/password/.content.xml
new file mode 100644
index 0000000000..e97222c1be
--- /dev/null
+++ b/examples/ui.content/src/main/content/jcr_root/content/core-components-examples/library/adaptive-form/password/.content.xml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/password/.content.xml b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/password/.content.xml
new file mode 100644
index 0000000000..d738d26849
--- /dev/null
+++ b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/password/.content.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/password/basic/.content.xml b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/password/basic/.content.xml
new file mode 100644
index 0000000000..ef1113d23c
--- /dev/null
+++ b/it/content/src/main/content/jcr_root/content/dam/formsanddocuments/core-components-it/samples/password/basic/.content.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/password/.content.xml b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/password/.content.xml
new file mode 100644
index 0000000000..a0ac99e384
--- /dev/null
+++ b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/password/.content.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/password/basic/.content.xml b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/password/basic/.content.xml
new file mode 100644
index 0000000000..292ec6da0d
--- /dev/null
+++ b/it/content/src/main/content/jcr_root/content/forms/af/core-components-it/samples/password/basic/.content.xml
@@ -0,0 +1,251 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui.af.apps/pom.xml b/ui.af.apps/pom.xml
index 38362a2211..209df589d0 100644
--- a/ui.af.apps/pom.xml
+++ b/ui.af.apps/pom.xml
@@ -324,6 +324,7 @@
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
index 0ef50cf14f..4c45390ac7 100644
--- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/af-clientlibs/core-forms-components-runtime-all/.content.xml
@@ -5,4 +5,4 @@
cssProcessor="[default:none,min:none]"
jsProcessor="[default:none,min:none]"
categories="[core.forms.components.runtime.all]"
- embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime,core.forms.components.review.v1.runtime, core.forms.components.turnstile.v1.runtime]"/>
+ embed="[core.forms.components.runtime.base,core.forms.components.container.v2.runtime,core.forms.components.datePicker.v1.runtime,core.forms.components.textinput.v1.runtime,core.forms.components.numberinput.v1.runtime,core.forms.components.panelcontainer.v1.runtime,core.forms.components.radiobutton.v1.runtime,core.forms.components.text.v1.runtime,core.forms.components.checkboxgroup.v1.runtime,core.forms.components.button.v1.runtime,core.forms.components.image.v1.runtime,core.forms.components.dropdown.v1.runtime,core.forms.components.fileinput.v3.runtime,core.forms.components.accordion.v1.runtime,core.forms.components.tabs.v1.runtime,core.forms.components.wizard.v1.runtime,core.forms.components.verticaltabs.v1.runtime,core.forms.components.recaptcha.v1.runtime,core.forms.components.checkbox.v1.runtime,core.forms.components.fragment.v1.runtime,core.forms.components.switch.v1.runtime,core.forms.components.termsandconditions.v1.runtime, core.forms.components.hcaptcha.v1.runtime,core.forms.components.review.v1.runtime, core.forms.components.turnstile.v1.runtime, core.forms.components.password.v1.runtime]"/>
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/clientlibs/editorhook/js/replacehook.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/clientlibs/editorhook/js/replacehook.js
index 3e3ae98578..aa31facd66 100644
--- a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/clientlibs/editorhook/js/replacehook.js
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/container/v2/container/clientlibs/editorhook/js/replacehook.js
@@ -40,7 +40,8 @@
'plain-text': fieldTypes.NON_INPUT,
'title': fieldTypes.NON_INPUT,
'image': fieldTypes.NON_INPUT,
- 'panel': fieldTypes.CONTAINER
+ 'panel': fieldTypes.CONTAINER,
+ 'password' : fieldTypes.TEXT
}
const preservedProperties = ['id', 'description', 'enabled', 'jcr:created', 'jcr:title', 'name',
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/.content.xml
new file mode 100644
index 0000000000..491392d539
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/.content.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/.content.xml
new file mode 100644
index 0000000000..12d179732b
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/.content.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/.content.xml
new file mode 100644
index 0000000000..a2530d42b7
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/.content.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/README.md b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/README.md
new file mode 100644
index 0000000000..499db3745d
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/README.md
@@ -0,0 +1,98 @@
+
+Adaptive Form Password (v1)
+====
+Adaptive Form Password field component written in HTL.
+
+## Features
+
+* Provides the following type of input:
+ * password
+
+* Custom constraint messages for the above types
+* Styles
+* Allows replacing this component with other component (as mentioned below).
+
+### Use Object
+The Form Password component uses the `com.adobe.cq.forms.core.components.models.form.Password` Sling Model for its Use-object.
+
+### Edit Dialog Properties
+The following properties are written to JCR for this Form Password component and are expected to be available as `Resource` properties:
+
+1. `./jcr:title` - defines the label to use for this field
+2. `./hideTitle` - if set to `true`, the label of this field will be hidden
+3. `./name` - defines the name of the field, which will be submitted with the form data
+4. `./description` - defines a help message that can be rendered in the field as a hint for the user
+5. `./dataRef` - defines bind reference with model
+6. `./placeholder` - defines place holder for the field
+7. `./unboundFormElement` - defines if the field is unbound
+8. `./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
+9. `./requiredMessage` - defines the message displayed as tooltip when submitting the form if the value is left empty
+10. `./readOnly` - if set to `true`, the filed will be read only
+11. `./maxLength` - define maximum characters permitted
+12. `./minLength` - define minimum characters permitted
+13. `./maxLengthMessage` - define maximum characters of error message permitted
+14. `./pattern` - define regular expression permitted
+15. `./minLengthMessage` - define minimum characters of error message permitted
+16. `./validatePictureClauseMessage` - define error message if wrong pattern is entered.
+
+## Client Libraries
+The component provides a `core.forms.components.password.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.password.v1.editor` editor client library category that includes
+JavaScript handling for dialog interaction. It is already included by its edit dialog.
+
+## BEM Description
+```
+BLOCK cmp-adaptiveform-password
+ ELEMENT cmp-adaptiveform-password__label
+ ELEMENT cmp-adaptiveform-password__label-container
+ ELEMENT cmp-adaptiveform-password__widget
+ ELEMENT cmp-adaptiveform-password__questionmark
+ ELEMENT cmp-adaptiveform-password__shortdescription
+ ELEMENT cmp-adaptiveform-password__longdescription
+ ELEMENT cmp-adaptiveform-password__errormessage
+ ELEMENT cmp-adaptiveform-password__eyeicon
+ ELEMENT cmp-adaptiveform-password__input-wrapper
+```
+
+### Note
+By placing the class names `cmp-adaptiveform-password__label` and `cmp-adaptiveform-password__questionmark` within the `cmp-adaptiveform-password__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.
+
+## Replace feature:
+We support replace feature that allows replacing Password component to any of the below components:
+
+* Email Input
+* Number Input
+* Telephone Input
+* Text Box
+* Date Picker
+
+## JavaScript Data Attribute Bindings
+
+The following attributes must be added for the initialization of the password component in the form view:
+ 1. `data-cmp-is="adaptiveFormPassword"`
+ 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
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_design_dialog/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_design_dialog/.content.xml
new file mode 100644
index 0000000000..630ec0ff2e
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_design_dialog/.content.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_dialog/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_dialog/.content.xml
new file mode 100644
index 0000000000..409d2d1d93
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_dialog/.content.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_template.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_template.xml
new file mode 100644
index 0000000000..f5fbc5ecf6
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/_cq_template.xml
@@ -0,0 +1,4 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/.content.xml
new file mode 100644
index 0000000000..491392d539
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/.content.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/.content.xml
new file mode 100644
index 0000000000..9db59eb5c7
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/.content.xml
@@ -0,0 +1,5 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/js.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/js.txt
new file mode 100644
index 0000000000..8a845d07a4
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/js.txt
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright 2024 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
+editDialog.js
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/js/editDialog.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/js/editDialog.js
new file mode 100644
index 0000000000..66e54543a5
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/editor/js/editDialog.js
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright 2024 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";
+
+ var EDIT_DIALOG = ".cmp-adaptiveform-password__editdialog",
+ PASSWORD_MAXLENGTH = EDIT_DIALOG + " .cmp-adaptiveform-password__maxlength",
+ PASSWORD_MINLENGTH = EDIT_DIALOG + " .cmp-adaptiveform-password__minlength",
+ BASE_PLACEHOLDER = EDIT_DIALOG + " .cmp-adaptiveform-base__placeholder",
+ PASSWORD_VALUE = EDIT_DIALOG + " .cmp-adaptiveform-password__value",
+ PASSWORD_RICHTEXTVALUE = EDIT_DIALOG + " .cmp-adaptiveform-password__richtextvalue",
+ PASSWORD_VALIDATIONPATTERN = EDIT_DIALOG + " .cmp-adaptiveform-password__validationpattern",
+ PASSWORD_VALIDATIONFORMAT = EDIT_DIALOG + " .cmp-adaptiveform-password__validationformat",
+ Utils = window.CQ.FormsCoreComponents.Utils.v1;
+
+ function handleValidationPatternDropDown(dialog) {
+ Utils.handlePatternDropDown(dialog,PASSWORD_VALIDATIONPATTERN,PASSWORD_VALIDATIONFORMAT);
+ }
+
+ function handleValidationFormat(dialog){
+ Utils.handlePatternFormat(dialog,PASSWORD_VALIDATIONPATTERN,PASSWORD_VALIDATIONFORMAT);
+ }
+
+ Utils.initializeEditDialog(EDIT_DIALOG)(handleValidationPatternDropDown,handleValidationFormat);
+
+})(jQuery);
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/.content.xml b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/.content.xml
new file mode 100644
index 0000000000..50764aff9f
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/.content.xml
@@ -0,0 +1,6 @@
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/css.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/css.txt
new file mode 100644
index 0000000000..1e33d67d6c
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/css.txt
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright 2024 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=css
+passwordview.css
\ No newline at end of file
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/css/passwordview.css b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/css/passwordview.css
new file mode 100644
index 0000000000..5e3f0f91b1
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/css/passwordview.css
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright 2024 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.
+ ******************************************************************************/
+
+ .cmp-adaptiveform-password {
+
+ }
+
+ .cmp-adaptiveform-password__widget {
+
+ }
+ .cmp-adaptiveform-password__widget{
+
+ }
+
+ .cmp-adaptiveform-password__label {
+
+ }
+ .cmp-adaptiveform-password__label-container{
+
+ }
+
+ .cmp-adaptiveform-password__longdescription {
+ }
+
+ .cmp-adaptiveform-password__shortdescription {
+ }
+
+ .cmp-adaptiveform-password__questionmark {
+
+ }
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/js.txt b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/js.txt
new file mode 100644
index 0000000000..12d384898e
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/js.txt
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright 2024 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
+passwordview.js
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/js/passwordview.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/js/passwordview.js
new file mode 100644
index 0000000000..d4230f9ca6
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/clientlibs/site/js/passwordview.js
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright 2024 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 Password extends FormView.FormFieldBase {
+
+ 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 = "adaptiveFormPassword";
+ static bemBlock = 'cmp-adaptiveform-password'
+ static selectors = {
+ self: "[data-" + this.NS + '-is="' + this.IS + '"]',
+ widget: `.${Password.bemBlock}__widget`,
+ label: `.${Password.bemBlock}__label`,
+ description: `.${Password.bemBlock}__longdescription`,
+ qm: `.${Password.bemBlock}__questionmark`,
+ errorDiv: `.${Password.bemBlock}__errormessage`,
+ tooltipDiv: `.${Password.bemBlock}__shortdescription`,
+ eyeIcon: `.${Password.bemBlock}__eyeicon`
+ };
+
+ constructor(params) {
+ super(params);
+ }
+
+ getWidget() {
+ return this.element.querySelector(Password.selectors.widget);
+ }
+
+ getDescription() {
+ return this.element.querySelector(Password.selectors.description);
+ }
+
+ getLabel() {
+ return this.element.querySelector(Password.selectors.label);
+ }
+
+ getErrorDiv() {
+ return this.element.querySelector(Password.selectors.errorDiv);
+ }
+
+ getTooltipDiv() {
+ return this.element.querySelector(Password.selectors.tooltipDiv);
+ }
+
+ getQuestionMarkDiv() {
+ return this.element.querySelector(Password.selectors.qm);
+ }
+
+ getEyeIcon(){
+ return this.element.querySelector(Password.selectors.eyeIcon);
+ }
+
+ setModel(model) {
+ super.setModel(model);
+ if (this.widget.value !== '') {
+ this._model.value = this.widget.value;
+ }
+ this.widget.addEventListener('blur', (e) => {
+ this._model.value = e.target.value;
+ this.setInactive();
+ });
+ this.widget.addEventListener('focus', (e) => {
+ this.setActive();
+ });
+ this.getEyeIcon().addEventListener('click', (e) => {
+ this.#togglePasswordType();
+ });
+ }
+
+ #togglePasswordType() {
+ const widget = this.getWidget();
+ if (widget.value) {
+ const widget = this.getWidget();
+ if (widget.type === "password") {
+ widget.type = "text";
+ this.getEyeIcon().classList.add('open');
+ } else {
+ widget.type = "password";
+ this.getEyeIcon().classList.remove('open');
+ }
+ }
+ }
+ }
+
+ FormView.Utils.setupField(({element, formContainer}) => {
+ return new Password({element, formContainer})
+ }, Password.selectors.self);
+
+})();
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/password.html b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/password.html
new file mode 100644
index 0000000000..35776817fb
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/password.html
@@ -0,0 +1,57 @@
+
+
+
diff --git a/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/password.js b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/password.js
new file mode 100644
index 0000000000..dc33ea8b81
--- /dev/null
+++ b/ui.af.apps/src/main/content/jcr_root/apps/core/fd/components/form/password/v1/password/password.js
@@ -0,0 +1,34 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Copyright 2024 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";
+
+ return {
+ labelPath: labelPath,
+ shortDescriptionPath: shortDescriptionPath,
+ longDescriptionPath: longDescriptionPath,
+ questionMarkPath: questionMarkPath,
+ errorMessagePath: errorMessagePath,
+ clientlibs: clientlibsArr
+ }
+});
\ No newline at end of file
diff --git a/ui.frontend/src/constants.js b/ui.frontend/src/constants.js
index 04d6f8078e..a74dc91e20 100644
--- a/ui.frontend/src/constants.js
+++ b/ui.frontend/src/constants.js
@@ -374,6 +374,18 @@ export const Constants = {
* @memberof module:FormView~Constants
* @namespace FIELD_TYPE
*/
- FIELD_TYPE: FIELD_TYPE
+ FIELD_TYPE: FIELD_TYPE,
+
+ /**
+ * Html input type text
+ * @type {string}
+ */
+ HTML_INPUT_TYPE_TEXT : "text",
+
+ /**
+ * Html input type password
+ * @type {string}
+ */
+ HTML_INPUT_TYPE_PASSWORD : "password"
};
diff --git a/ui.tests/test-module/libs/commons/formsConstants.js b/ui.tests/test-module/libs/commons/formsConstants.js
index c511260f7a..cf2e1992fa 100644
--- a/ui.tests/test-module/libs/commons/formsConstants.js
+++ b/ui.tests/test-module/libs/commons/formsConstants.js
@@ -50,6 +50,7 @@ var formsConstants = {
"termsandconditions": "/apps/forms-components-examples/components/form/termsandconditions",
"submitButton": "/apps/forms-components-examples/components/form/actions/submit",
"review": "/apps/forms-components-examples/components/form/review",
+ "password": "/apps/forms-components-examples/components/form/password"
}
},
resourceType : {
diff --git a/ui.tests/test-module/specs/password/password.authoring.cy.js b/ui.tests/test-module/specs/password/password.authoring.cy.js
new file mode 100644
index 0000000000..a6e4552e99
--- /dev/null
+++ b/ui.tests/test-module/specs/password/password.authoring.cy.js
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2024 Adobe Systems Incorporated
+ *
+ * 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.
+ */
+
+const sitesSelectors = require('../../libs/commons/sitesSelectors'),
+ afConstants = require('../../libs/commons/formsConstants');
+
+/**
+ * Testing Password with Sites Editor
+ */
+describe('Page - Authoring', function () {
+ // we can use these values to log in
+
+ const dropPasswordInContainer = function () {
+ const dataPath = "/content/forms/af/core-components-it/blank/jcr:content/guideContainer/*",
+ responsiveGridDropZoneSelector = sitesSelectors.overlays.overlay.component + "[data-path='" + dataPath + "']";
+ cy.selectLayer("Edit");
+ cy.insertComponent(responsiveGridDropZoneSelector, "Adaptive Form Password Box", afConstants.components.forms.resourceType.password);
+ cy.get('body').click(0, 0);
+ }
+
+ const dropPasswordInSites = function () {
+ const dataPath = "/content/core-components-examples/library/adaptive-form/password/jcr:content/root/responsivegrid/demo/component/guideContainer/*",
+ responsiveGridDropZoneSelector = sitesSelectors.overlays.overlay.component + "[data-path='" + dataPath + "']";
+ cy.selectLayer("Edit");
+ cy.insertComponent(responsiveGridDropZoneSelector, "Adaptive Form Password Box", afConstants.components.forms.resourceType.password);
+ cy.get('body').click(0, 0);
+ }
+
+ const testPasswordBehaviour = function (passwordEditPathSelector, passwordDrop, isSites) {
+ if (isSites) {
+ dropPasswordInSites();
+ } else {
+ dropPasswordInContainer();
+ }
+ cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + passwordEditPathSelector);
+ cy.invokeEditableAction("[data-action='CONFIGURE']"); // this line is causing frame busting which is causing cypress to fail
+
+ // Checking some dynamic behaviours
+ cy.get(".cmp-adaptiveform-password__maxlength").invoke('css', 'display').should('equal', 'block');
+ cy.get(".cmp-adaptiveform-password__minlength").invoke('css', 'display').should('equal', 'block');
+ cy.get(".cmp-adaptiveform-base__placeholder").parent('div').invoke('css', 'display').should('equal', 'block');
+ cy.get('.cmp-adaptiveform-password__editdialog').contains('Validation').click({force: true}).then(() => {
+ cy.get("[name='./pattern']").should('have.length', 1);
+ cy.get("[name='./validatePictureClauseMessage']").should('have.length', 1);
+ cy.get('.cq-dialog-cancel').click();
+ cy.deleteComponentByPath(passwordDrop);
+ })
+ }
+
+ const testCopyPasteComponent = function (passwordEditPathSelector, passwordEditPathSelectorCopy, passwordDrop) {
+ dropPasswordInContainer();
+ cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + passwordEditPathSelector);
+ cy.invokeEditableAction("[data-action='CONFIGURE']"); // this line is causing frame busting which is causing cypress to fail
+ // Check If Dialog Options Are Visible
+ cy.get(".cmp-adaptiveform-base__editdialogbasic input[name='./name']")
+ .should("exist")
+ .should("be.visible");
+ cy.get(".cmp-adaptiveform-base__editdialogbasic input[name='./name']").focus().clear();
+ cy.get(".cmp-adaptiveform-base__editdialogbasic input[name='./name']").invoke('val', 'Password');
+ cy.get(".cmp-adaptiveform-base__editdialogbasic input[name='./name']").focus().type("{enter}");
+ cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + passwordEditPathSelector);
+ cy.invokeEditableAction("[data-action='COPY']");
+ const dataPath = "/content/forms/af/core-components-it/blank/jcr:content/guideContainer/*",
+ responsiveGridDropZoneSelector = sitesSelectors.overlays.overlay.component + "[data-path='" + dataPath + "']";
+ cy.openEditableToolbar(responsiveGridDropZoneSelector);
+ cy.invokeEditableAction("[data-action='PASTE']");
+ cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + passwordEditPathSelectorCopy);
+ cy.invokeEditableAction("[data-action='CONFIGURE']"); // this line is causing frame busting which is causing cypress to fail
+ // Check If Dialog Options Are Visible
+ cy.get(".cmp-adaptiveform-base__editdialogbasic [name='./name']")
+ .should("exist")
+ .should("have.value", "Password_copy_1");
+ cy.get("coral-dialog.is-open coral-dialog-footer button[variant='default']").click();
+ cy.deleteComponentByPath(passwordDrop);
+ cy.deleteComponentByPath(passwordDrop + "_copy");
+ }
+
+ const getRuleEditorIframe = () => {
+ // get the iframe > document > body
+ // and retry until the body element is not empty
+ return cy
+ .get('iframe#af-rule-editor')
+ .its('0.contentDocument.body').should('not.be.empty')
+ .then(cy.wrap)
+ }
+
+ context('Open Forms Editor', function () {
+ const pagePath = "/content/forms/af/core-components-it/blank",
+ passwordEditPath = pagePath + afConstants.FORM_EDITOR_FORM_CONTAINER_SUFFIX + "/password",
+ passwordEditPathSelector = "[data-path='" + passwordEditPath + "']",
+ passwordEditPathSelectorCopy = "[data-path='" + passwordEditPath + "_copy']",
+ passwordDrop = pagePath + afConstants.FORM_EDITOR_FORM_CONTAINER_SUFFIX + "/" + afConstants.components.forms.resourceType.password.split("/").pop();
+ beforeEach(function () {
+ // this is done since cypress session results in 403 sometimes
+ cy.openAuthoring(pagePath);
+ });
+
+ it('insert Password in form container', function () {
+ dropPasswordInContainer();
+ cy.deleteComponentByPath(passwordDrop);
+ });
+
+ it('open edit dialog of Password', function () {
+ testPasswordBehaviour(passwordEditPathSelector, passwordDrop);
+ })
+
+ it('pasted component should have unique name', function () {
+ testCopyPasteComponent(passwordEditPathSelector, passwordEditPathSelectorCopy, passwordDrop);
+ })
+ })
+
+ context('Open Sites Editor', function () {
+ const pagePath = "/content/core-components-examples/library/adaptive-form/password",
+ passwordEditPath = pagePath + afConstants.RESPONSIVE_GRID_DEMO_SUFFIX + "/guideContainer/password",
+ passwordInsideSitesContainerEditPath = pagePath + afConstants.RESPONSIVE_GRID_DEMO_SUFFIX + "/guideContainer/container/password_demo",
+ passwordEditPathSelector = "[data-path='" + passwordEditPath + "']",
+ passwordInsideSitesContainerEditPathSelector = "[data-path='" + passwordInsideSitesContainerEditPath + "']",
+ passwordDrop = pagePath + afConstants.RESPONSIVE_GRID_DEMO_SUFFIX + '/guideContainer/' + afConstants.components.forms.resourceType.password.split("/").pop();
+
+ beforeEach(function () {
+ cy.openAuthoring(pagePath);
+ });
+
+ it('insert aem forms Password', function () {
+ dropPasswordInSites();
+ cy.deleteComponentByPath(passwordDrop);
+ });
+
+ it('open edit dialog of aem forms Password', function() {
+ testPasswordBehaviour(passwordEditPathSelector, passwordDrop, true);
+ });
+
+ it('Test z-index of Rule editor iframe', function () {
+ dropPasswordInSites();
+ cy.openSidePanelTab("Content Tree");
+ cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + passwordEditPathSelector);
+ cy.invokeEditableAction("[data-action='editexpression']");
+ cy.get("#af-rule-editor").should("be.visible");
+ cy.get("#af-rule-editor")
+ .invoke("css", "z-index")
+ .should("equal", '10');
+ getRuleEditorIframe().find("#objectNavigationTree").should("be.visible");
+ getRuleEditorIframe().find("#create-rule-button").should("be.visible");
+ cy.wait(1000)
+ getRuleEditorIframe().find(".exp-Close-Button").should("be.visible").click();
+ cy.deleteComponentByPath(passwordDrop);
+ });
+
+ it('Test z-index of Rule editor iframe for components inside site container', function () {
+ cy.openSidePanelTab("Content Tree");
+ cy.openEditableToolbar(sitesSelectors.overlays.overlay.component + passwordInsideSitesContainerEditPathSelector);
+ cy.invokeEditableAction("[data-action='editexpression']");
+ cy.get("#af-rule-editor").should("be.visible");
+ cy.get("#af-rule-editor")
+ .invoke("css", "z-index")
+ .should("equal", '10');
+ getRuleEditorIframe().find("#objectNavigationTree").should("be.visible");
+ getRuleEditorIframe().find("#objectNavigationTree " + passwordInsideSitesContainerEditPathSelector).should("be.visible");
+ getRuleEditorIframe().find("#create-rule-button").should("be.visible");
+ cy.wait(1000);
+ getRuleEditorIframe().find(".exp-Close-Button").should("be.visible").click();
+ });
+ });
+});
diff --git a/ui.tests/test-module/specs/password/password.runtime.cy.js b/ui.tests/test-module/specs/password/password.runtime.cy.js
new file mode 100644
index 0000000000..7163223cf1
--- /dev/null
+++ b/ui.tests/test-module/specs/password/password.runtime.cy.js
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright 2024 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 Password", () => {
+
+ before(() => {
+ cy.attachConsoleErrorSpy();
+ });
+
+ const pagePath = "content/forms/af/core-components-it/samples/password/basic.html"
+ const bemBlock = 'cmp-adaptiveform-password'
+ const IS = "adaptiveFormPassword"
+ const selectors = {
+ password : `[data-cmp-is="${IS}"]`
+ }
+
+ let formContainer = null;
+
+ /**
+ * initialization of form container before every test
+ * */
+ 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 ? "" : "not."}have.attr`;
+ const value = state.value == null ? '' : 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(passDisabledAttributeCheck, 'disabled');
+ cy.get('input').should('have.value', value)
+ });
+ }
+
+ 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]) => {
+ if(field.options.visible === "true") {
+ expect(field.getId()).to.equal(id)
+ expect(formContainer._model.getElement(id), `model and view are in sync`).to.equal(field.getModel())
+ checkHTML(id, field.getModel().getState())
+ }
+ });
+ cy.expectNoConsoleErrors();
+ })
+
+ it(" model's changes are reflected in the html ", () => {
+ const [id, passwordfieldView] = Object.entries(formContainer._fields)[0]
+ const model = formContainer._model.getElement(id)
+ model.value = "some other value"
+ checkHTML(model.id, model.getState()).then(() => {
+ model.visible = false
+ return checkHTML(model.id, model.getState())
+ }).then(() => {
+ model.enabled = false
+ return checkHTML(model.id, model.getState())
+ })
+ cy.expectNoConsoleErrors();
+ });
+
+ it(" html changes are reflected in model ", () => {
+ const [id, password1fieldView] = Object.entries(formContainer._fields)[0]
+ const model = formContainer._model.getElement(id)
+ const input = "value"
+ cy.get(`#${id}`).find("input").clear().type(input).blur().then(x => {
+ expect(model.getState().value).to.equal(input)
+ })
+ cy.expectNoConsoleErrors();
+ });
+
+ it("should toggle description and tooltip", () => {
+ cy.toggleDescriptionTooltip(bemBlock, 'tooltip_scenario_test');
+ })
+
+ it("should show and hide other fields on a certain input", () => {
+ // Rule on passwordbox1: When passwordbox1 has input "Adobe@123" => Show passwordbox3 and Hide passwordbox2
+
+ const [passwordbox1, passwordbox1FieldView] = Object.entries(formContainer._fields)[0];
+ const [passwordbox2, passwordbox2FieldView] = Object.entries(formContainer._fields)[1];
+ const [passwordbox3, passwordbox3FieldView] = Object.entries(formContainer._fields)[2];
+ const input = "Adobe@123";
+
+ cy.get(`#${passwordbox1}`).find("input").clear().type(input).blur().then(x => {
+ cy.get(`#${passwordbox3}`).should('be.visible')
+ cy.get(`#${passwordbox2}`).should('not.be.visible')
+ })
+ cy.expectNoConsoleErrors();
+ })
+
+ it("should enable and disable other textfields on a certain string input", () => {
+ // Rule on passwordbox1: When passwordbox1 has input "Aem@123" => Enable passwordbox2 and Disable passwordbox4
+
+ const [passwordbox1, passwordbox1FieldView] = Object.entries(formContainer._fields)[0];
+ const [passwordbox2, passwordbox2FieldView] = Object.entries(formContainer._fields)[1];
+ const [passwordbox4, passwordbox4FieldView] = Object.entries(formContainer._fields)[3];
+ const input = "Aem@123";
+
+ cy.get(`#${passwordbox1}`).find("input").clear().type(input).blur().then(x => {
+ cy.get(`#${passwordbox2}`).find("input").should('be.enabled')
+ cy.get(`#${passwordbox4}`).find("input").should('not.be.enabled')
+ })
+ cy.expectNoConsoleErrors();
+ })
+
+ it("should set and clear value based on rules", () => {
+ // Rule on passwordbox5: When input of passwordbox5 is "Aemforms@123", set value of passwordbox1 to "new password" and clear value of passwordbox4
+
+ const [passwordbox1, passwordbox1FieldView] = Object.entries(formContainer._fields)[0];
+ const [passwordbox4, passwordbox4FieldView] = Object.entries(formContainer._fields)[3];
+ const [passwordbox5, passwordbox5FieldView] = Object.entries(formContainer._fields)[4];
+
+ const input = "Aemforms@123";
+ // cy.get(`#${passwordbox4}`).find("input").clear().type("this must be cleared")
+ cy.get(`#${passwordbox5}`).find("input").clear().type(input).blur().then(x => {
+ cy.get(`#${passwordbox4}`).find("input").should('have.value',"")
+ cy.get(`#${passwordbox1}`).find("input").should('have.value', "new password")
+ })
+ cy.expectNoConsoleErrors();
+ })
+
+ it("should show required error message on blur when field is empty", () =>{
+ const [passwordbox6, passwordbox6FieldView] = Object.entries(formContainer._fields)[5];
+ cy.get(`#${passwordbox6}`).find("input").clear().focus().blur().then(x => {
+ cy.get(`#${passwordbox6}`).find(".cmp-adaptiveform-password__errormessage").should('have.text',"Please fill in this field.")
+ })
+ })
+
+ 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", "cmp-adaptiveform-password");
+ })
+
+ })
+
+ it("should show required error message on entering wrong validation pattern of password", () =>{
+ const [passwordbox11, passwordbox11FieldView] = Object.entries(formContainer._fields)[10];
+ cy.get(`#${passwordbox11}`).find("input").clear().type(1).blur().then(x => {
+ cy.get(`#${passwordbox11}`).find(".cmp-adaptiveform-password__errormessage").should('have.text',"Please enter valid password")
+ })
+ })
+})
+