From 92c1b7a28b9d790ea826b18afc89ff93f6e4008c Mon Sep 17 00:00:00 2001 From: ddariod Date: Fri, 26 Dec 2025 17:22:44 -0500 Subject: [PATCH 01/19] retrieve styleProperties per contentlet --- .../velocity/services/PageRenderUtil.java | 22 +++++++++++++++++++ .../factories/PersonalizedContentlet.java | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java index 90f522b35417..3bf9e9609d84 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java @@ -321,6 +321,7 @@ private List populateContainers() throws DotDataException, DotSecu this.widgetPreExecute(contentlet); this.addAccrueTags(contentlet); this.addRelationships(contentlet); + this.addStyles(contentlet, personalizedContentlet); if (personalizedContentlet.getPersonalization().equals(includeContentFor)) { @@ -525,6 +526,27 @@ private void widgetPreExecute(final Contentlet contentlet) { } } + /** + * Adds style properties from the MultiTree to the contentlet's data map. + * This ensures that contentlet styling metadata is properly scoped to its specific + * personalization and variant context. + * + * @param contentlet The {@link Contentlet} to add style properties to + * @param personalizedContentlet The {@link PersonalizedContentlet} containing the style + * properties from the MultiTree relationship + */ + private void addStyles(Contentlet contentlet, PersonalizedContentlet personalizedContentlet) { + if (!Config.getBooleanProperty("FEATURE_FLAG_UVE_STYLE_EDITOR", false)) { + return; + } + + final Map styleProperties = personalizedContentlet.getStyleProperties(); + + if (UtilMethods.isSet(styleProperties) && !styleProperties.isEmpty()) { + contentlet.getMap().put("styleProperties", styleProperties); + } + } + private boolean needParseContainerPrefix(final Container container, final String uniqueId) { return !ParseContainer.isParserContainerUUID(uniqueId) && (templateLayout == null || !templateLayout.existsContainer(container, uniqueId)); diff --git a/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java b/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java index 0f33202f96b5..ff084308b214 100644 --- a/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java +++ b/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java @@ -44,6 +44,10 @@ public Object getTreeOrder() { return treeOrder; } + public Map getStyleProperties() { + return styleProperties; + } + @Override public boolean equals(Object o) { if (this == o) return true; From a0e809cbfa872c2a53b20dba11190f9282c64919 Mon Sep 17 00:00:00 2001 From: ddariod Date: Tue, 30 Dec 2025 09:51:48 -0500 Subject: [PATCH 02/19] create postman collection for test style definition --- ...ts_StyleProperties.postman_collection.json | 1351 +++++++++++++++++ .../resources/postman/PagesResourceTests.json | 232 --- 2 files changed, 1351 insertions(+), 232 deletions(-) create mode 100644 dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json new file mode 100644 index 000000000000..7cc105facfa5 --- /dev/null +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -0,0 +1,1351 @@ +{ + "info": { + "_postman_id": "18ac1393-80ec-4fd1-a4aa-664e8a22ea20", + "name": "Define StyleProperties for Contentlets", + "description": "## Description:\n\nThis collection validates the application of Style Properties to **Contentlets** based on their **location**.\n\nSince a Contentlet is always hosted within a **Container**, and a **Page** can have multiple Containers, you can define unique styles for the exact same Contentlet if:\n\n1. The Contentlet is placed in a different Container.\n \n2. The Contentlet and its Container appear on a different Page.\n \n\nInside are three sub folders:\n\n### Setup\n\nDefines the base data needed for the tests.\n\n### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the **Test Page 1**.\n\n### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "24818383" + }, + "item": [ + { + "name": "Setup", + "item": [ + { + "name": "Get default site", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "", + " var jsonData = pm.response.json();", + " pm.collectionVariables.set(\"hostname\", jsonData.entity.hostname);", + " pm.collectionVariables.set(\"hostIdentifier\", jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/site/defaultSite", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "site", + "defaultSite" + ] + } + }, + "response": [] + }, + { + "name": "Create Test Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Page created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"pageIdentifier\", jsonData.entity.identifier);", + " pm.collectionVariables.set(\"pageName\", jsonData.entity.name);", + " pm.collectionVariables.set(\"pagePath\", jsonData.entity.path);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_1_{{$timestamp}}\",\n \"url\":\"testPageStyles_1_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates a test page" + }, + "response": [] + }, + { + "name": "Create Test Page 2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Page created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"pageIdentifier2\", jsonData.entity.identifier);", + " pm.collectionVariables.set(\"pageName2\", jsonData.entity.name);", + " pm.collectionVariables.set(\"pagePath2\", jsonData.entity.path);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_2_{{$timestamp}}\",\n \"url\":\"testPageStyles_2_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_2_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates a test page" + }, + "response": [] + }, + { + "name": "Create Test Content Type", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Store first content type ID\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.entity).to.not.be.null;", + " pm.expect(jsonData.entity[0]).to.not.be.null;", + " pm.expect(jsonData.entity[0].id).to.not.be.null;", + " pm.collectionVariables.set(\"contentType1Id\", jsonData.entity[0].id);", + " pm.collectionVariables.set(\"contentType1VarName\", jsonData.entity[0].variable);", + " console.log('First content type created with ID:', jsonData.entity[0].id);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"defaultType\": false,\n \"name\": \"Styles_Test_ContentType_{{$timestamp}}\",\n \"description\": \"First content type for page tests\",\n \"host\": \"{{hostname}}\",\n \"owner\": \"dotcms.org.1\",\n \"fixed\": false,\n \"system\": false,\n \"folder\": \"SYSTEM_FOLDER\",\n \"fields\": [\n {\n \"dataType\": \"SYSTEM\",\n \"dbColumn\": \"system_field1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableHostFolderField\",\n \"indexed\": true,\n \"listed\": false,\n \"name\": \"Host/Folder\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 1,\n \"unique\": false,\n \"variable\": \"hostfolder\"\n },\n {\n \"dataType\": \"TEXT\",\n \"dbColumn\": \"text1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"indexed\": true,\n \"listed\": true,\n \"name\": \"title\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 2,\n \"unique\": false,\n \"variable\": \"title\"\n }\n ],\n \"workflow\": [\"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/contenttype", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "contenttype" + ] + } + }, + "response": [] + }, + { + "name": "Create Container", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Store container information\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.entity).to.not.be.null;", + " pm.expect(jsonData.entity.identifier).to.not.be.null;", + " pm.collectionVariables.set(\"containerId\", jsonData.entity.identifier);", + " console.log('Container created with ID:', jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"title\": \"Styles_Container_{{$timestamp}}\",\n \"friendlyName\": \"Container for style properties content type tests\",\n \"maxContentlets\": 25,\n \"code\": \"
\\n#foreach($contentlet in $contents)\\n

$contentlet.title

\\n#end\\n
\",\n \"preLoop\": \"
\",\n \"postLoop\": \"
\",\n \"containerStructures\": [\n {\n \"structureId\": \"{{contentType1Id}}\",\n \"code\": \"
\\n

$title

\\n
\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/containers", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "containers" + ] + } + }, + "response": [] + }, + { + "name": "Create Test Contentlet 1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Rich Text created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_1\", jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 1\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates test data" + }, + "response": [] + }, + { + "name": "Create Test Contentlet 2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Rich Text created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_2\", jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 2\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates test data" + }, + "response": [] + } + ], + "description": "### Setup\n\nDefines the base data needed along the other tests.\n\n- Create two Pages for testing\n \n - testPageStyles_1\n \n - testPageStyles_2\n \n- Create a Content Type `Styles_Test_ContentType` that requires `hostfolder` and `title` fields.\n \n- Create a custom Container `Styles_Container` that only accepts the content type`Styles_Test_ContentType`\n \n- Create 2 Contentlets with `hostfolder` and `title` fields.\n \n - Contentlet 1\n \n - Contentlet 2" + }, + { + "name": "Defining Contentlet Styles", + "item": [ + { + "name": "Save Content With Basic Styles", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const contentlet2 = pm.collectionVariables.get(\"Contentlet_2\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Entity array exists\", function () {", + " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(\"No errors returned\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "// ============================", + "// Validate first merged entry", + "// ============================", + "pm.test(\"First entry has correct styleProperties\", function () {", + " const first = json.entity.find(item => item.contentletId === contentlet1);", + " pm.expect(first).to.exist;", + " pm.expect(first.styleProperties).to.be.an(\"object\");", + " pm.expect(first.styleProperties.width).to.eql(\"100px\");", + " pm.expect(first.styleProperties.color).to.eql(\"#FF0000\");", + " pm.expect(first.styleProperties.margin).to.eql(\"10px\");", + "});", + "", + "// ============================", + "// Validate second merged entry", + "// ============================", + "pm.test(\"Second entry has no style properties\", function () {", + " const second = json.entity.find(item => item.contentletId === contentlet2);", + " pm.expect(second).to.exist;", + " pm.expect(second.styleProperties).to.eql({});", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\",\n \"{{Contentlet_2}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\",\n \"color\": \"#FF0000\",\n \"margin\": \"10px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "Save Content With Complex Styles", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Entity array exists\", function () {", + " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + " const contentlet = json.entity.find(item => item.contentletId === contentlet1);", + " pm.expect(contentlet).to.exist;", + " pm.expect(contentlet.styleProperties).to.be.an(\"object\");", + " pm.expect(contentlet.styleProperties.height).to.eql(300);", + " pm.expect(contentlet.styleProperties.visible).to.be.true;", + "", + " // Deep styleProperties object", + " const styleLayout = contentlet.styleProperties.layout;", + " pm.expect(styleLayout).to.be.an(\"object\");", + " pm.expect(styleLayout.display).to.eql(\"flex\");", + " pm.expect(styleLayout.gap).to.eql(16);", + " pm.expect(styleLayout.alignItems).to.eql(\"center\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"height\": 300,\n \"visible\": true,\n \"layout\": {\n \"display\": \"flex\",\n \"gap\": 16,\n \"alignItems\": \"center\"\n }\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "BadRequest when Saving Content With Styles", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const contentlet2 = pm.collectionVariables.get(\"Contentlet_2\");", + "", + "pm.test(\"Status is 400\", function () {", + " pm.response.to.have.status(400);", + "});", + "", + "pm.test(\"Response is JSON\", function () {", + " pm.response.to.be.json;", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Error array exists\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(\"No styleProperties were saved\", function () {", + " pm.expect(json.entity).to.be.an(\"string\").that.is.empty;", + "});", + "", + "// ============================", + "// Validate first error cause is for INVALID_CONTENTLET_REFERENCE", + "// ============================", + "pm.test(\"First error failed with INVALID_CONTENTLET_REFERENCE\", function () {", + " const first = json.errors.find(item => item.contentletId === '7c9cb3a7-bb68');", + " pm.expect(first).to.exist;", + " pm.expect(first.errorCode).to.eql(\"INVALID_CONTENTLET_REFERENCE\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\",\n \"{{Contentlet_2}}\"\n ],\n \"styleProperties\": {\n \"7c9cb3a7-bb68\": {\n \"color\": \"#FF0000\"\n },\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "Save Styles for the same Content in different Container", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Entity array exists\", function () {", + " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(\"No errors returned\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "// ============================", + "// Validate SYSTEM_CONTAINER styles", + "// ============================", + "pm.test(\"SYSTEM_CONTAINER has width styleProperties\", function () {", + " const systemContainer = json.entity.find(item => item.containerId === \"SYSTEM_CONTAINER\");", + " pm.expect(systemContainer).to.exist;", + " pm.expect(systemContainer.contentletId).to.eql(contentlet1);", + " pm.expect(systemContainer.styleProperties.width).to.eql(\"100px\");", + "});", + "", + "// ============================", + "// Validate CUSTOM_CONTAINER styles", + "// ============================", + "pm.test(\"CUSTOM_CONTAINER has color styleProperties\", function () {", + " const customContainer = json.entity.find(item => item.containerId === CUSTOM_CONTAINER);", + " pm.expect(customContainer).to.exist;", + " pm.expect(customContainer.contentletId).to.eql(contentlet1);", + " pm.expect(customContainer.styleProperties.color).to.eql(\"#FF0000\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n },\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + } + ], + "description": "### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the `testPageStyles_1`.\n\n- Save Contentlets with Basic Styles\n \n - `Contentlet 1` with basic Style Properties\n \n - `Contentlet 2` without Styles\n \n- Save Contentlet with Complex Styles\n \n - `Contentlet 1` with deep object definition Style Properties\n \n- BadRequest trying to set Styles for a contentlet that does not exists, should fail.\n \n- Save Styles for the same Contentlet but in different Containers, each of them does not affect the other one.\n \n - `Contentlet 1` saved with \"width = 100px\" style value in the `SYSTEM_CONTAINER`\n \n - `Contentlet 1` saved with \"color = \"#FF0000\" style in the custom Container `Styles_Container`" + }, + { + "name": "Retrieve Contentlet Styles", + "item": [ + { + "name": "Turn on Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", + " const entity = json.entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Accept", + "value": "*/*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.9" + }, + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Origin", + "value": "http://localhost:8080" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Referer", + "value": "http://localhost:8080/c/portal/layout?p_l_id=1a87b81c-e7ec-4e5b-9218-b55790353f09&p_p_id=maintenance&p_p_action=0&&dm_rlout=1&r=1767059927087&in_frame=true&frame=detailFrame&container=true&angularCurrentPortlet=maintenance" + }, + { + "key": "Sec-Fetch-Dest", + "value": "empty" + }, + { + "key": "Sec-Fetch-Mode", + "value": "cors" + }, + { + "key": "Sec-Fetch-Site", + "value": "same-origin" + }, + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" + }, + { + "key": "sec-ch-ua", + "value": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "Cookie", + "value": "dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=7AE5078EDF76A883E1503838A62A9B4A; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDU5NTI4MDgyLCJzdWIiOiJNZlY2eU5RdG9zSitOTVBsMTVJcnJnPT0iLCJpYXQiOjE3NjcwNTk1MjgsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTQ1OTI4fQ._WBLaAADyuYyclVKqHeWU7SrUrau3QQV7yx6-wWRiaE" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"key\": \"FEATURE_FLAG_UVE_STYLE_EDITOR\",\n \"value\": \"true\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "" + ] + }, + "description": "Generated from cURL: curl 'http://localhost:8080/api/v1/system-table/' \\\n -H 'Accept: */*' \\\n -H 'Accept-Language: en-US,en;q=0.9' \\\n -H 'Cache-Control: no-cache' \\\n -H 'Connection: keep-alive' \\\n -H 'Content-Type: application/json' \\\n -b 'dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=7AE5078EDF76A883E1503838A62A9B4A; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDU5NTI4MDgyLCJzdWIiOiJNZlY2eU5RdG9zSitOTVBsMTVJcnJnPT0iLCJpYXQiOjE3NjcwNTk1MjgsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTQ1OTI4fQ._WBLaAADyuYyclVKqHeWU7SrUrau3QQV7yx6-wWRiaE' \\\n -H 'Origin: http://localhost:8080' \\\n -H 'Pragma: no-cache' \\\n -H 'Referer: http://localhost:8080/c/portal/layout?p_l_id=1a87b81c-e7ec-4e5b-9218-b55790353f09&p_p_id=maintenance&p_p_action=0&&dm_rlout=1&r=1767059927087&in_frame=true&frame=detailFrame&container=true&angularCurrentPortlet=maintenance' \\\n -H 'Sec-Fetch-Dest: empty' \\\n -H 'Sec-Fetch-Mode: cors' \\\n -H 'Sec-Fetch-Site: same-origin' \\\n -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \\\n -H 'sec-ch-ua: \"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"' \\\n -H 'sec-ch-ua-mobile: ?0' \\\n -H 'sec-ch-ua-platform: \"macOS\"' \\\n --data-raw '{\"key\":\"FEATURE_FLAG_UVE_STYLE_EDITOR\",\"value\":\"true\"}'" + }, + "response": [] + }, + { + "name": "Add Content in 1st Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Content added to Test Page successfuly\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Adds a single content to the created page" + }, + "response": [] + }, + { + "name": "Add Content in 2nd Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Content added to Test Page successfuly\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier2}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier2}}", + "content" + ] + }, + "description": "Adds a single content to the created page" + }, + "response": [] + }, + { + "name": "Get Styles for Contentlet1 in Page1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + " // filter by container", + " const container = json.entity.containers[CUSTOM_CONTAINER];", + " pm.expect(container, \"Container not found\").to.exist;", + " ", + " // filter by contentlet", + " const allContentlets = Object.values(container.contentlets).flat();", + " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet, \"Contentlet not found\").to.exist;", + " pm.expect(contentlet.styleProperties.color).to.eql(\"#FF0000\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.9" + }, + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Referer", + "value": "http://localhost:8080/dotAdmin/" + }, + { + "key": "Sec-Fetch-Dest", + "value": "empty" + }, + { + "key": "Sec-Fetch-Mode", + "value": "cors" + }, + { + "key": "Sec-Fetch-Site", + "value": "same-origin" + }, + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" + }, + { + "key": "sec-ch-ua", + "value": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "Cookie", + "value": "dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM" + } + ], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{pageName}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{pageName}}" + ] + }, + "description": "Generated from cURL: curl 'http://localhost:8080/api/v1/page/render/testPageStyles_1_1767065402?language_id=1&device_inode=&mId=edit&com.dotmarketing.persona.id=modes.persona.no.persona&mode=EDIT_MODE' \\\n -H 'Accept: application/json, text/plain, */*' \\\n -H 'Accept-Language: en-US,en;q=0.9' \\\n -H 'Cache-Control: no-cache' \\\n -H 'Connection: keep-alive' \\\n -b 'dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM' \\\n -H 'Pragma: no-cache' \\\n -H 'Referer: http://localhost:8080/dotAdmin/' \\\n -H 'Sec-Fetch-Dest: empty' \\\n -H 'Sec-Fetch-Mode: cors' \\\n -H 'Sec-Fetch-Site: same-origin' \\\n -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \\\n -H 'sec-ch-ua: \"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"' \\\n -H 'sec-ch-ua-mobile: ?0' \\\n -H 'sec-ch-ua-platform: \"macOS\"'" + }, + "response": [] + }, + { + "name": "Get Styles for Contentlet1 in Page2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + " // filter by container", + " const container = json.entity.containers[CUSTOM_CONTAINER];", + " pm.expect(container, \"Container not found\").to.exist;", + " ", + " // filter by contentlet", + " const allContentlets = Object.values(container.contentlets).flat();", + " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet, \"Contentlet not found\").to.exist;", + " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "Accept-Language", + "value": "en-US,en;q=0.9" + }, + { + "key": "Cache-Control", + "value": "no-cache" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Referer", + "value": "http://localhost:8080/dotAdmin/" + }, + { + "key": "Sec-Fetch-Dest", + "value": "empty" + }, + { + "key": "Sec-Fetch-Mode", + "value": "cors" + }, + { + "key": "Sec-Fetch-Site", + "value": "same-origin" + }, + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" + }, + { + "key": "sec-ch-ua", + "value": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"macOS\"" + }, + { + "key": "Cookie", + "value": "dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM" + } + ], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{pageName2}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{pageName2}}" + ] + }, + "description": "Generated from cURL: curl 'http://localhost:8080/api/v1/page/render/testPageStyles_1_1767065402?language_id=1&device_inode=&mId=edit&com.dotmarketing.persona.id=modes.persona.no.persona&mode=EDIT_MODE' \\\n -H 'Accept: application/json, text/plain, */*' \\\n -H 'Accept-Language: en-US,en;q=0.9' \\\n -H 'Cache-Control: no-cache' \\\n -H 'Connection: keep-alive' \\\n -b 'dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM' \\\n -H 'Pragma: no-cache' \\\n -H 'Referer: http://localhost:8080/dotAdmin/' \\\n -H 'Sec-Fetch-Dest: empty' \\\n -H 'Sec-Fetch-Mode: cors' \\\n -H 'Sec-Fetch-Site: same-origin' \\\n -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \\\n -H 'sec-ch-ua: \"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"' \\\n -H 'sec-ch-ua-mobile: ?0' \\\n -H 'sec-ch-ua-platform: \"macOS\"'" + }, + "response": [] + } + ], + "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + " const serverURL = pm.environment.get('serverURL'); // Get the server URL from the environment variable", + " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", + "", + "// If we are unable to get the JWT we need to generate a new one", + " if (!pm.environment.get('jwt')) {", + " const username = pm.environment.get(\"user\");", + " const password = pm.environment.get(\"password\");", + " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", + "", + "", + " const requestOptions = {", + " url: apiUrl,", + " method: \"POST\",", + " header: {", + " \"accept\": \"*/*\",", + " \"content-type\": \"application/json\",", + " \"Authorization\": `Basic ${basicAuth}`", + " },", + " body: {", + " mode: \"raw\",", + " raw: JSON.stringify({", + " \"expirationSeconds\": 7200,", + " \"userId\": \"dotcms.org.1\",", + " \"network\": \"0.0.0.0/0\",", + " \"claims\": {\"label\": \"postman-tests\"}", + " })", + " }", + " };", + "", + "", + " pm.sendRequest(requestOptions, function (err, response) {", + " if (err) {", + " console.log(err);", + " } else {", + " const jwt = response.json().entity.jwt;", + " pm.environment.set('jwt', jwt);", + " console.log(jwt);", + " }", + " });", + " }" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "hostname", + "value": "" + }, + { + "key": "hostIdentifier", + "value": "" + }, + { + "key": "pageIdentifier", + "value": "" + }, + { + "key": "pagePath", + "value": "" + }, + { + "key": "Contentlet_1", + "value": "" + }, + { + "key": "Contentlet_2", + "value": "" + }, + { + "key": "Contentlet_3", + "value": "" + }, + { + "key": "pageIdentifier2", + "value": "" + }, + { + "key": "pagePath2", + "value": "" + }, + { + "key": "contentType1Id", + "value": "" + }, + { + "key": "contentType1VarName", + "value": "" + }, + { + "key": "containerId", + "value": "" + }, + { + "key": "stylePropertiesBody", + "value": "" + }, + { + "key": "pageName", + "value": "" + }, + { + "key": "pageName2", + "value": "" + } + ] +} \ No newline at end of file diff --git a/dotcms-postman/src/main/resources/postman/PagesResourceTests.json b/dotcms-postman/src/main/resources/postman/PagesResourceTests.json index c2685969be2b..4c2ccf96bc44 100644 --- a/dotcms-postman/src/main/resources/postman/PagesResourceTests.json +++ b/dotcms-postman/src/main/resources/postman/PagesResourceTests.json @@ -3842,238 +3842,6 @@ "description": "This test is for when users make a request sending at the Body the same container and uuid diff times.\nThis will merge all those contentlets and save the page successfully." }, "response": [] - }, - { - "name": "Save Content With Style Properties", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"richContentIdentifier1\");", - "const contentlet2 = pm.collectionVariables.get(\"richContentIdentifier2\");", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"Entity array exists\", function () {", - " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", - "});", - "", - "pm.test(\"No errors returned\", function () {", - " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", - "});", - "", - "// ============================", - "// Validate first merged entry", - "// ============================", - "pm.test(\"First entry has correct styleProperties\", function () {", - " const first = json.entity.find(item => item.contentletId === contentlet1);", - " pm.expect(first).to.exist;", - " pm.expect(first.styleProperties).to.be.an(\"object\");", - " pm.expect(first.styleProperties.width).to.eql(\"100px\");", - " pm.expect(first.styleProperties.color).to.eql(\"#FF0000\");", - " pm.expect(first.styleProperties.margin).to.eql(\"10px\");", - "});", - "", - "// ============================", - "// Validate second merged entry", - "// ============================", - "pm.test(\"Second entry has no style properties\", function () {", - " const second = json.entity.find(item => item.contentletId === contentlet2);", - " pm.expect(second).to.exist;", - " pm.expect(second.styleProperties).to.eql({});", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "// Get dynamically created IDs", - "const contentlet1 = pm.collectionVariables.get('richContentIdentifier1');", - "const contentlet2 = pm.collectionVariables.get('richContentIdentifier2');", - "", - "// Build request body with style properties", - "const stylePropsMap = {};", - "stylePropsMap[contentlet1] = {", - " width: '100px',", - " color: '#FF0000',", - " margin: '10px'", - "};", - "", - "const requestBody = [", - " {", - " identifier: '//demo.dotcms.com/application/containers/default/',", - " uuid: '1',", - " contentletsId: [contentlet1],", - " styleProperties: stylePropsMap", - " },", - " {", - " identifier: '//demo.dotcms.com/application/containers/default/',", - " uuid: '1',", - " contentletsId: [contentlet2]", - " }", - "];", - "", - "pm.collectionVariables.set('stylePropertiesBody', JSON.stringify(requestBody));" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{{stylePropertiesBody}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/bec7b960-a8bf-4f14-a22b-0d94caf217f0/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "bec7b960-a8bf-4f14-a22b-0d94caf217f0", - "content" - ] - }, - "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." - }, - "response": [] - }, - { - "name": "BadRequest when Saving Content With Style Properties", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"richContentIdentifier1\");", - "const contentlet2 = pm.collectionVariables.get(\"richContentIdentifier2\");", - "", - "pm.test(\"Status is 400\", function () {", - " pm.response.to.have.status(400);", - "});", - "", - "pm.test(\"Response is JSON\", function () {", - " pm.response.to.be.json;", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"Error array exists\", function () {", - " pm.expect(json.errors).to.be.an(\"array\").that.is.not.empty;", - "});", - "", - "pm.test(\"No styleProperties were saved\", function () {", - " pm.expect(json.entity).to.be.an(\"string\").that.is.empty;", - "});", - "", - "// ============================", - "// Validate first error cause is for INVALID_CONTENTLET_REFERENCE", - "// ============================", - "pm.test(\"First error failed with INVALID_CONTENTLET_REFERENCE\", function () {", - " const first = json.errors.find(item => item.contentletId === '7c9cb3a7-bb68');", - " pm.expect(first).to.exist;", - " pm.expect(first.errorCode).to.eql(\"INVALID_CONTENTLET_REFERENCE\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "// Get dynamically created IDs", - "const contentlet1 = pm.collectionVariables.get('richContentIdentifier1');", - "const contentlet2 = pm.collectionVariables.get('richContentIdentifier2');", - "", - "// Build request body with style properties", - "const stylePropsMap = {", - " '7c9cb3a7-bb68': {", - " color: '#FF0000'", - " }", - "};", - "stylePropsMap[contentlet1] = {", - " with: '100px',", - " color: '#FF0000',", - " margin: '10px'", - "};", - "", - "const requestBody = [", - " {", - " identifier: '//demo.dotcms.com/application/containers/default/',", - " uuid: '1',", - " contentletsId: [contentlet1],", - " styleProperties: stylePropsMap", - " },", - " {", - " identifier: '//demo.dotcms.com/application/containers/default/',", - " uuid: '1',", - " contentletsId: [contentlet2]", - " }", - "];", - "", - "pm.collectionVariables.set('stylePropertiesBody', JSON.stringify(requestBody));" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{{stylePropertiesBody}}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/bec7b960-a8bf-4f14-a22b-0d94caf217f0/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "bec7b960-a8bf-4f14-a22b-0d94caf217f0", - "content" - ] - }, - "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." - }, - "response": [] } ], "description": " @Path(\"{pageId}/content\")", From 985ce7da059201a77865f569a2738b0395ee3d90 Mon Sep 17 00:00:00 2001 From: ddariod Date: Tue, 30 Dec 2025 09:52:29 -0500 Subject: [PATCH 03/19] add support for objects and arrays for style properties definition --- .../rest/api/v1/page/PageContainerForm.java | 80 +++++++++++++------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java index 7df73c007f1d..0290c8f9dcb0 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java @@ -84,35 +84,69 @@ public PageContainerForm deserialize(final JsonParser jsonParser, // Parse styleProperties for each contentlet (optional field) final JsonNode stylePropertiesNode = jsonElement.get(STYLE_PROPERTIES_ATTRIBUTE_NAME); - if (stylePropertiesNode != null && stylePropertiesNode.isObject()) { - stylePropertiesNode.fields().forEachRemaining(entry -> { - final String contentletId = entry.getKey(); - final JsonNode styleProps = entry.getValue(); - if (styleProps != null && styleProps.isObject()) { - final Map propsMap = new HashMap<>(); - styleProps.fields().forEachRemaining(prop -> { - final JsonNode propValue = prop.getValue(); - // Handle different JSON value types - if (propValue.isTextual()) { - propsMap.put(prop.getKey(), propValue.asText()); - } else if (propValue.isNumber()) { - propsMap.put(prop.getKey(), propValue.numberValue()); - } else if (propValue.isBoolean()) { - propsMap.put(prop.getKey(), propValue.asBoolean()); - } else { - propsMap.put(prop.getKey(), propValue.toString()); - } - }); - containerEntry.setStyleProperties(contentletId, propsMap); - } - }); - } + getStylePropertiesNode(stylePropertiesNode, containerEntry); entries.add(containerEntry); } return new PageContainerForm(entries, jsonNode.toString()); } + + /** + * Gets the style properties node from the JSON object. + * @param stylePropertiesNode The JSON node containing the style properties. + * @param containerEntry The container entry to set the style properties. + */ + private void getStylePropertiesNode(final JsonNode stylePropertiesNode, final ContainerEntry containerEntry) { + if (stylePropertiesNode != null && stylePropertiesNode.isObject()) { + stylePropertiesNode.fields().forEachRemaining(entry -> { + final String contentletId = entry.getKey(); + final JsonNode styleProps = entry.getValue(); + if (styleProps != null && styleProps.isObject()) { + final Map propsMap = new HashMap<>(); + styleProps.fields().forEachRemaining(prop -> { + final JsonNode propValue = prop.getValue(); + propsMap.put(prop.getKey(), convertJsonNodeToObject(propValue)); + }); + containerEntry.setStyleProperties(contentletId, propsMap); + } + }); + } + } + + /** + * Recursively converts a JsonNode to its corresponding Java object type. + * Handles all JSON types: primitives, objects, arrays, and null. + * + * @param node The JsonNode to convert + * @return The converted Java object (String, Number, Boolean, Map, List, or null) + */ + private Object convertJsonNodeToObject(final JsonNode node) { + if (node == null || node.isNull()) { + return null; + } else if (node.isBoolean()) { + return node.asBoolean(); + } else if (node.isInt()) { + return node.asInt(); + } else if (node.isLong()) { + return node.asLong(); + } else if (node.isDouble() || node.isFloat()) { + return node.asDouble(); + } else if (node.isArray()) { + final List list = new ArrayList<>(); + node.forEach(element -> list.add(convertJsonNodeToObject(element))); + return list; + } else if (node.isObject()) { + final Map map = new HashMap<>(); + node.fields().forEachRemaining(entry -> + map.put(entry.getKey(), convertJsonNodeToObject(entry.getValue())) + ); + return map; + } else { + // Fallback for any other type and String values + return node.asText(); + } + } } /** From c3c3f3b46471caedc3a82595505eee7353a7e599 Mon Sep 17 00:00:00 2001 From: ddariod Date: Tue, 30 Dec 2025 09:56:42 -0500 Subject: [PATCH 04/19] add comment. --- .../com/dotcms/rendering/velocity/services/PageRenderUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java index 3bf9e9609d84..bc97a233a71c 100644 --- a/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java +++ b/dotCMS/src/main/java/com/dotcms/rendering/velocity/services/PageRenderUtil.java @@ -527,6 +527,7 @@ private void widgetPreExecute(final Contentlet contentlet) { } /** + * Only applies when the FEATURE_FLAG_UVE_STYLE_EDITOR is enabled. * Adds style properties from the MultiTree to the contentlet's data map. * This ensures that contentlet styling metadata is properly scoped to its specific * personalization and variant context. From 6a89e42cef0ac517ec83c0f51b84b7b94b90c5f3 Mon Sep 17 00:00:00 2001 From: ddariod Date: Tue, 30 Dec 2025 10:44:59 -0500 Subject: [PATCH 05/19] add test when feature flag is not enabled --- ...ts_StyleProperties.postman_collection.json | 2624 ++++++++--------- 1 file changed, 1275 insertions(+), 1349 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 7cc105facfa5..0f1a7e669541 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -1,1351 +1,1277 @@ { - "info": { - "_postman_id": "18ac1393-80ec-4fd1-a4aa-664e8a22ea20", - "name": "Define StyleProperties for Contentlets", - "description": "## Description:\n\nThis collection validates the application of Style Properties to **Contentlets** based on their **location**.\n\nSince a Contentlet is always hosted within a **Container**, and a **Page** can have multiple Containers, you can define unique styles for the exact same Contentlet if:\n\n1. The Contentlet is placed in a different Container.\n \n2. The Contentlet and its Container appear on a different Page.\n \n\nInside are three sub folders:\n\n### Setup\n\nDefines the base data needed for the tests.\n\n### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the **Test Page 1**.\n\n### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined.", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "24818383" - }, - "item": [ - { - "name": "Setup", - "item": [ - { - "name": "Get default site", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "", - " var jsonData = pm.response.json();", - " pm.collectionVariables.set(\"hostname\", jsonData.entity.hostname);", - " pm.collectionVariables.set(\"hostIdentifier\", jsonData.entity.identifier);", - "});" - ], - "type": "text/javascript", - "packages": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{serverURL}}/api/v1/site/defaultSite", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "site", - "defaultSite" - ] - } - }, - "response": [] - }, - { - "name": "Create Test Page", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Page created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"pageIdentifier\", jsonData.entity.identifier);", - " pm.collectionVariables.set(\"pageName\", jsonData.entity.name);", - " pm.collectionVariables.set(\"pagePath\", jsonData.entity.path);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_1_{{$timestamp}}\",\n \"url\":\"testPageStyles_1_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "workflow", - "actions", - "default", - "fire", - "PUBLISH" - ], - "query": [ - { - "key": "indexPolicy", - "value": "WAIT_FOR" - } - ] - }, - "description": "Creates a test page" - }, - "response": [] - }, - { - "name": "Create Test Page 2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Page created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"pageIdentifier2\", jsonData.entity.identifier);", - " pm.collectionVariables.set(\"pageName2\", jsonData.entity.name);", - " pm.collectionVariables.set(\"pagePath2\", jsonData.entity.path);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_2_{{$timestamp}}\",\n \"url\":\"testPageStyles_2_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_2_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "workflow", - "actions", - "default", - "fire", - "PUBLISH" - ], - "query": [ - { - "key": "indexPolicy", - "value": "WAIT_FOR" - } - ] - }, - "description": "Creates a test page" - }, - "response": [] - }, - { - "name": "Create Test Content Type", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Store first content type ID\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.entity).to.not.be.null;", - " pm.expect(jsonData.entity[0]).to.not.be.null;", - " pm.expect(jsonData.entity[0].id).to.not.be.null;", - " pm.collectionVariables.set(\"contentType1Id\", jsonData.entity[0].id);", - " pm.collectionVariables.set(\"contentType1VarName\", jsonData.entity[0].variable);", - " console.log('First content type created with ID:', jsonData.entity[0].id);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"defaultType\": false,\n \"name\": \"Styles_Test_ContentType_{{$timestamp}}\",\n \"description\": \"First content type for page tests\",\n \"host\": \"{{hostname}}\",\n \"owner\": \"dotcms.org.1\",\n \"fixed\": false,\n \"system\": false,\n \"folder\": \"SYSTEM_FOLDER\",\n \"fields\": [\n {\n \"dataType\": \"SYSTEM\",\n \"dbColumn\": \"system_field1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableHostFolderField\",\n \"indexed\": true,\n \"listed\": false,\n \"name\": \"Host/Folder\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 1,\n \"unique\": false,\n \"variable\": \"hostfolder\"\n },\n {\n \"dataType\": \"TEXT\",\n \"dbColumn\": \"text1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"indexed\": true,\n \"listed\": true,\n \"name\": \"title\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 2,\n \"unique\": false,\n \"variable\": \"title\"\n }\n ],\n \"workflow\": [\"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"]\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/contenttype", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "contenttype" - ] - } - }, - "response": [] - }, - { - "name": "Create Container", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "pm.test(\"Store container information\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.entity).to.not.be.null;", - " pm.expect(jsonData.entity.identifier).to.not.be.null;", - " pm.collectionVariables.set(\"containerId\", jsonData.entity.identifier);", - " console.log('Container created with ID:', jsonData.entity.identifier);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "{{jwt}}", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"title\": \"Styles_Container_{{$timestamp}}\",\n \"friendlyName\": \"Container for style properties content type tests\",\n \"maxContentlets\": 25,\n \"code\": \"
\\n#foreach($contentlet in $contents)\\n

$contentlet.title

\\n#end\\n
\",\n \"preLoop\": \"
\",\n \"postLoop\": \"
\",\n \"containerStructures\": [\n {\n \"structureId\": \"{{contentType1Id}}\",\n \"code\": \"
\\n

$title

\\n
\"\n }\n ]\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/containers", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "containers" - ] - } - }, - "response": [] - }, - { - "name": "Create Test Contentlet 1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Rich Text created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"Contentlet_1\", jsonData.entity.identifier);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 1\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "workflow", - "actions", - "default", - "fire", - "PUBLISH" - ], - "query": [ - { - "key": "indexPolicy", - "value": "WAIT_FOR" - } - ] - }, - "description": "Creates test data" - }, - "response": [] - }, - { - "name": "Create Test Contentlet 2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Rich Text created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"Contentlet_2\", jsonData.entity.identifier);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "PUT", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 2\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "workflow", - "actions", - "default", - "fire", - "PUBLISH" - ], - "query": [ - { - "key": "indexPolicy", - "value": "WAIT_FOR" - } - ] - }, - "description": "Creates test data" - }, - "response": [] - } - ], - "description": "### Setup\n\nDefines the base data needed along the other tests.\n\n- Create two Pages for testing\n \n - testPageStyles_1\n \n - testPageStyles_2\n \n- Create a Content Type `Styles_Test_ContentType` that requires `hostfolder` and `title` fields.\n \n- Create a custom Container `Styles_Container` that only accepts the content type`Styles_Test_ContentType`\n \n- Create 2 Contentlets with `hostfolder` and `title` fields.\n \n - Contentlet 1\n \n - Contentlet 2" - }, - { - "name": "Defining Contentlet Styles", - "item": [ - { - "name": "Save Content With Basic Styles", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const contentlet2 = pm.collectionVariables.get(\"Contentlet_2\");", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"Entity array exists\", function () {", - " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", - "});", - "", - "pm.test(\"No errors returned\", function () {", - " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", - "});", - "", - "// ============================", - "// Validate first merged entry", - "// ============================", - "pm.test(\"First entry has correct styleProperties\", function () {", - " const first = json.entity.find(item => item.contentletId === contentlet1);", - " pm.expect(first).to.exist;", - " pm.expect(first.styleProperties).to.be.an(\"object\");", - " pm.expect(first.styleProperties.width).to.eql(\"100px\");", - " pm.expect(first.styleProperties.color).to.eql(\"#FF0000\");", - " pm.expect(first.styleProperties.margin).to.eql(\"10px\");", - "});", - "", - "// ============================", - "// Validate second merged entry", - "// ============================", - "pm.test(\"Second entry has no style properties\", function () {", - " const second = json.entity.find(item => item.contentletId === contentlet2);", - " pm.expect(second).to.exist;", - " pm.expect(second.styleProperties).to.eql({});", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\",\n \"{{Contentlet_2}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\",\n \"color\": \"#FF0000\",\n \"margin\": \"10px\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - }, - "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." - }, - "response": [] - }, - { - "name": "Save Content With Complex Styles", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"Entity array exists\", function () {", - " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", - "});", - "", - "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", - " const contentlet = json.entity.find(item => item.contentletId === contentlet1);", - " pm.expect(contentlet).to.exist;", - " pm.expect(contentlet.styleProperties).to.be.an(\"object\");", - " pm.expect(contentlet.styleProperties.height).to.eql(300);", - " pm.expect(contentlet.styleProperties.visible).to.be.true;", - "", - " // Deep styleProperties object", - " const styleLayout = contentlet.styleProperties.layout;", - " pm.expect(styleLayout).to.be.an(\"object\");", - " pm.expect(styleLayout.display).to.eql(\"flex\");", - " pm.expect(styleLayout.gap).to.eql(16);", - " pm.expect(styleLayout.alignItems).to.eql(\"center\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"height\": 300,\n \"visible\": true,\n \"layout\": {\n \"display\": \"flex\",\n \"gap\": 16,\n \"alignItems\": \"center\"\n }\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - }, - "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." - }, - "response": [] - }, - { - "name": "BadRequest when Saving Content With Styles", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const contentlet2 = pm.collectionVariables.get(\"Contentlet_2\");", - "", - "pm.test(\"Status is 400\", function () {", - " pm.response.to.have.status(400);", - "});", - "", - "pm.test(\"Response is JSON\", function () {", - " pm.response.to.be.json;", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"Error array exists\", function () {", - " pm.expect(json.errors).to.be.an(\"array\").that.is.not.empty;", - "});", - "", - "pm.test(\"No styleProperties were saved\", function () {", - " pm.expect(json.entity).to.be.an(\"string\").that.is.empty;", - "});", - "", - "// ============================", - "// Validate first error cause is for INVALID_CONTENTLET_REFERENCE", - "// ============================", - "pm.test(\"First error failed with INVALID_CONTENTLET_REFERENCE\", function () {", - " const first = json.errors.find(item => item.contentletId === '7c9cb3a7-bb68');", - " pm.expect(first).to.exist;", - " pm.expect(first.errorCode).to.eql(\"INVALID_CONTENTLET_REFERENCE\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\",\n \"{{Contentlet_2}}\"\n ],\n \"styleProperties\": {\n \"7c9cb3a7-bb68\": {\n \"color\": \"#FF0000\"\n },\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - }, - "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." - }, - "response": [] - }, - { - "name": "Save Styles for the same Content in different Container", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"Entity array exists\", function () {", - " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", - "});", - "", - "pm.test(\"No errors returned\", function () {", - " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", - "});", - "", - "// ============================", - "// Validate SYSTEM_CONTAINER styles", - "// ============================", - "pm.test(\"SYSTEM_CONTAINER has width styleProperties\", function () {", - " const systemContainer = json.entity.find(item => item.containerId === \"SYSTEM_CONTAINER\");", - " pm.expect(systemContainer).to.exist;", - " pm.expect(systemContainer.contentletId).to.eql(contentlet1);", - " pm.expect(systemContainer.styleProperties.width).to.eql(\"100px\");", - "});", - "", - "// ============================", - "// Validate CUSTOM_CONTAINER styles", - "// ============================", - "pm.test(\"CUSTOM_CONTAINER has color styleProperties\", function () {", - " const customContainer = json.entity.find(item => item.containerId === CUSTOM_CONTAINER);", - " pm.expect(customContainer).to.exist;", - " pm.expect(customContainer.contentletId).to.eql(contentlet1);", - " pm.expect(customContainer.styleProperties.color).to.eql(\"#FF0000\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n },\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - }, - "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." - }, - "response": [] - } - ], - "description": "### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the `testPageStyles_1`.\n\n- Save Contentlets with Basic Styles\n \n - `Contentlet 1` with basic Style Properties\n \n - `Contentlet 2` without Styles\n \n- Save Contentlet with Complex Styles\n \n - `Contentlet 1` with deep object definition Style Properties\n \n- BadRequest trying to set Styles for a contentlet that does not exists, should fail.\n \n- Save Styles for the same Contentlet but in different Containers, each of them does not affect the other one.\n \n - `Contentlet 1` saved with \"width = 100px\" style value in the `SYSTEM_CONTAINER`\n \n - `Contentlet 1` saved with \"color = \"#FF0000\" style in the custom Container `Styles_Container`" - }, - { - "name": "Retrieve Contentlet Styles", - "item": [ - { - "name": "Turn on Style Editor", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", - " const entity = json.entity;", - " pm.expect(entity).to.exist;", - " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [ - { - "key": "Accept", - "value": "*/*" - }, - { - "key": "Accept-Language", - "value": "en-US,en;q=0.9" - }, - { - "key": "Cache-Control", - "value": "no-cache" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Origin", - "value": "http://localhost:8080" - }, - { - "key": "Pragma", - "value": "no-cache" - }, - { - "key": "Referer", - "value": "http://localhost:8080/c/portal/layout?p_l_id=1a87b81c-e7ec-4e5b-9218-b55790353f09&p_p_id=maintenance&p_p_action=0&&dm_rlout=1&r=1767059927087&in_frame=true&frame=detailFrame&container=true&angularCurrentPortlet=maintenance" - }, - { - "key": "Sec-Fetch-Dest", - "value": "empty" - }, - { - "key": "Sec-Fetch-Mode", - "value": "cors" - }, - { - "key": "Sec-Fetch-Site", - "value": "same-origin" - }, - { - "key": "User-Agent", - "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" - }, - { - "key": "sec-ch-ua", - "value": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"" - }, - { - "key": "sec-ch-ua-mobile", - "value": "?0" - }, - { - "key": "sec-ch-ua-platform", - "value": "\"macOS\"" - }, - { - "key": "Cookie", - "value": "dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=7AE5078EDF76A883E1503838A62A9B4A; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDU5NTI4MDgyLCJzdWIiOiJNZlY2eU5RdG9zSitOTVBsMTVJcnJnPT0iLCJpYXQiOjE3NjcwNTk1MjgsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTQ1OTI4fQ._WBLaAADyuYyclVKqHeWU7SrUrau3QQV7yx6-wWRiaE" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"key\": \"FEATURE_FLAG_UVE_STYLE_EDITOR\",\n \"value\": \"true\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/system-table/", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "system-table", - "" - ] - }, - "description": "Generated from cURL: curl 'http://localhost:8080/api/v1/system-table/' \\\n -H 'Accept: */*' \\\n -H 'Accept-Language: en-US,en;q=0.9' \\\n -H 'Cache-Control: no-cache' \\\n -H 'Connection: keep-alive' \\\n -H 'Content-Type: application/json' \\\n -b 'dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=7AE5078EDF76A883E1503838A62A9B4A; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDU5NTI4MDgyLCJzdWIiOiJNZlY2eU5RdG9zSitOTVBsMTVJcnJnPT0iLCJpYXQiOjE3NjcwNTk1MjgsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTQ1OTI4fQ._WBLaAADyuYyclVKqHeWU7SrUrau3QQV7yx6-wWRiaE' \\\n -H 'Origin: http://localhost:8080' \\\n -H 'Pragma: no-cache' \\\n -H 'Referer: http://localhost:8080/c/portal/layout?p_l_id=1a87b81c-e7ec-4e5b-9218-b55790353f09&p_p_id=maintenance&p_p_action=0&&dm_rlout=1&r=1767059927087&in_frame=true&frame=detailFrame&container=true&angularCurrentPortlet=maintenance' \\\n -H 'Sec-Fetch-Dest: empty' \\\n -H 'Sec-Fetch-Mode: cors' \\\n -H 'Sec-Fetch-Site: same-origin' \\\n -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \\\n -H 'sec-ch-ua: \"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"' \\\n -H 'sec-ch-ua-mobile: ?0' \\\n -H 'sec-ch-ua-platform: \"macOS\"' \\\n --data-raw '{\"key\":\"FEATURE_FLAG_UVE_STYLE_EDITOR\",\"value\":\"true\"}'" - }, - "response": [] - }, - { - "name": "Add Content in 1st Page", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Content added to Test Page successfuly\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - }, - "description": "Adds a single content to the created page" - }, - "response": [] - }, - { - "name": "Add Content in 2nd Page", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Content added to Test Page successfuly\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier2}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier2}}", - "content" - ] - }, - "description": "Adds a single content to the created page" - }, - "response": [] - }, - { - "name": "Get Styles for Contentlet1 in Page1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", - " // filter by container", - " const container = json.entity.containers[CUSTOM_CONTAINER];", - " pm.expect(container, \"Container not found\").to.exist;", - " ", - " // filter by contentlet", - " const allContentlets = Object.values(container.contentlets).flat();", - " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", - " pm.expect(contentlet, \"Contentlet not found\").to.exist;", - " pm.expect(contentlet.styleProperties.color).to.eql(\"#FF0000\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json, text/plain, */*" - }, - { - "key": "Accept-Language", - "value": "en-US,en;q=0.9" - }, - { - "key": "Cache-Control", - "value": "no-cache" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "Pragma", - "value": "no-cache" - }, - { - "key": "Referer", - "value": "http://localhost:8080/dotAdmin/" - }, - { - "key": "Sec-Fetch-Dest", - "value": "empty" - }, - { - "key": "Sec-Fetch-Mode", - "value": "cors" - }, - { - "key": "Sec-Fetch-Site", - "value": "same-origin" - }, - { - "key": "User-Agent", - "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" - }, - { - "key": "sec-ch-ua", - "value": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"" - }, - { - "key": "sec-ch-ua-mobile", - "value": "?0" - }, - { - "key": "sec-ch-ua-platform", - "value": "\"macOS\"" - }, - { - "key": "Cookie", - "value": "dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM" - } - ], - "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{pageName}}", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "render", - "{{pageName}}" - ] - }, - "description": "Generated from cURL: curl 'http://localhost:8080/api/v1/page/render/testPageStyles_1_1767065402?language_id=1&device_inode=&mId=edit&com.dotmarketing.persona.id=modes.persona.no.persona&mode=EDIT_MODE' \\\n -H 'Accept: application/json, text/plain, */*' \\\n -H 'Accept-Language: en-US,en;q=0.9' \\\n -H 'Cache-Control: no-cache' \\\n -H 'Connection: keep-alive' \\\n -b 'dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM' \\\n -H 'Pragma: no-cache' \\\n -H 'Referer: http://localhost:8080/dotAdmin/' \\\n -H 'Sec-Fetch-Dest: empty' \\\n -H 'Sec-Fetch-Mode: cors' \\\n -H 'Sec-Fetch-Site: same-origin' \\\n -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \\\n -H 'sec-ch-ua: \"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"' \\\n -H 'sec-ch-ua-mobile: ?0' \\\n -H 'sec-ch-ua-platform: \"macOS\"'" - }, - "response": [] - }, - { - "name": "Get Styles for Contentlet1 in Page2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", - " // filter by container", - " const container = json.entity.containers[CUSTOM_CONTAINER];", - " pm.expect(container, \"Container not found\").to.exist;", - " ", - " // filter by contentlet", - " const allContentlets = Object.values(container.contentlets).flat();", - " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", - " pm.expect(contentlet, \"Contentlet not found\").to.exist;", - " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "GET", - "header": [ - { - "key": "Accept", - "value": "application/json, text/plain, */*" - }, - { - "key": "Accept-Language", - "value": "en-US,en;q=0.9" - }, - { - "key": "Cache-Control", - "value": "no-cache" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "Pragma", - "value": "no-cache" - }, - { - "key": "Referer", - "value": "http://localhost:8080/dotAdmin/" - }, - { - "key": "Sec-Fetch-Dest", - "value": "empty" - }, - { - "key": "Sec-Fetch-Mode", - "value": "cors" - }, - { - "key": "Sec-Fetch-Site", - "value": "same-origin" - }, - { - "key": "User-Agent", - "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" - }, - { - "key": "sec-ch-ua", - "value": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"" - }, - { - "key": "sec-ch-ua-mobile", - "value": "?0" - }, - { - "key": "sec-ch-ua-platform", - "value": "\"macOS\"" - }, - { - "key": "Cookie", - "value": "dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM" - } - ], - "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{pageName2}}", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "render", - "{{pageName2}}" - ] - }, - "description": "Generated from cURL: curl 'http://localhost:8080/api/v1/page/render/testPageStyles_1_1767065402?language_id=1&device_inode=&mId=edit&com.dotmarketing.persona.id=modes.persona.no.persona&mode=EDIT_MODE' \\\n -H 'Accept: application/json, text/plain, */*' \\\n -H 'Accept-Language: en-US,en;q=0.9' \\\n -H 'Cache-Control: no-cache' \\\n -H 'Connection: keep-alive' \\\n -b 'dmid=e4cdaf95-fcec-4d75-bd53-43fb7cd56949; opvc=16d47637-b215-46c7-9e60-6b14ea398840; sitevisitscookie=2; DWRSESSIONID=FJxrzjfq1ZqjuYizayPGb8ES7Jp; JSESSIONID=1CDC90FB491A3E4C132C3BEE939FC7A7; rme=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI3MTgxNjdjOC1jN2ZmLTQyYzAtOWY1MC1mMjdlMjI4NWU2ZTMiLCJ4bW9kIjoxNzY3MDY1NDUzNjI5LCJzdWIiOiJaTkZkTDZ5ZUp5MmsxYWFlN2Q2bDNRPT0iLCJpYXQiOjE3NjcwNjU0NTMsImlzcyI6ImRvdGNtcy1wcm9kdWN0aW9uIiwiZXhwIjoxNzY3MTUxODUzfQ.OB-8uCB7LuD0rl01wMbPVCTD7JUuqPbTjcUyffVAsUM' \\\n -H 'Pragma: no-cache' \\\n -H 'Referer: http://localhost:8080/dotAdmin/' \\\n -H 'Sec-Fetch-Dest: empty' \\\n -H 'Sec-Fetch-Mode: cors' \\\n -H 'Sec-Fetch-Site: same-origin' \\\n -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' \\\n -H 'sec-ch-ua: \"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"' \\\n -H 'sec-ch-ua-mobile: ?0' \\\n -H 'sec-ch-ua-platform: \"macOS\"'" - }, - "response": [] - } - ], - "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - " const serverURL = pm.environment.get('serverURL'); // Get the server URL from the environment variable", - " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", - "", - "// If we are unable to get the JWT we need to generate a new one", - " if (!pm.environment.get('jwt')) {", - " const username = pm.environment.get(\"user\");", - " const password = pm.environment.get(\"password\");", - " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", - "", - "", - " const requestOptions = {", - " url: apiUrl,", - " method: \"POST\",", - " header: {", - " \"accept\": \"*/*\",", - " \"content-type\": \"application/json\",", - " \"Authorization\": `Basic ${basicAuth}`", - " },", - " body: {", - " mode: \"raw\",", - " raw: JSON.stringify({", - " \"expirationSeconds\": 7200,", - " \"userId\": \"dotcms.org.1\",", - " \"network\": \"0.0.0.0/0\",", - " \"claims\": {\"label\": \"postman-tests\"}", - " })", - " }", - " };", - "", - "", - " pm.sendRequest(requestOptions, function (err, response) {", - " if (err) {", - " console.log(err);", - " } else {", - " const jwt = response.json().entity.jwt;", - " pm.environment.set('jwt', jwt);", - " console.log(jwt);", - " }", - " });", - " }" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "hostname", - "value": "" - }, - { - "key": "hostIdentifier", - "value": "" - }, - { - "key": "pageIdentifier", - "value": "" - }, - { - "key": "pagePath", - "value": "" - }, - { - "key": "Contentlet_1", - "value": "" - }, - { - "key": "Contentlet_2", - "value": "" - }, - { - "key": "Contentlet_3", - "value": "" - }, - { - "key": "pageIdentifier2", - "value": "" - }, - { - "key": "pagePath2", - "value": "" - }, - { - "key": "contentType1Id", - "value": "" - }, - { - "key": "contentType1VarName", - "value": "" - }, - { - "key": "containerId", - "value": "" - }, - { - "key": "stylePropertiesBody", - "value": "" - }, - { - "key": "pageName", - "value": "" - }, - { - "key": "pageName2", - "value": "" - } - ] + "info": { + "_postman_id": "7e70edc5-b319-4d3f-b332-0c6c17d303ff", + "name": "Define StyleProperties for Contentlets", + "description": "## Description:\n\nThis collection validates the application of Style Properties to **Contentlets** based on their **location**.\n\nSince a Contentlet is always hosted within a **Container**, and a **Page** can have multiple Containers, you can define unique styles for the exact same Contentlet if:\n\n1. The Contentlet is placed in a different Container.\n \n2. The Contentlet and its Container appear on a different Page.\n \n\nInside are three sub folders:\n\n### Setup\n\nDefines the base data needed for the tests.\n\n### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the **Test Page 1**.\n\n### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "24818383" + }, + "item": [ + { + "name": "Setup", + "item": [ + { + "name": "Get default site", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "", + " var jsonData = pm.response.json();", + " pm.collectionVariables.set(\"hostname\", jsonData.entity.hostname);", + " pm.collectionVariables.set(\"hostIdentifier\", jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/site/defaultSite", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "site", + "defaultSite" + ] + } + }, + "response": [] + }, + { + "name": "Create Test Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Page created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"pageIdentifier\", jsonData.entity.identifier);", + " pm.collectionVariables.set(\"pageName\", jsonData.entity.name);", + " pm.collectionVariables.set(\"pagePath\", jsonData.entity.path);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_1_{{$timestamp}}\",\n \"url\":\"testPageStyles_1_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates a test page" + }, + "response": [] + }, + { + "name": "Create Test Page 2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Page created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"pageIdentifier2\", jsonData.entity.identifier);", + " pm.collectionVariables.set(\"pageName2\", jsonData.entity.name);", + " pm.collectionVariables.set(\"pagePath2\", jsonData.entity.path);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_2_{{$timestamp}}\",\n \"url\":\"testPageStyles_2_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_2_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates a test page" + }, + "response": [] + }, + { + "name": "Create Test Content Type", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Store first content type ID\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.entity).to.not.be.null;", + " pm.expect(jsonData.entity[0]).to.not.be.null;", + " pm.expect(jsonData.entity[0].id).to.not.be.null;", + " pm.collectionVariables.set(\"contentType1Id\", jsonData.entity[0].id);", + " pm.collectionVariables.set(\"contentType1VarName\", jsonData.entity[0].variable);", + " console.log('First content type created with ID:', jsonData.entity[0].id);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"defaultType\": false,\n \"name\": \"Styles_Test_ContentType_{{$timestamp}}\",\n \"description\": \"First content type for page tests\",\n \"host\": \"{{hostname}}\",\n \"owner\": \"dotcms.org.1\",\n \"fixed\": false,\n \"system\": false,\n \"folder\": \"SYSTEM_FOLDER\",\n \"fields\": [\n {\n \"dataType\": \"SYSTEM\",\n \"dbColumn\": \"system_field1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableHostFolderField\",\n \"indexed\": true,\n \"listed\": false,\n \"name\": \"Host/Folder\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 1,\n \"unique\": false,\n \"variable\": \"hostfolder\"\n },\n {\n \"dataType\": \"TEXT\",\n \"dbColumn\": \"text1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"indexed\": true,\n \"listed\": true,\n \"name\": \"title\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 2,\n \"unique\": false,\n \"variable\": \"title\"\n }\n ],\n \"workflow\": [\"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/contenttype", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "contenttype" + ] + } + }, + "response": [] + }, + { + "name": "Create Container", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Store container information\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.entity).to.not.be.null;", + " pm.expect(jsonData.entity.identifier).to.not.be.null;", + " pm.collectionVariables.set(\"containerId\", jsonData.entity.identifier);", + " console.log('Container created with ID:', jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"title\": \"Styles_Container_{{$timestamp}}\",\n \"friendlyName\": \"Container for style properties content type tests\",\n \"maxContentlets\": 25,\n \"code\": \"
\\n#foreach($contentlet in $contents)\\n

$contentlet.title

\\n#end\\n
\",\n \"preLoop\": \"
\",\n \"postLoop\": \"
\",\n \"containerStructures\": [\n {\n \"structureId\": \"{{contentType1Id}}\",\n \"code\": \"
\\n

$title

\\n
\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/containers", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "containers" + ] + } + }, + "response": [] + }, + { + "name": "Create Test Contentlet 1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Rich Text created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_1\", jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 1\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates test data" + }, + "response": [] + }, + { + "name": "Create Test Contentlet 2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Rich Text created successfully\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_2\", jsonData.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 2\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH?indexPolicy=WAIT_FOR", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ], + "query": [ + { + "key": "indexPolicy", + "value": "WAIT_FOR" + } + ] + }, + "description": "Creates test data" + }, + "response": [] + } + ], + "description": "### Setup\n\nDefines the base data needed along the other tests.\n\n- Create two Pages for testing\n \n - testPageStyles_1\n \n - testPageStyles_2\n \n- Create a Content Type `Styles_Test_ContentType` that requires `hostfolder` and `title` fields.\n \n- Create a custom Container `Styles_Container` that only accepts the content type`Styles_Test_ContentType`\n \n- Create 2 Contentlets with `hostfolder` and `title` fields.\n \n - Contentlet 1\n \n - Contentlet 2" + }, + { + "name": "Defining Contentlet Styles", + "item": [ + { + "name": "Save Content With Basic Styles", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const contentlet2 = pm.collectionVariables.get(\"Contentlet_2\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Entity array exists\", function () {", + " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(\"No errors returned\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "// ============================", + "// Validate first merged entry", + "// ============================", + "pm.test(\"First entry has correct styleProperties\", function () {", + " const first = json.entity.find(item => item.contentletId === contentlet1);", + " pm.expect(first).to.exist;", + " pm.expect(first.styleProperties).to.be.an(\"object\");", + " pm.expect(first.styleProperties.width).to.eql(\"100px\");", + " pm.expect(first.styleProperties.color).to.eql(\"#FF0000\");", + " pm.expect(first.styleProperties.margin).to.eql(\"10px\");", + "});", + "", + "// ============================", + "// Validate second merged entry", + "// ============================", + "pm.test(\"Second entry has no style properties\", function () {", + " const second = json.entity.find(item => item.contentletId === contentlet2);", + " pm.expect(second).to.exist;", + " pm.expect(second.styleProperties).to.eql({});", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\",\n \"{{Contentlet_2}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\",\n \"color\": \"#FF0000\",\n \"margin\": \"10px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "Save Content With Complex Styles", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Entity array exists\", function () {", + " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + " const contentlet = json.entity.find(item => item.contentletId === contentlet1);", + " pm.expect(contentlet).to.exist;", + " pm.expect(contentlet.styleProperties).to.be.an(\"object\");", + " pm.expect(contentlet.styleProperties.height).to.eql(300);", + " pm.expect(contentlet.styleProperties.visible).to.be.true;", + "", + " // Deep styleProperties object", + " const styleLayout = contentlet.styleProperties.layout;", + " pm.expect(styleLayout).to.be.an(\"object\");", + " pm.expect(styleLayout.display).to.eql(\"flex\");", + " pm.expect(styleLayout.gap).to.eql(16);", + " pm.expect(styleLayout.alignItems).to.eql(\"center\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"height\": 300,\n \"visible\": true,\n \"layout\": {\n \"display\": \"flex\",\n \"gap\": 16,\n \"alignItems\": \"center\"\n }\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "BadRequest when Saving Content With Styles", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const contentlet2 = pm.collectionVariables.get(\"Contentlet_2\");", + "", + "pm.test(\"Status is 400\", function () {", + " pm.response.to.have.status(400);", + "});", + "", + "pm.test(\"Response is JSON\", function () {", + " pm.response.to.be.json;", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Error array exists\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(\"No styleProperties were saved\", function () {", + " pm.expect(json.entity).to.be.an(\"string\").that.is.empty;", + "});", + "", + "// ============================", + "// Validate first error cause is for INVALID_CONTENTLET_REFERENCE", + "// ============================", + "pm.test(\"First error failed with INVALID_CONTENTLET_REFERENCE\", function () {", + " const first = json.errors.find(item => item.contentletId === '7c9cb3a7-bb68');", + " pm.expect(first).to.exist;", + " pm.expect(first.errorCode).to.eql(\"INVALID_CONTENTLET_REFERENCE\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\",\n \"{{Contentlet_2}}\"\n ],\n \"styleProperties\": {\n \"7c9cb3a7-bb68\": {\n \"color\": \"#FF0000\"\n },\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "Save Styles for the same Content in different Container", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"Entity array exists\", function () {", + " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + "});", + "", + "pm.test(\"No errors returned\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "// ============================", + "// Validate SYSTEM_CONTAINER styles", + "// ============================", + "pm.test(\"SYSTEM_CONTAINER has width styleProperties\", function () {", + " const systemContainer = json.entity.find(item => item.containerId === \"SYSTEM_CONTAINER\");", + " pm.expect(systemContainer).to.exist;", + " pm.expect(systemContainer.contentletId).to.eql(contentlet1);", + " pm.expect(systemContainer.styleProperties.width).to.eql(\"100px\");", + "});", + "", + "// ============================", + "// Validate CUSTOM_CONTAINER styles", + "// ============================", + "pm.test(\"CUSTOM_CONTAINER has color styleProperties\", function () {", + " const customContainer = json.entity.find(item => item.containerId === CUSTOM_CONTAINER);", + " pm.expect(customContainer).to.exist;", + " pm.expect(customContainer.contentletId).to.eql(contentlet1);", + " pm.expect(customContainer.styleProperties.color).to.eql(\"#FF0000\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n },\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + } + ], + "description": "### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the `testPageStyles_1`.\n\n- Save Contentlets with Basic Styles\n \n - `Contentlet 1` with basic Style Properties\n \n - `Contentlet 2` without Styles\n \n- Save Contentlet with Complex Styles\n \n - `Contentlet 1` with deep object definition Style Properties\n \n- BadRequest trying to set Styles for a contentlet that does not exists, should fail.\n \n- Save Styles for the same Contentlet but in different Containers, each of them does not affect the other one.\n \n - `Contentlet 1` saved with \"width = 100px\" style value in the `SYSTEM_CONTAINER`\n \n - `Contentlet 1` saved with \"color = \"#FF0000\" style in the custom Container `Styles_Container`" + }, + { + "name": "Retrieve Contentlet Styles", + "item": [ + { + "name": "Turn ON Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", + " const entity = json.entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\": \"FEATURE_FLAG_UVE_STYLE_EDITOR\",\n \"value\": \"true\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "" + ] + } + }, + "response": [] + }, + { + "name": "Add Content in 1st Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Content added to Test Page successfuly\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Adds a single content to the created page" + }, + "response": [] + }, + { + "name": "Add Content in 2nd Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Content added to Test Page successfuly\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier2}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier2}}", + "content" + ] + }, + "description": "Adds a single content to the created page" + }, + "response": [] + }, + { + "name": "Get Styles for Contentlet1 in Page1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + " // filter by container", + " const container = json.entity.containers[CUSTOM_CONTAINER];", + " pm.expect(container, \"Container not found\").to.exist;", + " ", + " // filter by contentlet", + " const allContentlets = Object.values(container.contentlets).flat();", + " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet, \"Contentlet not found\").to.exist;", + " pm.expect(contentlet.styleProperties.color).to.eql(\"#FF0000\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{pageName}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{pageName}}" + ] + } + }, + "response": [] + }, + { + "name": "Get Styles for Contentlet1 in Page2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + " // filter by container", + " const container = json.entity.containers[CUSTOM_CONTAINER];", + " pm.expect(container, \"Container not found\").to.exist;", + " ", + " // filter by contentlet", + " const allContentlets = Object.values(container.contentlets).flat();", + " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet, \"Contentlet not found\").to.exist;", + " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{pageName2}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{pageName2}}" + ] + } + }, + "response": [] + }, + { + "name": "Turn OFF Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is disabled\", function () {", + " const entity = json.entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR Deleted');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\"key\":\"FEATURE_FLAG_UVE_STYLE_EDITOR\"}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/_delete", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Styles NOT Present for Contentlet1 in Page1", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(`Validate ${contentlet1} does not have styleProperties`, function () {", + " // filter by container", + " const container = json.entity.containers[CUSTOM_CONTAINER];", + " pm.expect(container, \"Container not found\").to.exist;", + " ", + " // filter by contentlet", + " const allContentlets = Object.values(container.contentlets).flat();", + " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet, \"Contentlet not found\").to.exist;", + " // Validate that styles are not present", + " pm.expect(contentlet.styleProperties).to.be.undefined;", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{pageName}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{pageName}}" + ] + } + }, + "response": [] + } + ], + "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + " const serverURL = pm.environment.get('serverURL'); // Get the server URL from the environment variable", + " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", + "", + "// If we are unable to get the JWT we need to generate a new one", + " if (!pm.environment.get('jwt')) {", + " const username = pm.environment.get(\"user\");", + " const password = pm.environment.get(\"password\");", + " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", + "", + "", + " const requestOptions = {", + " url: apiUrl,", + " method: \"POST\",", + " header: {", + " \"accept\": \"*/*\",", + " \"content-type\": \"application/json\",", + " \"Authorization\": `Basic ${basicAuth}`", + " },", + " body: {", + " mode: \"raw\",", + " raw: JSON.stringify({", + " \"expirationSeconds\": 7200,", + " \"userId\": \"dotcms.org.1\",", + " \"network\": \"0.0.0.0/0\",", + " \"claims\": {\"label\": \"postman-tests\"}", + " })", + " }", + " };", + "", + "", + " pm.sendRequest(requestOptions, function (err, response) {", + " if (err) {", + " console.log(err);", + " } else {", + " const jwt = response.json().entity.jwt;", + " pm.environment.set('jwt', jwt);", + " console.log(jwt);", + " }", + " });", + " }" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "hostname", + "value": "" + }, + { + "key": "hostIdentifier", + "value": "" + }, + { + "key": "pageIdentifier", + "value": "" + }, + { + "key": "pagePath", + "value": "" + }, + { + "key": "Contentlet_1", + "value": "" + }, + { + "key": "Contentlet_2", + "value": "" + }, + { + "key": "Contentlet_3", + "value": "" + }, + { + "key": "pageIdentifier2", + "value": "" + }, + { + "key": "pagePath2", + "value": "" + }, + { + "key": "contentType1Id", + "value": "" + }, + { + "key": "contentType1VarName", + "value": "" + }, + { + "key": "containerId", + "value": "" + }, + { + "key": "stylePropertiesBody", + "value": "" + }, + { + "key": "pageName", + "value": "" + }, + { + "key": "pageName2", + "value": "" + } + ] } \ No newline at end of file From d976726fc11a974eafe2537faa30eea683863037 Mon Sep 17 00:00:00 2001 From: ddariod Date: Tue, 30 Dec 2025 10:48:07 -0500 Subject: [PATCH 06/19] add authentication for tests --- ...ts_StyleProperties.postman_collection.json | 76 ++++--------------- 1 file changed, 14 insertions(+), 62 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 0f1a7e669541..90db58b31407 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -1149,69 +1149,21 @@ "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" } ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - " const serverURL = pm.environment.get('serverURL'); // Get the server URL from the environment variable", - " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", - "", - "// If we are unable to get the JWT we need to generate a new one", - " if (!pm.environment.get('jwt')) {", - " const username = pm.environment.get(\"user\");", - " const password = pm.environment.get(\"password\");", - " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", - "", - "", - " const requestOptions = {", - " url: apiUrl,", - " method: \"POST\",", - " header: {", - " \"accept\": \"*/*\",", - " \"content-type\": \"application/json\",", - " \"Authorization\": `Basic ${basicAuth}`", - " },", - " body: {", - " mode: \"raw\",", - " raw: JSON.stringify({", - " \"expirationSeconds\": 7200,", - " \"userId\": \"dotcms.org.1\",", - " \"network\": \"0.0.0.0/0\",", - " \"claims\": {\"label\": \"postman-tests\"}", - " })", - " }", - " };", - "", - "", - " pm.sendRequest(requestOptions, function (err, response) {", - " if (err) {", - " console.log(err);", - " } else {", - " const jwt = response.json().entity.jwt;", - " pm.environment.set('jwt', jwt);", - " console.log(jwt);", - " }", - " });", - " }" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - "" - ] + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "admin", + "type": "string" + }, + { + "key": "username", + "value": "admin@dotcms.com", + "type": "string" } - } - ], + ] + }, "variable": [ { "key": "hostname", From 5e7f1ac79cc04e1112000496e62d1d5cc325016c Mon Sep 17 00:00:00 2001 From: ddariod Date: Tue, 30 Dec 2025 14:47:55 -0500 Subject: [PATCH 07/19] make style properties unmodifiable and update method name --- .../rest/api/v1/page/PageContainerForm.java | 35 ++++++++++--------- .../com/dotmarketing/beans/MultiTree.java | 3 +- .../factories/PersonalizedContentlet.java | 5 +-- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java index 0290c8f9dcb0..eeafea48b748 100644 --- a/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java +++ b/dotCMS/src/main/java/com/dotcms/rest/api/v1/page/PageContainerForm.java @@ -84,7 +84,9 @@ public PageContainerForm deserialize(final JsonParser jsonParser, // Parse styleProperties for each contentlet (optional field) final JsonNode stylePropertiesNode = jsonElement.get(STYLE_PROPERTIES_ATTRIBUTE_NAME); - getStylePropertiesNode(stylePropertiesNode, containerEntry); + if (UtilMethods.isSet(stylePropertiesNode) && stylePropertiesNode.isObject()) { + processStyleProperties(stylePropertiesNode, containerEntry); + } entries.add(containerEntry); } @@ -93,25 +95,24 @@ public PageContainerForm deserialize(final JsonParser jsonParser, } /** - * Gets the style properties node from the JSON object. + * Processes the style properties for the container entry. + * It converts the JSON node to a Map and sets it to the container entry. * @param stylePropertiesNode The JSON node containing the style properties. * @param containerEntry The container entry to set the style properties. */ - private void getStylePropertiesNode(final JsonNode stylePropertiesNode, final ContainerEntry containerEntry) { - if (stylePropertiesNode != null && stylePropertiesNode.isObject()) { - stylePropertiesNode.fields().forEachRemaining(entry -> { - final String contentletId = entry.getKey(); - final JsonNode styleProps = entry.getValue(); - if (styleProps != null && styleProps.isObject()) { - final Map propsMap = new HashMap<>(); - styleProps.fields().forEachRemaining(prop -> { - final JsonNode propValue = prop.getValue(); - propsMap.put(prop.getKey(), convertJsonNodeToObject(propValue)); - }); - containerEntry.setStyleProperties(contentletId, propsMap); - } - }); - } + private void processStyleProperties(final JsonNode stylePropertiesNode, final ContainerEntry containerEntry) { + stylePropertiesNode.fields().forEachRemaining(entry -> { + final String contentletId = entry.getKey(); + final JsonNode styleProps = entry.getValue(); + if (styleProps != null && styleProps.isObject()) { + final Map propsMap = new HashMap<>(); + styleProps.fields().forEachRemaining(prop -> { + final JsonNode propValue = prop.getValue(); + propsMap.put(prop.getKey(), convertJsonNodeToObject(propValue)); + }); + containerEntry.setStyleProperties(contentletId, propsMap); + } + }); } /** diff --git a/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java b/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java index 4bada1ce6392..c48abceb886c 100644 --- a/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java +++ b/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java @@ -7,6 +7,7 @@ import com.dotmarketing.portlets.containers.model.Container; import com.dotmarketing.portlets.contentlet.model.Contentlet; import com.dotmarketing.portlets.htmlpageasset.model.HTMLPageAsset; +import com.dotmarketing.util.UtilMethods; import com.fasterxml.jackson.annotation.JsonIgnore; import java.util.Map; import org.apache.commons.lang.builder.EqualsBuilder; @@ -75,7 +76,7 @@ public MultiTree(final String htmlPage, this.treeOrder = Math.max(treeOrder, 0); this.personalization = personalization; this.variantId = variantId; - this.styleProperties = styleProperties; + this.styleProperties = UtilMethods.isSet(styleProperties) ? Map.copyOf(styleProperties) : Map.of(); } /** full constructor */ diff --git a/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java b/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java index ff084308b214..4017f9d63225 100644 --- a/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java +++ b/dotCMS/src/main/java/com/dotmarketing/factories/PersonalizedContentlet.java @@ -1,5 +1,6 @@ package com.dotmarketing.factories; +import com.dotmarketing.util.UtilMethods; import java.io.Serializable; import java.util.Map; import java.util.Objects; @@ -22,14 +23,14 @@ public PersonalizedContentlet(final String contentletId, final String personaliz this.contentletId = contentletId; this.personalization = personalization; this.treeOrder = treeOrder; - this.styleProperties = styleProperties; + this.styleProperties = UtilMethods.isSet(styleProperties) ? Map.copyOf(styleProperties) : Map.of(); } public PersonalizedContentlet(final String contentletId, final String personalization) { this.contentletId = contentletId; this.personalization = personalization; this.treeOrder = 0; - this.styleProperties = null; + this.styleProperties = Map.of(); } public String getContentletId() { From c86b42c48857033c7c3ee7cbe741235566033c4d Mon Sep 17 00:00:00 2001 From: ddariod Date: Wed, 31 Dec 2025 10:50:46 -0500 Subject: [PATCH 08/19] change authorization and container for get contentlet style postman test --- ...ts_StyleProperties.postman_collection.json | 97 +++++++++++++++---- 1 file changed, 76 insertions(+), 21 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 90db58b31407..365a806f6167 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "7e70edc5-b319-4d3f-b332-0c6c17d303ff", + "_postman_id": "57b69e00-6c5a-4470-81fe-1d1780dcb75e", "name": "Define StyleProperties for Contentlets", "description": "## Description:\n\nThis collection validates the application of Style Properties to **Contentlets** based on their **location**.\n\nSince a Contentlet is always hosted within a **Container**, and a **Page** can have multiple Containers, you can define unique styles for the exact same Contentlet if:\n\n1. The Contentlet is placed in a different Container.\n \n2. The Contentlet and its Container appear on a different Page.\n \n\nInside are three sub folders:\n\n### Setup\n\nDefines the base data needed for the tests.\n\n### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the **Test Page 1**.\n\n### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", @@ -847,7 +847,7 @@ "header": [], "body": { "mode": "raw", - "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", "options": { "raw": { "language": "json" @@ -905,7 +905,7 @@ "header": [], "body": { "mode": "raw", - "raw": "[\n {\n \"identifier\": \"{{containerId}}\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", "options": { "raw": { "language": "json" @@ -937,7 +937,6 @@ "script": { "exec": [ "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", "", "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", @@ -946,9 +945,9 @@ "// Parse JSON", "const json = pm.response.json();", "", - "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + "pm.test(\"Validate Contentlet_1 in Page_1 has correct styleProperties\", function () {", " // filter by container", - " const container = json.entity.containers[CUSTOM_CONTAINER];", + " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", " pm.expect(container, \"Container not found\").to.exist;", " ", " // filter by contentlet", @@ -991,7 +990,6 @@ "script": { "exec": [ "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", "", "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", @@ -1000,9 +998,9 @@ "// Parse JSON", "const json = pm.response.json();", "", - "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", + "pm.test(\"Validate Contentlet_1 in Page_2 has correct styleProperties\", function () {", " // filter by container", - " const container = json.entity.containers[CUSTOM_CONTAINER];", + " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", " pm.expect(container, \"Container not found\").to.exist;", " ", " // filter by contentlet", @@ -1098,7 +1096,6 @@ "script": { "exec": [ "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "const CUSTOM_CONTAINER = pm.collectionVariables.get(\"containerId\");", "", "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", @@ -1109,7 +1106,7 @@ "", "pm.test(`Validate ${contentlet1} does not have styleProperties`, function () {", " // filter by container", - " const container = json.entity.containers[CUSTOM_CONTAINER];", + " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", " pm.expect(container, \"Container not found\").to.exist;", " ", " // filter by contentlet", @@ -1146,24 +1143,82 @@ "response": [] } ], - "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `Styles_Container` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" + "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" } ], "auth": { - "type": "basic", - "basic": [ - { - "key": "password", - "value": "admin", - "type": "string" - }, + "type": "bearer", + "bearer": [ { - "key": "username", - "value": "admin@dotcms.com", + "key": "token", + "value": "{{jwt}}", "type": "string" } ] }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + " const serverURL = pm.environment.get('serverURL'); // Get the server URL from the environment variable", + " const apiUrl = `${serverURL}/api/v1/apitoken`; // Construct the full API URL", + "", + "// If we are unable to get the JWT we need to generate a new one", + " if (!pm.environment.get('jwt')) {", + " const username = pm.environment.get(\"user\");", + " const password = pm.environment.get(\"password\");", + " const basicAuth = Buffer.from(`${username}:${password}`).toString('base64');", + "", + "", + " const requestOptions = {", + " url: apiUrl,", + " method: \"POST\",", + " header: {", + " \"accept\": \"*/*\",", + " \"content-type\": \"application/json\",", + " \"Authorization\": `Basic ${basicAuth}`", + " },", + " body: {", + " mode: \"raw\",", + " raw: JSON.stringify({", + " \"expirationSeconds\": 7200,", + " \"userId\": \"dotcms.org.1\",", + " \"network\": \"0.0.0.0/0\",", + " \"claims\": {\"label\": \"postman-tests\"}", + " })", + " }", + " };", + "", + "", + " pm.sendRequest(requestOptions, function (err, response) {", + " if (err) {", + " console.log(err);", + " } else {", + " const jwt = response.json().entity.jwt;", + " pm.environment.set('jwt', jwt);", + " console.log(jwt);", + " }", + " });", + " }" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + } + ], "variable": [ { "key": "hostname", From caa0c054ad96eb587e4609bcd8fa275d4b656936 Mon Sep 17 00:00:00 2001 From: ddariod Date: Fri, 2 Jan 2026 11:12:07 -0500 Subject: [PATCH 09/19] fix integration and postman test for style properties --- .../factories/MultiTreeAPITest.java | 7 ++--- ...ts_StyleProperties.postman_collection.json | 30 ++++++++----------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java b/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java index dca3e48ece52..2ea8b99ae115 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java @@ -4359,8 +4359,7 @@ public void testUpdate_stylePropertiesToNull() throws Exception { MultiTree retrieved = retrieveMultiTree(0); - assertNull("NULL style properties should be persisted", - retrieved.getStyleProperties()); + assertEquals("Style properties should be empty", Map.of(), retrieved.getStyleProperties()); } /** @@ -4376,7 +4375,7 @@ public void testCreate_withNullStyleProperties() throws Exception { MultiTree retrieved = retrieveMultiTree(0); assertNotNull("Retrieved multiTree should not be null", retrieved); - assertNull("Style properties should be null", retrieved.getStyleProperties()); + assertEquals("Style properties should be empty", Map.of(), retrieved.getStyleProperties()); } /** @@ -4393,7 +4392,7 @@ public void testCreate_withEmptyStyleProperties() throws Exception { MultiTree retrieved = retrieveMultiTree(0); assertNotNull("Retrieved multiTree should not be null", retrieved); - assertNull("Style properties should be null", retrieved.getStyleProperties()); + assertEquals("Style properties should be empty", Map.of(), retrieved.getStyleProperties()); } } diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 365a806f6167..45d6770a2ff4 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -60,7 +60,6 @@ " pm.expect(jsonData.errors.length).to.eql(0);", " pm.collectionVariables.set(\"pageIdentifier\", jsonData.entity.identifier);", " pm.collectionVariables.set(\"pageName\", jsonData.entity.name);", - " pm.collectionVariables.set(\"pagePath\", jsonData.entity.path);", "});" ], "type": "text/javascript", @@ -118,7 +117,6 @@ " pm.expect(jsonData.errors.length).to.eql(0);", " pm.collectionVariables.set(\"pageIdentifier2\", jsonData.entity.identifier);", " pm.collectionVariables.set(\"pageName2\", jsonData.entity.name);", - " pm.collectionVariables.set(\"pagePath2\", jsonData.entity.path);", "});" ], "type": "text/javascript", @@ -938,12 +936,16 @@ "exec": [ "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", "", + "// wait 1 sec before execute", + "setTimeout(function(){}, 1000);", + "", "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", "});", "", "// Parse JSON", "const json = pm.response.json();", + "console.log(\"DEBUG RESPONSE: \" + JSON.stringify(json, null, 2));", "", "pm.test(\"Validate Contentlet_1 in Page_1 has correct styleProperties\", function () {", " // filter by container", @@ -991,12 +993,16 @@ "exec": [ "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", "", + "// wait 1 sec before execute", + "setTimeout(function(){}, 1000);", + "", "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", "});", "", "// Parse JSON", "const json = pm.response.json();", + "console.log(\"DEBUG RESPONSE 2: \" + JSON.stringify(json, null, 2));", "", "pm.test(\"Validate Contentlet_1 in Page_2 has correct styleProperties\", function () {", " // filter by container", @@ -1097,12 +1103,16 @@ "exec": [ "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", "", + "// wait 1 sec before execute", + "setTimeout(function(){}, 1000);", + "", "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", "});", "", "// Parse JSON", "const json = pm.response.json();", + "console.log(\"DEBUG RESPONSE 3: \" + JSON.stringify(json, null, 2));", "", "pm.test(`Validate ${contentlet1} does not have styleProperties`, function () {", " // filter by container", @@ -1232,10 +1242,6 @@ "key": "pageIdentifier", "value": "" }, - { - "key": "pagePath", - "value": "" - }, { "key": "Contentlet_1", "value": "" @@ -1244,18 +1250,10 @@ "key": "Contentlet_2", "value": "" }, - { - "key": "Contentlet_3", - "value": "" - }, { "key": "pageIdentifier2", "value": "" }, - { - "key": "pagePath2", - "value": "" - }, { "key": "contentType1Id", "value": "" @@ -1268,10 +1266,6 @@ "key": "containerId", "value": "" }, - { - "key": "stylePropertiesBody", - "value": "" - }, { "key": "pageName", "value": "" From 50037f7486b981b689cff455202bc53c356917f4 Mon Sep 17 00:00:00 2001 From: ddariod Date: Fri, 2 Jan 2026 15:12:33 -0500 Subject: [PATCH 10/19] remove get styles postman test --- ...ts_StyleProperties.postman_collection.json | 400 ------------------ 1 file changed, 400 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 45d6770a2ff4..1ce919a428f9 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -754,406 +754,6 @@ } ], "description": "### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the `testPageStyles_1`.\n\n- Save Contentlets with Basic Styles\n \n - `Contentlet 1` with basic Style Properties\n \n - `Contentlet 2` without Styles\n \n- Save Contentlet with Complex Styles\n \n - `Contentlet 1` with deep object definition Style Properties\n \n- BadRequest trying to set Styles for a contentlet that does not exists, should fail.\n \n- Save Styles for the same Contentlet but in different Containers, each of them does not affect the other one.\n \n - `Contentlet 1` saved with \"width = 100px\" style value in the `SYSTEM_CONTAINER`\n \n - `Contentlet 1` saved with \"color = \"#FF0000\" style in the custom Container `Styles_Container`" - }, - { - "name": "Retrieve Contentlet Styles", - "item": [ - { - "name": "Turn ON Style Editor", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", - " const entity = json.entity;", - " pm.expect(entity).to.exist;", - " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"key\": \"FEATURE_FLAG_UVE_STYLE_EDITOR\",\n \"value\": \"true\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/system-table/", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "system-table", - "" - ] - } - }, - "response": [] - }, - { - "name": "Add Content in 1st Page", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Content added to Test Page successfuly\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier}}", - "content" - ] - }, - "description": "Adds a single content to the created page" - }, - "response": [] - }, - { - "name": "Add Content in 2nd Page", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Test Content added to Test Page successfuly\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier2}}/content", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "{{pageIdentifier2}}", - "content" - ] - }, - "description": "Adds a single content to the created page" - }, - "response": [] - }, - { - "name": "Get Styles for Contentlet1 in Page1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "", - "// wait 1 sec before execute", - "setTimeout(function(){}, 1000);", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "console.log(\"DEBUG RESPONSE: \" + JSON.stringify(json, null, 2));", - "", - "pm.test(\"Validate Contentlet_1 in Page_1 has correct styleProperties\", function () {", - " // filter by container", - " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", - " pm.expect(container, \"Container not found\").to.exist;", - " ", - " // filter by contentlet", - " const allContentlets = Object.values(container.contentlets).flat();", - " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", - " pm.expect(contentlet, \"Contentlet not found\").to.exist;", - " pm.expect(contentlet.styleProperties.color).to.eql(\"#FF0000\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{pageName}}", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "render", - "{{pageName}}" - ] - } - }, - "response": [] - }, - { - "name": "Get Styles for Contentlet1 in Page2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "", - "// wait 1 sec before execute", - "setTimeout(function(){}, 1000);", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "console.log(\"DEBUG RESPONSE 2: \" + JSON.stringify(json, null, 2));", - "", - "pm.test(\"Validate Contentlet_1 in Page_2 has correct styleProperties\", function () {", - " // filter by container", - " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", - " pm.expect(container, \"Container not found\").to.exist;", - " ", - " // filter by contentlet", - " const allContentlets = Object.values(container.contentlets).flat();", - " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", - " pm.expect(contentlet, \"Contentlet not found\").to.exist;", - " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{pageName2}}", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "render", - "{{pageName2}}" - ] - } - }, - "response": [] - }, - { - "name": "Turn OFF Style Editor", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "", - "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is disabled\", function () {", - " const entity = json.entity;", - " pm.expect(entity).to.exist;", - " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR Deleted');", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "DELETE", - "header": [], - "body": { - "mode": "raw", - "raw": "{\"key\":\"FEATURE_FLAG_UVE_STYLE_EDITOR\"}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{serverURL}}/api/v1/system-table/_delete", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "system-table", - "_delete" - ] - } - }, - "response": [] - }, - { - "name": "Styles NOT Present for Contentlet1 in Page1", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "", - "// wait 1 sec before execute", - "setTimeout(function(){}, 1000);", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "console.log(\"DEBUG RESPONSE 3: \" + JSON.stringify(json, null, 2));", - "", - "pm.test(`Validate ${contentlet1} does not have styleProperties`, function () {", - " // filter by container", - " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", - " pm.expect(container, \"Container not found\").to.exist;", - " ", - " // filter by contentlet", - " const allContentlets = Object.values(container.contentlets).flat();", - " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", - " pm.expect(contentlet, \"Contentlet not found\").to.exist;", - " // Validate that styles are not present", - " pm.expect(contentlet.styleProperties).to.be.undefined;", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{pageName}}", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "render", - "{{pageName}}" - ] - } - }, - "response": [] - } - ], - "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" } ], "auth": { From 9a4904c2a6ee1b68f89fbb61c7d0f5372b4d58f5 Mon Sep 17 00:00:00 2001 From: ddariod Date: Fri, 2 Jan 2026 15:15:23 -0500 Subject: [PATCH 11/19] keep MultiTree to null --- dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java | 2 +- .../java/com/dotmarketing/factories/MultiTreeAPITest.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java b/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java index c48abceb886c..758c05512bb6 100644 --- a/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java +++ b/dotCMS/src/main/java/com/dotmarketing/beans/MultiTree.java @@ -76,7 +76,7 @@ public MultiTree(final String htmlPage, this.treeOrder = Math.max(treeOrder, 0); this.personalization = personalization; this.variantId = variantId; - this.styleProperties = UtilMethods.isSet(styleProperties) ? Map.copyOf(styleProperties) : Map.of(); + this.styleProperties = UtilMethods.isSet(styleProperties) ? Map.copyOf(styleProperties) : null; } /** full constructor */ diff --git a/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java b/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java index 2ea8b99ae115..dca3e48ece52 100644 --- a/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java +++ b/dotcms-integration/src/test/java/com/dotmarketing/factories/MultiTreeAPITest.java @@ -4359,7 +4359,8 @@ public void testUpdate_stylePropertiesToNull() throws Exception { MultiTree retrieved = retrieveMultiTree(0); - assertEquals("Style properties should be empty", Map.of(), retrieved.getStyleProperties()); + assertNull("NULL style properties should be persisted", + retrieved.getStyleProperties()); } /** @@ -4375,7 +4376,7 @@ public void testCreate_withNullStyleProperties() throws Exception { MultiTree retrieved = retrieveMultiTree(0); assertNotNull("Retrieved multiTree should not be null", retrieved); - assertEquals("Style properties should be empty", Map.of(), retrieved.getStyleProperties()); + assertNull("Style properties should be null", retrieved.getStyleProperties()); } /** @@ -4392,7 +4393,7 @@ public void testCreate_withEmptyStyleProperties() throws Exception { MultiTree retrieved = retrieveMultiTree(0); assertNotNull("Retrieved multiTree should not be null", retrieved); - assertEquals("Style properties should be empty", Map.of(), retrieved.getStyleProperties()); + assertNull("Style properties should be null", retrieved.getStyleProperties()); } } From c0deecfe5a877d70c42e236ec5526e0bc17bc253 Mon Sep 17 00:00:00 2001 From: ddariod Date: Fri, 2 Jan 2026 16:23:49 -0500 Subject: [PATCH 12/19] add test for get style properties --- ...ts_StyleProperties.postman_collection.json | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 1ce919a428f9..75c635424315 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -754,6 +754,180 @@ } ], "description": "### Defining Contentlet Styles:\n\nTest the Contentlet Style definition in the `testPageStyles_1`.\n\n- Save Contentlets with Basic Styles\n \n - `Contentlet 1` with basic Style Properties\n \n - `Contentlet 2` without Styles\n \n- Save Contentlet with Complex Styles\n \n - `Contentlet 1` with deep object definition Style Properties\n \n- BadRequest trying to set Styles for a contentlet that does not exists, should fail.\n \n- Save Styles for the same Contentlet but in different Containers, each of them does not affect the other one.\n \n - `Contentlet 1` saved with \"width = 100px\" style value in the `SYSTEM_CONTAINER`\n \n - `Contentlet 1` saved with \"color = \"#FF0000\" style in the custom Container `Styles_Container`" + }, + { + "name": "Retrieve Contentlet Styles", + "item": [ + { + "name": "Turn ON Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", + " const entity = json.entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\": \"FEATURE_FLAG_UVE_STYLE_EDITOR\",\n \"value\": \"true\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "" + ] + } + }, + "response": [] + }, + { + "name": "Add Content in 2nd Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Content added to Test Page successfuly\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier2}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier2}}", + "content" + ] + }, + "description": "Adds a single content to the created page" + }, + "response": [] + }, + { + "name": "Get Styles for Contentlet1 in Page2", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "// wait 1 sec before execute", + "setTimeout(function(){}, 1000);", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "console.log(\"DEBUG RESPONSE 2: \" + JSON.stringify(json, null, 2));", + "", + "pm.test(\"Validate Contentlet_1 in Page_2 has correct styleProperties\", function () {", + " // filter by container", + " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", + " pm.expect(container, \"Container not found\").to.exist;", + " ", + " // filter by contentlet", + " const allContentlets = Object.values(container.contentlets).flat();", + " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet, \"Contentlet not found\").to.exist;", + " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{pageName2}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{pageName2}}" + ] + } + }, + "response": [] + } + ], + "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" } ], "auth": { From 774a4a27c0bd386ca133ae1b839f55da91bcb899 Mon Sep 17 00:00:00 2001 From: ddariod Date: Fri, 2 Jan 2026 17:11:35 -0500 Subject: [PATCH 13/19] remove get contentlet request --- ...ts_StyleProperties.postman_collection.json | 57 ------------------- 1 file changed, 57 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 75c635424315..1ba87af5d287 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -868,63 +868,6 @@ "description": "Adds a single content to the created page" }, "response": [] - }, - { - "name": "Get Styles for Contentlet1 in Page2", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", - "", - "// wait 1 sec before execute", - "setTimeout(function(){}, 1000);", - "", - "pm.test(\"Status code is 200\", function () {", - " pm.response.to.have.status(200);", - "});", - "", - "// Parse JSON", - "const json = pm.response.json();", - "console.log(\"DEBUG RESPONSE 2: \" + JSON.stringify(json, null, 2));", - "", - "pm.test(\"Validate Contentlet_1 in Page_2 has correct styleProperties\", function () {", - " // filter by container", - " const container = json.entity.containers[\"SYSTEM_CONTAINER\"];", - " pm.expect(container, \"Container not found\").to.exist;", - " ", - " // filter by contentlet", - " const allContentlets = Object.values(container.contentlets).flat();", - " const contentlet = allContentlets.find(c => c.identifier === contentlet1);", - " pm.expect(contentlet, \"Contentlet not found\").to.exist;", - " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", - "});" - ], - "type": "text/javascript", - "packages": {}, - "requests": {} - } - } - ], - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{pageName2}}", - "host": [ - "{{serverURL}}" - ], - "path": [ - "api", - "v1", - "page", - "render", - "{{pageName2}}" - ] - } - }, - "response": [] } ], "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" From 03667917f28ab4142a941066c79b11402309bf48 Mon Sep 17 00:00:00 2001 From: ddariod Date: Sat, 3 Jan 2026 20:03:23 -0500 Subject: [PATCH 14/19] define better names and add get test --- ...ts_StyleProperties.postman_collection.json | 140 ++++++++++++++---- 1 file changed, 110 insertions(+), 30 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 1ba87af5d287..b51afc45c656 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -49,7 +49,7 @@ "response": [] }, { - "name": "Create Test Page", + "name": "Create First Test Page", "event": [ { "listen": "test", @@ -58,14 +58,24 @@ "pm.test(\"Test Page created successfully\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"pageIdentifier\", jsonData.entity.identifier);", - " pm.collectionVariables.set(\"pageName\", jsonData.entity.name);", + " pm.collectionVariables.set(\"firstPageIdentifier\", jsonData.entity.identifier);", "});" ], "type": "text/javascript", "packages": {}, "requests": {} } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"firstPageUrl\", \"first-test-page\" + Date.now());" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } } ], "request": { @@ -73,7 +83,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_1_{{$timestamp}}\",\n \"url\":\"testPageStyles_1_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"htmlpageasset\",\n \"title\": \"First Test Page Styles_{{$timestamp}}\",\n \"url\": \"{{firstPageUrl}}\",\n \"hostFolder\": \"{{hostname}}\",\n \"template\": \"SYSTEM_TEMPLATE\",\n \"friendlyName\": \"First Test Page Styles_{{$timestamp}}\",\n \"cachettl\": 0\n }\n}", "options": { "raw": { "language": "json" @@ -106,7 +116,7 @@ "response": [] }, { - "name": "Create Test Page 2", + "name": "Create Second Test Page", "event": [ { "listen": "test", @@ -115,14 +125,24 @@ "pm.test(\"Test Page created successfully\", function () {", " var jsonData = pm.response.json();", " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"pageIdentifier2\", jsonData.entity.identifier);", - " pm.collectionVariables.set(\"pageName2\", jsonData.entity.name);", + " pm.collectionVariables.set(\"secondPageIdentifier\", jsonData.entity.identifier);", "});" ], "type": "text/javascript", "packages": {}, "requests": {} } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"secondPageUrl\", \"second-test-page\" + Date.now());" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } } ], "request": { @@ -130,7 +150,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n\t\n\t\"contentlet\": {\n\t\t\"contentType\":\"htmlpageasset\",\n \"title\":\"testPageStyles_2_{{$timestamp}}\",\n \"url\":\"testPageStyles_2_{{$timestamp}}\",\n \"hostFolder\":\"{{hostname}}\",\n \"template\":\"SYSTEM_TEMPLATE\",\n \"friendlyName\":\"testPageStyles_2_{{$timestamp}}\",\n \"cachettl\":0\n\t\t\n\t}\n}", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"htmlpageasset\",\n \"title\": \"Second Test Page Styles_{{$timestamp}}\",\n \"url\": \"{{secondPageUrl}}\",\n \"hostFolder\": \"{{hostname}}\",\n \"template\": \"SYSTEM_TEMPLATE\",\n \"friendlyName\": \"Second Test Page Styles_{{$timestamp}}\",\n \"cachettl\": 0\n }\n}", "options": { "raw": { "language": "json" @@ -178,8 +198,8 @@ " pm.expect(jsonData.entity).to.not.be.null;", " pm.expect(jsonData.entity[0]).to.not.be.null;", " pm.expect(jsonData.entity[0].id).to.not.be.null;", - " pm.collectionVariables.set(\"contentType1Id\", jsonData.entity[0].id);", - " pm.collectionVariables.set(\"contentType1VarName\", jsonData.entity[0].variable);", + " pm.collectionVariables.set(\"contentTypeId\", jsonData.entity[0].id);", + " pm.collectionVariables.set(\"contentTypeVarName\", jsonData.entity[0].variable);", " console.log('First content type created with ID:', jsonData.entity[0].id);", "});" ], @@ -204,7 +224,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"defaultType\": false,\n \"name\": \"Styles_Test_ContentType_{{$timestamp}}\",\n \"description\": \"First content type for page tests\",\n \"host\": \"{{hostname}}\",\n \"owner\": \"dotcms.org.1\",\n \"fixed\": false,\n \"system\": false,\n \"folder\": \"SYSTEM_FOLDER\",\n \"fields\": [\n {\n \"dataType\": \"SYSTEM\",\n \"dbColumn\": \"system_field1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableHostFolderField\",\n \"indexed\": true,\n \"listed\": false,\n \"name\": \"Host/Folder\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 1,\n \"unique\": false,\n \"variable\": \"hostfolder\"\n },\n {\n \"dataType\": \"TEXT\",\n \"dbColumn\": \"text1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"indexed\": true,\n \"listed\": true,\n \"name\": \"title\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 2,\n \"unique\": false,\n \"variable\": \"title\"\n }\n ],\n \"workflow\": [\"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"]\n}", + "raw": "{\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"defaultType\": false,\n \"name\": \"Styles_Test_ContentType_{{$timestamp}}\",\n \"description\": \"First content type for page tests\",\n \"host\": \"{{hostname}}\",\n \"owner\": \"dotcms.org.1\",\n \"fixed\": false,\n \"system\": false,\n \"folder\": \"SYSTEM_FOLDER\",\n \"fields\": [\n {\n \"dataType\": \"SYSTEM\",\n \"dbColumn\": \"system_field1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableHostFolderField\",\n \"indexed\": true,\n \"listed\": false,\n \"name\": \"Host/Folder\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 1,\n \"unique\": false,\n \"variable\": \"hostfolder\"\n },\n {\n \"dataType\": \"TEXT\",\n \"dbColumn\": \"text1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"indexed\": true,\n \"listed\": true,\n \"name\": \"title\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 2,\n \"unique\": false,\n \"variable\": \"title\"\n }\n ],\n \"workflow\": [\n \"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"\n ]\n}", "options": { "raw": { "language": "json" @@ -265,7 +285,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"title\": \"Styles_Container_{{$timestamp}}\",\n \"friendlyName\": \"Container for style properties content type tests\",\n \"maxContentlets\": 25,\n \"code\": \"
\\n#foreach($contentlet in $contents)\\n

$contentlet.title

\\n#end\\n
\",\n \"preLoop\": \"
\",\n \"postLoop\": \"
\",\n \"containerStructures\": [\n {\n \"structureId\": \"{{contentType1Id}}\",\n \"code\": \"
\\n

$title

\\n
\"\n }\n ]\n}", + "raw": "{\n \"title\": \"Styles_Container_{{$timestamp}}\",\n \"friendlyName\": \"Container for style properties content type tests\",\n \"maxContentlets\": 25,\n \"code\": \"
\\n#foreach($contentlet in $contents)\\n

$contentlet.title

\\n#end\\n
\",\n \"preLoop\": \"
\",\n \"postLoop\": \"
\",\n \"containerStructures\": [\n {\n \"structureId\": \"{{contentTypeId}}\",\n \"code\": \"
\\n

$title

\\n
\"\n }\n ]\n}", "options": { "raw": { "language": "json" @@ -310,7 +330,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 1\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentTypeVarName}}\",\n \"title\": \"Contentlet 1\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", "options": { "raw": { "language": "json" @@ -366,7 +386,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentType1VarName}}\",\n \"title\": \"Contentlet 2\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentTypeVarName}}\",\n \"title\": \"Contentlet 2\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", "options": { "raw": { "language": "json" @@ -480,7 +500,7 @@ } }, "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "raw": "{{serverURL}}/api/v1/page/{{firstPageIdentifier}}/content", "host": [ "{{serverURL}}" ], @@ -488,7 +508,7 @@ "api", "v1", "page", - "{{pageIdentifier}}", + "{{firstPageIdentifier}}", "content" ] }, @@ -561,7 +581,7 @@ } }, "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "raw": "{{serverURL}}/api/v1/page/{{firstPageIdentifier}}/content", "host": [ "{{serverURL}}" ], @@ -569,7 +589,7 @@ "api", "v1", "page", - "{{pageIdentifier}}", + "{{firstPageIdentifier}}", "content" ] }, @@ -645,7 +665,7 @@ } }, "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "raw": "{{serverURL}}/api/v1/page/{{firstPageIdentifier}}/content", "host": [ "{{serverURL}}" ], @@ -653,7 +673,7 @@ "api", "v1", "page", - "{{pageIdentifier}}", + "{{firstPageIdentifier}}", "content" ] }, @@ -736,7 +756,7 @@ } }, "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "raw": "{{serverURL}}/api/v1/page/{{firstPageIdentifier}}/content", "host": [ "{{serverURL}}" ], @@ -744,7 +764,7 @@ "api", "v1", "page", - "{{pageIdentifier}}", + "{{firstPageIdentifier}}", "content" ] }, @@ -853,7 +873,7 @@ } }, "url": { - "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier2}}/content", + "raw": "{{serverURL}}/api/v1/page/{{secondPageIdentifier}}/content", "host": [ "{{serverURL}}" ], @@ -861,13 +881,73 @@ "api", "v1", "page", - "{{pageIdentifier2}}", + "{{secondPageIdentifier}}", "content" ] }, "description": "Adds a single content to the created page" }, "response": [] + }, + { + "name": "Check Styles in Second Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Only one Contentlet must be present\", function() {", + " var entity = pm.response.json().entity;", + " var contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + " pm.expect(contentletList.length).to.eql(1);", + "});", + "", + "pm.test(\"The rendered section should contain data attribute 'data-dot-on-number-of-pages' for the contentlet object\", function() {", + " var entity = pm.response.json().entity;", + " var contentletData = entity.containers.SYSTEM_CONTAINER.rendered[\"uuid-1\"];", + " console.log(contentletData);", + " pm.expect(contentletData).includes(\"data-dot-on-number-of-pages\");", + "});", + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{secondPageUrl}}?language_id=1&mode=EDIT_MODE&host_id={{hostIdentifier}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{secondPageUrl}}" + ], + "query": [ + { + "key": "language_id", + "value": "1" + }, + { + "key": "mode", + "value": "EDIT_MODE" + }, + { + "key": "host_id", + "value": "{{hostIdentifier}}" + } + ] + } + }, + "response": [] } ], "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" @@ -956,7 +1036,7 @@ "value": "" }, { - "key": "pageIdentifier", + "key": "firstPageIdentifier", "value": "" }, { @@ -968,15 +1048,15 @@ "value": "" }, { - "key": "pageIdentifier2", + "key": "secondPageIdentifier", "value": "" }, { - "key": "contentType1Id", + "key": "contentTypeId", "value": "" }, { - "key": "contentType1VarName", + "key": "contentTypeVarName", "value": "" }, { @@ -984,11 +1064,11 @@ "value": "" }, { - "key": "pageName", + "key": "firstPageUrl", "value": "" }, { - "key": "pageName2", + "key": "secondPageUrl", "value": "" } ] From cb339aebdaf85b832595f826cf4361687f2c8278 Mon Sep 17 00:00:00 2001 From: ddariod Date: Sun, 4 Jan 2026 09:26:07 -0500 Subject: [PATCH 15/19] add get assertion for style properties --- ...ts_StyleProperties.postman_collection.json | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index b51afc45c656..aaf532201afc 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -896,19 +896,23 @@ "listen": "test", "script": { "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const entity = pm.response.json().entity;", + "", "pm.test(\"Only one Contentlet must be present\", function() {", - " var entity = pm.response.json().entity;", - " var contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + " const contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", " pm.expect(contentletList.length).to.eql(1);", "});", "", - "pm.test(\"The rendered section should contain data attribute 'data-dot-on-number-of-pages' for the contentlet object\", function() {", - " var entity = pm.response.json().entity;", - " var contentletData = entity.containers.SYSTEM_CONTAINER.rendered[\"uuid-1\"];", - " console.log(contentletData);", - " pm.expect(contentletData).includes(\"data-dot-on-number-of-pages\");", - "});", - "" + "pm.test(\"Validate Contentlet_1 in Second Page has correct styleProperties\", function () {", + " // filter by container", + " var contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + "", + " // filter by contentlet", + " const contentlet = contentletList.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet).to.exist;", + " pm.expect(contentlet.styleProperties.width).to.eql(\"100px\");", + "});" ], "type": "text/javascript", "packages": {}, From b7819c3924a39a9d680f5ef840482aa45459a657 Mon Sep 17 00:00:00 2001 From: ddariod Date: Sun, 4 Jan 2026 10:42:42 -0500 Subject: [PATCH 16/19] add more get styles test --- ...ts_StyleProperties.postman_collection.json | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index aaf532201afc..12e8e01b8c97 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -831,6 +831,64 @@ }, "response": [] }, + { + "name": "Add Content in 1st Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Content added to Test Page successfuly\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.errors.length).to.eql(0);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"color\": \"#FF0000\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{firstPageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{firstPageIdentifier}}", + "content" + ] + }, + "description": "Adds a single content to the created page" + }, + "response": [] + }, { "name": "Add Content in 2nd Page", "event": [ @@ -889,6 +947,70 @@ }, "response": [] }, + { + "name": "Check Styles in First Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "const entity = pm.response.json().entity;", + "", + "pm.test(\"Only one Contentlet must be present\", function() {", + " const contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + " pm.expect(contentletList.length).to.eql(1);", + "});", + "", + "pm.test(\"Validate Contentlet_1 in First Page has correct styleProperties\", function () {", + " // filter by container", + " var contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + "", + " // filter by contentlet", + " const contentlet = contentletList.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet).to.exist;", + " pm.expect(contentlet.styleProperties.color).to.eql(\"#FF0000\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{firstPageUrl}}?language_id=1&mode=EDIT_MODE&host_id={{hostIdentifier}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{firstPageUrl}}" + ], + "query": [ + { + "key": "language_id", + "value": "1" + }, + { + "key": "mode", + "value": "EDIT_MODE" + }, + { + "key": "host_id", + "value": "{{hostIdentifier}}" + } + ] + } + }, + "response": [] + }, { "name": "Check Styles in Second Page", "event": [ @@ -952,6 +1074,106 @@ } }, "response": [] + }, + { + "name": "Turn OFF Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is disabled\", function () {", + " const entity = pm.response.json().entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR Deleted');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\"key\":\"FEATURE_FLAG_UVE_STYLE_EDITOR\"}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/_delete", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Styles NOT Present for Contentlet in First Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(`Validate ${contentlet1} does not have styleProperties`, function () {", + " // filter by container", + " const entity = pm.response.json().entity;", + " const contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + " ", + " // filter by contentlet", + " const contentlet = contentletList.find(c => c.identifier === contentlet1);", + " pm.expect(contentlet).to.exist;", + " // Validate that styles are not present", + " pm.expect(contentlet.styleProperties).to.be.undefined;", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/page/render/{{firstPageUrl}}", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "render", + "{{firstPageUrl}}" + ] + } + }, + "response": [] } ], "description": "### Retrieve Contentlet Styles:\n\nTest that the Contentlets have specific Styles defined when the feature flag `FEATURE_FLAG_UVE_STYLE_EDITOR` is enabled.\n\n- Turn ON `FEATURE_FLAG_UVE_STYLE_EDITOR` to allow the visualization of the Style Properties.\n \n- Save the **same** **Contentlet** in the **same** **Container** but in **different** **Pages**\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_1`\n \n - `Contentlet 1` in the `SYSTEM_CONTAINER` **Container**, inside the **Page**`testPageStyles_2`\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_1` **Page** have the \"color = #FF0000\" Style.\n \n- Validate that the **Contentlet** `Contentlet 1` within the `testPageStyles_2` **Page** have the \"width = 100px\" Style.\n \n- Turn OFF `FEATURE_FLAG_UVE_STYLE_EDITOR`\n \n - Get **Contentlet** `Contentlet 1` does not contain `styleProperties` field" From d5de0e30edd483995d022b154452f7c96e27a767 Mon Sep 17 00:00:00 2001 From: ddariod Date: Sun, 4 Jan 2026 12:06:34 -0500 Subject: [PATCH 17/19] fix postman tests for styles --- ...ts_StyleProperties.postman_collection.json | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json index 12e8e01b8c97..6093710323fd 100644 --- a/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json +++ b/dotcms-postman/src/main/resources/postman/Define_Contentlets_StyleProperties.postman_collection.json @@ -20,9 +20,9 @@ "pm.test(\"Status code is 200\", function () {", " pm.response.to.have.status(200);", "", - " var jsonData = pm.response.json();", - " pm.collectionVariables.set(\"hostname\", jsonData.entity.hostname);", - " pm.collectionVariables.set(\"hostIdentifier\", jsonData.entity.identifier);", + " const entity = pm.response.json().entity;", + " pm.collectionVariables.set(\"hostname\", entity.hostname);", + " pm.collectionVariables.set(\"hostIdentifier\", entity.identifier);", "});" ], "type": "text/javascript", @@ -56,9 +56,9 @@ "script": { "exec": [ "pm.test(\"Test Page created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"firstPageIdentifier\", jsonData.entity.identifier);", + " const json = pm.response.json();", + " pm.expect(json.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"firstPageIdentifier\", json.entity.identifier);", "});" ], "type": "text/javascript", @@ -123,9 +123,9 @@ "script": { "exec": [ "pm.test(\"Test Page created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"secondPageIdentifier\", jsonData.entity.identifier);", + " const json = pm.response.json();", + " pm.expect(json.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"secondPageIdentifier\", json.entity.identifier);", "});" ], "type": "text/javascript", @@ -194,13 +194,12 @@ "});", "", "pm.test(\"Store first content type ID\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.entity).to.not.be.null;", - " pm.expect(jsonData.entity[0]).to.not.be.null;", - " pm.expect(jsonData.entity[0].id).to.not.be.null;", - " pm.collectionVariables.set(\"contentTypeId\", jsonData.entity[0].id);", - " pm.collectionVariables.set(\"contentTypeVarName\", jsonData.entity[0].variable);", - " console.log('First content type created with ID:', jsonData.entity[0].id);", + " const entity = pm.response.json().entity;", + " pm.expect(entity).to.not.be.null;", + " pm.expect(entity[0]).to.not.be.null;", + " pm.expect(entity[0].id).to.not.be.null;", + " pm.collectionVariables.set(\"contentTypeId\", entity[0].id);", + " pm.collectionVariables.set(\"contentTypeVarName\", entity[0].variable);", "});" ], "type": "text/javascript", @@ -257,11 +256,10 @@ "});", "", "pm.test(\"Store container information\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.entity).to.not.be.null;", - " pm.expect(jsonData.entity.identifier).to.not.be.null;", - " pm.collectionVariables.set(\"containerId\", jsonData.entity.identifier);", - " console.log('Container created with ID:', jsonData.entity.identifier);", + " const entity = pm.response.json().entity;", + " pm.expect(entity).to.not.be.null;", + " pm.expect(entity.identifier).to.not.be.null;", + " pm.collectionVariables.set(\"containerId\", entity.identifier);", "});" ], "type": "text/javascript", @@ -314,9 +312,9 @@ "script": { "exec": [ "pm.test(\"Test Rich Text created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"Contentlet_1\", jsonData.entity.identifier);", + " const json = pm.response.json();", + " pm.expect(json.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_1\", json.entity.identifier);", "});" ], "type": "text/javascript", @@ -370,9 +368,9 @@ "script": { "exec": [ "pm.test(\"Test Rich Text created successfully\", function () {", - " var jsonData = pm.response.json();", - " pm.expect(jsonData.errors.length).to.eql(0);", - " pm.collectionVariables.set(\"Contentlet_2\", jsonData.entity.identifier);", + " const json = pm.response.json();", + " pm.expect(json.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_2\", json.entity.identifier);", "});" ], "type": "text/javascript", @@ -529,15 +527,15 @@ " pm.response.to.have.status(200);", "});", "", - "// Parse JSON", - "const json = pm.response.json();", + "// Parse entity JSON", + "const entity = pm.response.json().entity;", "", "pm.test(\"Entity array exists\", function () {", - " pm.expect(json.entity).to.be.an(\"array\").that.is.not.empty;", + " pm.expect(entity).to.be.an(\"array\").that.is.not.empty;", "});", "", "pm.test(`Validate ${contentlet1} has correct styleProperties`, function () {", - " const contentlet = json.entity.find(item => item.contentletId === contentlet1);", + " const contentlet = entity.find(item => item.contentletId === contentlet1);", " pm.expect(contentlet).to.exist;", " pm.expect(contentlet.styleProperties).to.be.an(\"object\");", " pm.expect(contentlet.styleProperties.height).to.eql(300);", @@ -789,11 +787,8 @@ " pm.response.to.have.status(200);", "});", "", - "// Parse JSON", - "const json = pm.response.json();", - "", "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", - " const entity = json.entity;", + " const entity = pm.response.json().entity;", " pm.expect(entity).to.exist;", " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", "});" @@ -964,7 +959,7 @@ "", "pm.test(\"Validate Contentlet_1 in First Page has correct styleProperties\", function () {", " // filter by container", - " var contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + " const contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", "", " // filter by contentlet", " const contentlet = contentletList.find(c => c.identifier === contentlet1);", @@ -1028,7 +1023,7 @@ "", "pm.test(\"Validate Contentlet_1 in Second Page has correct styleProperties\", function () {", " // filter by container", - " var contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", + " const contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", "", " // filter by contentlet", " const contentlet = contentletList.find(c => c.identifier === contentlet1);", @@ -1138,11 +1133,11 @@ " pm.response.to.have.status(200);", "});", "", - "pm.test(`Validate ${contentlet1} does not have styleProperties`, function () {", + "pm.test(\"Validate Contentlet_1 in First Page has NOT styleProperties\", function () {", " // filter by container", " const entity = pm.response.json().entity;", " const contentletList = entity.containers.SYSTEM_CONTAINER.contentlets[\"uuid-1\"];", - " ", + "", " // filter by contentlet", " const contentlet = contentletList.find(c => c.identifier === contentlet1);", " pm.expect(contentlet).to.exist;", @@ -1160,7 +1155,7 @@ "method": "GET", "header": [], "url": { - "raw": "{{serverURL}}/api/v1/page/render/{{firstPageUrl}}", + "raw": "{{serverURL}}/api/v1/page/render/{{firstPageUrl}}?language_id=1&mode=EDIT_MODE&host_id={{hostIdentifier}}", "host": [ "{{serverURL}}" ], @@ -1170,6 +1165,20 @@ "page", "render", "{{firstPageUrl}}" + ], + "query": [ + { + "key": "language_id", + "value": "1" + }, + { + "key": "mode", + "value": "EDIT_MODE" + }, + { + "key": "host_id", + "value": "{{hostIdentifier}}" + } ] } }, From 4d60a02c10ff9d7004dd9f3da691e2084eca9735 Mon Sep 17 00:00:00 2001 From: ddariod Date: Sun, 4 Jan 2026 15:02:33 -0500 Subject: [PATCH 18/19] add test for graphql --- .../main/resources/postman/GraphQLTests.json | 631 ++++++++++++++++++ 1 file changed, 631 insertions(+) diff --git a/dotcms-postman/src/main/resources/postman/GraphQLTests.json b/dotcms-postman/src/main/resources/postman/GraphQLTests.json index 55631d11e4be..fb67c876edf9 100644 --- a/dotcms-postman/src/main/resources/postman/GraphQLTests.json +++ b/dotcms-postman/src/main/resources/postman/GraphQLTests.json @@ -4360,6 +4360,613 @@ } ] }, + { + "name": "Checking Style Properties", + "item": [ + { + "name": "Get default site", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "", + " const entity = pm.response.json().entity;", + " pm.collectionVariables.set(\"hostname\", entity.hostname);", + " pm.collectionVariables.set(\"hostIdentifier\", entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{serverURL}}/api/v1/site/defaultSite", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "site", + "defaultSite" + ] + } + }, + "response": [] + }, + { + "name": "Create Test Page", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Page created successfully\", function () {", + " const json = pm.response.json();", + " pm.expect(json.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"pageIdentifier\", json.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"pageUrl\", \"contentlet-styles-test-page\");" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"htmlpageasset\",\n \"title\": \"Test Page Styles_{{$timestamp}}\",\n \"url\": \"{{pageUrl}}\",\n \"hostFolder\": \"{{hostname}}\",\n \"template\": \"SYSTEM_TEMPLATE\",\n \"friendlyName\": \"First Test Page Styles_{{$timestamp}}\",\n \"cachettl\": 0\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ] + }, + "description": "Creates a test page" + }, + "response": [] + }, + { + "name": "Create Test Content Type", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Store first content type ID\", function () {", + " const entity = pm.response.json().entity;", + " pm.expect(entity).to.not.be.null;", + " pm.expect(entity[0]).to.not.be.null;", + " pm.expect(entity[0].id).to.not.be.null;", + " pm.collectionVariables.set(\"contentTypeId\", entity[0].id);", + " pm.collectionVariables.set(\"contentTypeVarName\", entity[0].variable);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"clazz\": \"com.dotcms.contenttype.model.type.ImmutableSimpleContentType\",\n \"defaultType\": false,\n \"name\": \"Styles_Test_ContentType_{{$timestamp}}\",\n \"description\": \"Content type for contentlet styles tests\",\n \"host\": \"{{hostname}}\",\n \"owner\": \"dotcms.org.1\",\n \"fixed\": false,\n \"system\": false,\n \"folder\": \"SYSTEM_FOLDER\",\n \"fields\": [\n {\n \"dataType\": \"SYSTEM\",\n \"dbColumn\": \"system_field1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableHostFolderField\",\n \"indexed\": true,\n \"listed\": false,\n \"name\": \"Host/Folder\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 1,\n \"unique\": false,\n \"variable\": \"hostfolder\"\n },\n {\n \"dataType\": \"TEXT\",\n \"dbColumn\": \"text1\",\n \"fieldVariables\": [],\n \"fixed\": false,\n \"clazz\": \"com.dotcms.contenttype.model.field.ImmutableTextField\",\n \"indexed\": true,\n \"listed\": true,\n \"name\": \"title\",\n \"readOnly\": false,\n \"required\": true,\n \"searchable\": true,\n \"sortOrder\": 2,\n \"unique\": false,\n \"variable\": \"title\"\n }\n ],\n \"workflow\": [\n \"d61a59e1-a49c-46f2-a929-db2b4bfa88b2\"\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/contenttype", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "contenttype" + ] + } + }, + "response": [] + }, + { + "name": "Create Test Contentlet", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Test Rich Text created successfully\", function () {", + " const json = pm.response.json();", + " pm.expect(json.errors.length).to.eql(0);", + " pm.collectionVariables.set(\"Contentlet_1\", json.entity.identifier);", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"contentlet\": {\n \"contentType\": \"{{contentTypeVarName}}\",\n \"title\": \"Contentlet 1\",\n \"hostfolder\": \"{{hostname}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/workflow/actions/default/fire/PUBLISH", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "workflow", + "actions", + "default", + "fire", + "PUBLISH" + ] + }, + "description": "Creates test data" + }, + "response": [] + }, + { + "name": "Save Content With Basic Styles Copy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "// Parse JSON", + "const json = pm.response.json();", + "", + "pm.test(\"No errors returned\", function () {", + " pm.expect(json.errors).to.be.an(\"array\").that.is.empty;", + "});", + "", + "pm.test(\"Contentlet_1 has correct styleProperties\", function () {", + " const first = json.entity.find(item => item.contentletId === contentlet1);", + " pm.expect(first).to.exist;", + " pm.expect(first.styleProperties).to.be.an(\"object\");", + " pm.expect(first.styleProperties.width).to.eql(\"100px\");", + " pm.expect(first.styleProperties.color).to.eql(\"#FF0000\");", + " pm.expect(first.styleProperties.margin).to.eql(\"10px\");", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"identifier\": \"SYSTEM_CONTAINER\",\n \"uuid\": \"1\",\n \"contentletsId\": [\n \"{{Contentlet_1}}\"\n ],\n \"styleProperties\": {\n \"{{Contentlet_1}}\": {\n \"width\": \"100px\",\n \"color\": \"#FF0000\",\n \"margin\": \"10px\"\n }\n }\n }\n]", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/page/{{pageIdentifier}}/content", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "page", + "{{pageIdentifier}}", + "content" + ] + }, + "description": "Test when users make a request sending the style properties for some contentlets.\nThis will save the style properties for the specified contentlets, in case style properties are not send the contentlet style properties will be null." + }, + "response": [] + }, + { + "name": "Turn ON Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is enabled\", function () {", + " const entity = pm.response.json().entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR saved/updated');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"key\": \"FEATURE_FLAG_UVE_STYLE_EDITOR\",\n \"value\": \"true\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "" + ] + } + }, + "response": [] + }, + { + "name": "GivenRequestByURI_ContainerContentletsFieldContainsStyleProperties", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "const response = pm.response.json();", + "", + "pm.test(\"GraphQL response has no errors\", function () {", + " pm.expect(response.errors).to.be.undefined;", + "});", + "", + "pm.test(\"Page data exists\", function () {", + " pm.expect(response.data).to.exist;", + " pm.expect(response.data.page).to.exist;", + "});", + "", + "// Finding the Container (Logic adjusted for nested structure)", + "let targetContainerWrapper = null;", + "", + "pm.test(\"Target Container exists\", function () {", + " const containers = response.data.page.containers;", + " ", + " // We have to look inside the 'containerContentlets' array of each container to find the UUID 'uuid-1'", + " containers.forEach(container => {", + " if(container.containerContentlets) {", + " const found = container.containerContentlets.find(c => c.uuid === 'uuid-1');", + " if(found) targetContainerWrapper = found;", + " }", + " });", + "", + " pm.expect(targetContainerWrapper, \"Could not find container with uuid-1\").to.exist;", + "});", + "", + "// Finding the Contentlet", + "let targetContentlet = null;", + "", + "pm.test(\"Contentlet exists in container\", function () {", + " // Only run this if previous test passed", + " pm.expect(targetContainerWrapper).to.exist; ", + "", + " targetContentlet = targetContainerWrapper.contentlets.find(c => c.identifier === contentlet1);", + " pm.expect(targetContentlet, \"Contentlet not found\").to.exist;", + "});", + "", + "// Checking Style Values", + "pm.test(\"Styles have correct width\", function () {", + " pm.expect(targetContentlet.styles).to.not.be.null;", + " pm.expect(targetContentlet.styles.width).to.eql('100px');", + " pm.expect(targetContentlet.styles.color).to.eql('#FF0000');", + " pm.expect(targetContentlet.styles.margin).to.eql('10px');", + "});", + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "user-agent": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Cookie", + "value": "JSESSIONID=1DF38761AD8B360EF1AD42C4AF07EC35", + "type": "text", + "disabled": true + }, + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36", + "type": "text" + } + ], + "body": { + "mode": "graphql", + "graphql": { + "query": "{\n page(url: \"testPageStyles_1_1767383996\") {\n containers {\n containerContentlets {\n uuid\n contentlets {\n identifier\n title\n styles: _map(key: \"styleProperties\")\n }\n }\n }\n }\n}\n", + "variables": "" + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/graphql", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "graphql" + ] + } + }, + "response": [] + }, + { + "name": "Turn OFF Style Editor", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"FEATURE_FLAG_UVE_STYLE_EDITOR is disabled\", function () {", + " const entity = pm.response.json().entity;", + " pm.expect(entity).to.exist;", + " pm.expect(entity).to.eql('FEATURE_FLAG_UVE_STYLE_EDITOR Deleted');", + "});" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "body": { + "mode": "raw", + "raw": "{\"key\":\"FEATURE_FLAG_UVE_STYLE_EDITOR\"}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/system-table/_delete", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "system-table", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "GivenRequestByURI_ContainerContentletsFieldNOTContainsStyleProperties", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "const contentlet1 = pm.collectionVariables.get(\"Contentlet_1\");", + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + "});", + "", + "const response = pm.response.json();", + "", + "pm.test(\"GraphQL response has no errors\", function () {", + " pm.expect(response.errors).to.be.undefined;", + "});", + "", + "pm.test(\"Page data exists\", function () {", + " pm.expect(response.data).to.exist;", + " pm.expect(response.data.page).to.exist;", + "});", + "", + "// Finding the Container (Logic adjusted for nested structure)", + "let targetContainerWrapper = null;", + "", + "pm.test(\"Target Container exists\", function () {", + " const containers = response.data.page.containers;", + " ", + " // We have to look inside the 'containerContentlets' array of each container to find the UUID 'uuid-1'", + " containers.forEach(container => {", + " if(container.containerContentlets) {", + " const found = container.containerContentlets.find(c => c.uuid === 'uuid-1');", + " if(found) targetContainerWrapper = found;", + " }", + " });", + "", + " pm.expect(targetContainerWrapper, \"Could not find container with uuid-1\").to.exist;", + "});", + "", + "// Finding the Contentlet", + "let targetContentlet = null;", + "", + "pm.test(\"Contentlet exists in container\", function () {", + " // Only run this if previous test passed", + " pm.expect(targetContainerWrapper).to.exist; ", + "", + " targetContentlet = targetContainerWrapper.contentlets.find(c => c.identifier === contentlet1);", + " pm.expect(targetContentlet, \"Contentlet not found\").to.exist;", + "});", + "", + "// Checking Styles", + "pm.test(\"Contentlet has styles field\", function () {", + " pm.expect(targetContentlet).to.exist;", + " pm.expect(targetContentlet).to.have.property('styles');", + " pm.expect(targetContentlet.styles).to.be.null;", + "});", + "" + ], + "type": "text/javascript", + "packages": {}, + "requests": {} + } + } + ], + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "user-agent": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "Cookie", + "value": "JSESSIONID=1DF38761AD8B360EF1AD42C4AF07EC35", + "type": "text", + "disabled": true + }, + { + "key": "User-Agent", + "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36", + "type": "text" + } + ], + "body": { + "mode": "graphql", + "graphql": { + "query": "{\n page(url: \"testPageStyles_1_1767383996\") {\n containers {\n containerContentlets {\n uuid\n contentlets {\n identifier\n title\n styles: _map(key: \"styleProperties\")\n }\n }\n }\n }\n}\n", + "variables": "" + } + }, + "url": { + "raw": "{{serverURL}}/api/v1/graphql", + "host": [ + "{{serverURL}}" + ], + "path": [ + "api", + "v1", + "graphql" + ] + } + }, + "response": [] + } + ] + }, { "name": "pre_ImportBundleWithMexicoPageAndRule", "event": [ @@ -13902,6 +14509,30 @@ { "key": "lockedByName", "value": "" + }, + { + "key": "hostname", + "value": "" + }, + { + "key": "hostIdentifier", + "value": "" + }, + { + "key": "pageIdentifier", + "value": "" + }, + { + "key": "contentTypeId", + "value": "" + }, + { + "key": "contentTypeVarName", + "value": "" + }, + { + "key": "Contentlet_1", + "value": "" } ] } \ No newline at end of file From e27016ec131d99c98cd49e62b79221e9363394d8 Mon Sep 17 00:00:00 2001 From: ddariod Date: Sun, 4 Jan 2026 15:34:06 -0500 Subject: [PATCH 19/19] use variables in GraphQLTests.json for styles --- .../main/resources/postman/GraphQLTests.json | 38 ++++--------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/dotcms-postman/src/main/resources/postman/GraphQLTests.json b/dotcms-postman/src/main/resources/postman/GraphQLTests.json index fb67c876edf9..45ea1cfbc020 100644 --- a/dotcms-postman/src/main/resources/postman/GraphQLTests.json +++ b/dotcms-postman/src/main/resources/postman/GraphQLTests.json @@ -4424,7 +4424,7 @@ "listen": "prerequest", "script": { "exec": [ - "pm.collectionVariables.set(\"pageUrl\", \"contentlet-styles-test-page\");" + "pm.collectionVariables.set(\"pageUrl\", \"contentlet-styles-test-page\" + Date.now());" ], "type": "text/javascript", "packages": {}, @@ -4774,24 +4774,12 @@ }, "request": { "method": "POST", - "header": [ - { - "key": "Cookie", - "value": "JSESSIONID=1DF38761AD8B360EF1AD42C4AF07EC35", - "type": "text", - "disabled": true - }, - { - "key": "User-Agent", - "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36", - "type": "text" - } - ], + "header": [], "body": { "mode": "graphql", "graphql": { - "query": "{\n page(url: \"testPageStyles_1_1767383996\") {\n containers {\n containerContentlets {\n uuid\n contentlets {\n identifier\n title\n styles: _map(key: \"styleProperties\")\n }\n }\n }\n }\n}\n", - "variables": "" + "query": "query getPageData($url: String!) {\n page(url: $url) {\n containers {\n containerContentlets {\n uuid\n contentlets {\n identifier\n title\n styles: _map(key: \"styleProperties\")\n }\n }\n }\n }\n}\n", + "variables": "{\n \"url\": \"{{pageUrl}}\"\n}" } }, "url": { @@ -4931,24 +4919,12 @@ }, "request": { "method": "POST", - "header": [ - { - "key": "Cookie", - "value": "JSESSIONID=1DF38761AD8B360EF1AD42C4AF07EC35", - "type": "text", - "disabled": true - }, - { - "key": "User-Agent", - "value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36", - "type": "text" - } - ], + "header": [], "body": { "mode": "graphql", "graphql": { - "query": "{\n page(url: \"testPageStyles_1_1767383996\") {\n containers {\n containerContentlets {\n uuid\n contentlets {\n identifier\n title\n styles: _map(key: \"styleProperties\")\n }\n }\n }\n }\n}\n", - "variables": "" + "query": "query getPageData($url: String!) {\n page(url: $url) {\n containers {\n containerContentlets {\n uuid\n contentlets {\n identifier\n title\n styles: _map(key: \"styleProperties\")\n }\n }\n }\n }\n}\n", + "variables": "{\n \"url\": \"{{pageUrl}}\"\n}" } }, "url": {