Merge remote-tracking branch 'origin/v11/dev' into v12/dev

This commit is contained in:
Bjarke Berg
2023-03-02 08:47:38 +01:00
40 changed files with 3287 additions and 124 deletions

View File

@@ -0,0 +1,89 @@
<style>
:host {
min-height: 160px;
}
button > * {
vertical-align: middle;
}
button {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
color: black;
background-color: transparent;
text-align: left;
padding: 0;
user-select: none;
border: none;
transition: border-color 120ms, background-color 120ms;
max-height: 80vh;
overflow:hidden;
}
button:hover {
color: #2152A3;
}
img {
object-fit: cover;
height: 100%;
width: 100%;
flex-grow: 0;
}
.icon {
font-size: 60px;
display: block;
}
.umb-icon {
display: inline-block;
width: 1em;
height: 1em;
flex-shrink: 0;
}
.umb-icon svg {
width: 100%;
height: 100%;
fill: currentColor;
animation: inherit;
}
.file-name {
background-color: rgba(255, 255, 255, 0.8);
color: black;
padding: 3px 6px;
position: absolute;
bottom: 0;
right: 0;
opacity: var(--umb-block-grid--block-ui-opacity, 0);
transition: opacity 120ms;
}
.is-trashed {
background-color: #d42054 !important;
color:white !important;
}
.is-trashed .file-name {
opacity: 1;
}
</style>
<button type="button" name="BlockGridCustomView" ng-click="block.edit()" ng-focus="block.focus" ng-class="{'is-trashed': mediaItem.trashed}">
{{mediaItem = (block.data.image[0].mediaKey | mediaItemResolver); ""}}
<img ng-if="mediaItem !== null && (mediaItem.mediaLink.indexOf('jpg') !== -1 || mediaItem.mediaLink.indexOf('png') !== -1 || mediaItem.mediaLink.indexOf('webp') !== -1 || mediaItem.mediaLink.indexOf('gif') !== -1) && !mediaItem.trashed" ng-src="{{mediaItem.mediaLink}}" alt="{{mediaItem.name}}" />
<umb-icon ng-if="mediaItem !== null && mediaItem.mediaLink.indexOf('jpg') === -1 && mediaItem.mediaLink.indexOf('png') === -1 && mediaItem.mediaLink.indexOf('webp') === -1 && mediaItem.mediaLink.indexOf('gif') === -1 || mediaItem.trashed" icon="{{mediaItem.contentType.icon}}" class="icon"></umb-icon>
<span ng-if="mediaItem !== null && mediaItem.name" class="file-name">
<span ng-if="mediaItem.trashed"><localize key="mediaPicker_trashed">Trashed</localize>:</span>
{{mediaItem.name}}
</span>
</button>

View File

@@ -0,0 +1,7 @@
.body{
font-family: 'Lato';
font-weight: 200;
font-size: 22px;
margin-top: 0.3em;
color: blue;
}

View File

@@ -0,0 +1,51 @@
.umb-block-grid__layout-container {
position: relative;
display: grid;
grid-template-columns: repeat(var(--umb-block-grid--grid-columns, 1), minmax(0, 1fr));
grid-auto-flow: row;
grid-auto-rows: minmax(50px, -webkit-min-content);
grid-auto-rows: minmax(50px, min-content);
-moz-column-gap: var(--umb-block-grid--column-gap, 0);
column-gap: var(--umb-block-grid--column-gap, 0);
row-gap: var(--umb-block-grid--row-gap, 0);
}
.umb-block-grid__layout-item {
position: relative;
/* For small devices we scale columnSpan by three, to make everything bigger than 1/3 take full width: */
grid-column-end: span min(calc(var(--umb-block-grid--item-column-span, 1) * 3), var(--umb-block-grid--grid-columns));
grid-row: span var(--umb-block-grid--item-row-span, 1);
}
.umb-block-grid__area-container, .umb-block-grid__block--view::part(area-container) {
position: relative;
display: grid;
grid-template-columns: repeat(var(--umb-block-grid--area-grid-columns, var(--umb-block-grid--grid-columns, 1)), minmax(0, 1fr));
grid-auto-flow: row;
grid-auto-rows: minmax(50px, -webkit-min-content);
grid-auto-rows: minmax(50px, min-content);
-moz-column-gap: var(--umb-block-grid--areas-column-gap, 0);
column-gap: var(--umb-block-grid--areas-column-gap, 0);
row-gap: var(--umb-block-grid--areas-row-gap, 0);
}
.umb-block-grid__area {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
/* For small devices we scale columnSpan by three, to make everything bigger than 1/3 take full width: */
grid-column-end: span min(calc(var(--umb-block-grid--area-column-span, 1) * 3), var(--umb-block-grid--area-grid-columns));
grid-row: span var(--umb-block-grid--area-row-span, 1);
}
@media (min-width:1024px) {
.umb-block-grid__layout-item {
grid-column-end: span min(var(--umb-block-grid--item-column-span, 1), var(--umb-block-grid--grid-columns));
}
.umb-block-grid__area {
grid-column-end: span min(var(--umb-block-grid--area-column-span, 1), var(--umb-block-grid--area-grid-columns));

View File

@@ -0,0 +1,8 @@
.title{
font-family: 'Lato';
font-weight: 300;
font-size: 34px;
margin-top: 0.5em;
color: red;
}

View File

@@ -7,8 +7,8 @@
"name": "acceptancetest",
"hasInstallScript": true,
"dependencies": {
"@umbraco/json-models-builders": "^1.0.3",
"@umbraco/playwright-testhelpers": "^1.0.21",
"@umbraco/json-models-builders": "^1.0.5",
"@umbraco/playwright-testhelpers": "^1.0.22",
"camelize": "^1.0.0",
"dotenv": "^16.0.2",
"faker": "^4.1.0",
@@ -17,7 +17,7 @@
"xhr2": "^0.2.1"
},
"devDependencies": {
"@playwright/test": "^1.19.2",
"@playwright/test": "^1.31",
"del": "^6.0.0",
"ncp": "^2.0.0",
"prompt": "^1.2.0",
@@ -86,19 +86,22 @@
}
},
"node_modules/@playwright/test": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.26.0.tgz",
"integrity": "sha512-D24pu1k/gQw3Lhbpc38G5bXlBjGDrH5A52MsrH12wz6ohGDeQ+aZg/JFSEsT/B3G8zlJe/EU4EkJK74hpqsjEg==",
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.31.1.tgz",
"integrity": "sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==",
"dev": true,
"dependencies": {
"@types/node": "*",
"playwright-core": "1.26.0"
"playwright-core": "1.31.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=14"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/@sideway/address": {
@@ -129,20 +132,20 @@
"dev": true
},
"node_modules/@umbraco/json-models-builders": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-1.0.3.tgz",
"integrity": "sha512-NNBIP9ZXXZvxanmG5OvE+Ppc2ObSLLUyBbwZiPtwerFxdlnYuUYA6qCq6mj7vx3na6MOQTPZMAiNFEaM0V9xFw==",
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-1.0.5.tgz",
"integrity": "sha512-14xowT8oiW9+DQVOoundRPvcvnNrU0Ey+06G/q/iZyUnqaNRu/i5nUqcbUZGdv6VBCdxaxq2H3WwtSET3gtneA==",
"dependencies": {
"camelize": "^1.0.0",
"faker": "^4.1.0"
}
},
"node_modules/@umbraco/playwright-testhelpers": {
"version": "1.0.21",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.21.tgz",
"integrity": "sha512-JfE1MvKc7LEVayF9AX4Ctmx8c6+M+m6+mV7g7QSOYPO7ky/PSlzVvI9S9S7vcpuwLB2Vp4NE9PcXaXUGEvNCnw==",
"version": "1.0.22",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.22.tgz",
"integrity": "sha512-hFqqQvEIylagfqFyhQ2rSyYlUP+xpWA5lkhJjkpb2qpxkIISxjwC/FYJTJGvcoBHuUaZrjsSv4lM2aJy2ZWHMA==",
"dependencies": {
"@umbraco/json-models-builders": "^1.0.2",
"@umbraco/json-models-builders": "^1.0.5",
"camelize": "^1.0.0",
"faker": "^4.1.0",
"form-data": "^4.0.0",
@@ -409,6 +412,20 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -725,9 +742,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.26.0.tgz",
"integrity": "sha512-p8huU8eU4gD3VkJd3DA1nA7R3XA6rFvFL+1RYS96cSljCF2yJE9CWEHTPF4LqX8KN9MoWCrAfVKP5381X3CZqg==",
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.1.tgz",
"integrity": "sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==",
"dev": true,
"bin": {
"playwright": "cli.js"
@@ -1018,13 +1035,14 @@
}
},
"@playwright/test": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.26.0.tgz",
"integrity": "sha512-D24pu1k/gQw3Lhbpc38G5bXlBjGDrH5A52MsrH12wz6ohGDeQ+aZg/JFSEsT/B3G8zlJe/EU4EkJK74hpqsjEg==",
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.31.1.tgz",
"integrity": "sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==",
"dev": true,
"requires": {
"@types/node": "*",
"playwright-core": "1.26.0"
"fsevents": "2.3.2",
"playwright-core": "1.31.1"
}
},
"@sideway/address": {
@@ -1055,20 +1073,20 @@
"dev": true
},
"@umbraco/json-models-builders": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-1.0.3.tgz",
"integrity": "sha512-NNBIP9ZXXZvxanmG5OvE+Ppc2ObSLLUyBbwZiPtwerFxdlnYuUYA6qCq6mj7vx3na6MOQTPZMAiNFEaM0V9xFw==",
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-1.0.5.tgz",
"integrity": "sha512-14xowT8oiW9+DQVOoundRPvcvnNrU0Ey+06G/q/iZyUnqaNRu/i5nUqcbUZGdv6VBCdxaxq2H3WwtSET3gtneA==",
"requires": {
"camelize": "^1.0.0",
"faker": "^4.1.0"
}
},
"@umbraco/playwright-testhelpers": {
"version": "1.0.21",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.21.tgz",
"integrity": "sha512-JfE1MvKc7LEVayF9AX4Ctmx8c6+M+m6+mV7g7QSOYPO7ky/PSlzVvI9S9S7vcpuwLB2Vp4NE9PcXaXUGEvNCnw==",
"version": "1.0.22",
"resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-1.0.22.tgz",
"integrity": "sha512-hFqqQvEIylagfqFyhQ2rSyYlUP+xpWA5lkhJjkpb2qpxkIISxjwC/FYJTJGvcoBHuUaZrjsSv4lM2aJy2ZWHMA==",
"requires": {
"@umbraco/json-models-builders": "^1.0.2",
"@umbraco/json-models-builders": "^1.0.5",
"camelize": "^1.0.0",
"faker": "^4.1.0",
"form-data": "^4.0.0",
@@ -1273,6 +1291,13 @@
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -1503,9 +1528,9 @@
"dev": true
},
"playwright-core": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.26.0.tgz",
"integrity": "sha512-p8huU8eU4gD3VkJd3DA1nA7R3XA6rFvFL+1RYS96cSljCF2yJE9CWEHTPF4LqX8KN9MoWCrAfVKP5381X3CZqg==",
"version": "1.31.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.1.tgz",
"integrity": "sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==",
"dev": true
},
"prompt": {

View File

@@ -10,7 +10,7 @@
"createTest": "node createTest.js"
},
"devDependencies": {
"@playwright/test": "^1.19.2",
"@playwright/test": "^1.31",
"typescript": "^4.8.3",
"tslib": "^2.4.0",
"del": "^6.0.0",
@@ -19,8 +19,8 @@
"wait-on": "^6.0.1"
},
"dependencies": {
"@umbraco/json-models-builders": "^1.0.3",
"@umbraco/playwright-testhelpers": "^1.0.21",
"@umbraco/json-models-builders": "^1.0.5",
"@umbraco/playwright-testhelpers": "^1.0.22",
"camelize": "^1.0.0",
"faker": "^4.1.0",
"form-data": "^4.0.0",

View File

@@ -36,6 +36,7 @@ const config: PlaywrightTestConfig = {
// baseURL: 'http://localhost:44332',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
// When working locally it can be a good idea to use trace: 'on-first-retry' instead of 'retain-on-failure', it can cut the local test times in half.
trace: 'retain-on-failure',
ignoreHTTPSErrors: true,
},

View File

@@ -0,0 +1,355 @@
import {AliasHelper, ConstantHelper, test} from "@umbraco/playwright-testhelpers";
import {BlockGridDataTypeBuilder} from "@umbraco/json-models-builders/dist/lib/builders/dataTypes";
import {ContentBuilder, DocumentTypeBuilder} from "@umbraco/json-models-builders";
import {expect} from "@playwright/test";
test.describe('BlockGridEditorAdvancedContent', () => {
const documentName = 'DocumentTest';
const blockGridName = 'BlockGridTest';
const elementName = 'ElementTitle';
const documentAlias = AliasHelper.toAlias(documentName);
const blockGridAlias = AliasHelper.toAlias(blockGridName);
const elementAlias = AliasHelper.toAlias(elementName);
test.beforeEach(async ({page, umbracoApi, umbracoUi}, testInfo) => {
await umbracoApi.report.report(testInfo);
await umbracoApi.login();
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
});
test.afterEach(async ({page, umbracoApi, umbracoUi}) => {
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
});
test.describe('Advanced', () => {
test('can see custom view in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
// CustomView
const customViewItemName = "Image";
const customViewFileName = "Image.html";
const customViewPath = 'customViews/' + customViewFileName;
const customViewMimeType = "text/html";
// Image
const imageName = "Umbraco";
const umbracoFileValue = {"src": "Umbraco.png"};
const imageFileName = "Umbraco.png";
const imagePath = 'mediaLibrary/' + imageFileName;
const imageMimeType = "image/png";
await umbracoApi.media.ensureNameNotExists(imageName);
await umbracoApi.media.ensureNameNotExists(customViewItemName);
const imageData = await umbracoApi.media.createImageWithFile(imageName, umbracoFileValue, imageFileName, imagePath, imageMimeType);
const customViewData = await umbracoApi.media.createFileWithFile(customViewItemName, customViewFileName, customViewPath, customViewMimeType);
const customViewMediaPath = customViewData.mediaLink;
const element = new DocumentTypeBuilder()
.withName(elementName)
.withAlias(elementAlias)
.AsElementType()
.addGroup()
.withName('ImageGroup')
.withAlias('imageGroup')
.addImagePickerProperty()
.withLabel('Image')
.withAlias('image')
.done()
.done()
.build();
await umbracoApi.documentTypes.save(element);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withView(customViewMediaPath)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, element, dataType);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.addImage()
.withMediaKey(imageData.key)
.done()
.done()
.addLayout()
.withContentUdi(element['key'])
.done()
.done()
.done()
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the block has the correct CustomView
await expect(page.locator('[data-content-element-type-key="' + element['key'] + '"]').locator('[view="' + customViewMediaPath + '"]')).toBeVisible();
// Checks if the custom view updated the block by locating a name in the customView
await expect(page.locator('[data-content-element-type-key="' + element['key'] + '"]').locator('[view="' + customViewMediaPath + '"]').locator('[name="BlockGridCustomView"]')).toBeVisible();
// Checks if the block is clickable
await page.locator('[data-content-element-type-key="' + element['key'] + '"]').click();
// Clean
await umbracoApi.media.ensureNameNotExists(customViewItemName);
await umbracoApi.media.ensureNameNotExists(imageName);
});
test('can see custom stylesheet in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const stylesheetName = "StylesheetBlockGrid.css";
const stylesheetPath = "stylesheet/" + stylesheetName;
const stylesheetMimeType = "text/css";
await umbracoApi.media.ensureNameNotExists(stylesheetName);
const stylesheetData = await umbracoApi.media.createFileWithFile(stylesheetName, stylesheetName, stylesheetPath, stylesheetMimeType);
const stylesheetDataPath = stylesheetData.mediaLink;
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withStylesheet(stylesheetDataPath)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the block has the correct template
await expect(page.locator('umb-block-grid-entry', {hasText: elementName}).locator('umb-block-grid-block')).toHaveAttribute('stylesheet', stylesheetDataPath);
// Clean
await umbracoApi.media.ensureNameNotExists(stylesheetName);
});
test('can see changed overlay editor size in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const editorSize = 'large';
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withEditorSize(editorSize)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Opens the content editor
await page.locator('[data-content-element-type-key="' + element['key'] + '"]').click();
// Assert
// Checks if the editor contains the correct editor size
await expect(page.locator('.umb-editor--' + editorSize).locator('[id="sub-view-0"]')).toBeVisible();
});
test('can use inline editing mode in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const newText = 'UpdatedText';
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withInlineEditing(true)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Updates the block text by using the inline editing mode
await page.locator('[data-element="property-' + blockGridAlias + '"]').locator('[id="title"]').click();
await page.locator('[data-element="property-' + blockGridAlias + '"]').locator('[id="title"]').fill(newText);
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the value in the block was updated by using the inline editing mode
await expect(page.locator('[data-element="property-' + blockGridAlias + '"]').locator('[id="title"]:visible')).toHaveValue(newText);
});
test('can hide content editor', async ({page, umbracoApi, umbracoUi}) => {
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withForceHideContentEditorInOverlay(true)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Click the block
await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName}).click();
// Assert
// Checks if the block is still clickable, if it's clickable that means the the content editor is hidden
await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName}).click();
});
});
test.describe('Catalogue appearance', () => {
test('can see background color in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const elementTwoName = 'TheSecondElement';
const elementTwoAlias = AliasHelper.toAlias(elementTwoName);
const backgroundColor = 'rgb(244, 67, 54)';
await umbracoApi.documentTypes.ensureNameNotExists(elementTwoName);
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const elementTwo = await umbracoApi.documentTypes.createDefaultElementType(elementTwoName, elementTwoAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withBackgroundColor(backgroundColor)
.done()
.addBlock()
.withContentElementTypeKey(elementTwo['key'])
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Opens the content editor
await page.locator('[data-element="property-' + blockGridAlias + '"]').getByRole('button', {name: 'Add content'}).click();
// Assert
// Checks if the element has the set background color
await expect(page.locator('umb-block-card', {hasText: elementName}).locator('[style="background-color: ' + backgroundColor + '; background-image: none;"]')).toBeVisible();
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementTwoName);
});
test('can see icon color in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const elementTwoName = 'TheSecondElement';
const elementTwoAlias = AliasHelper.toAlias(elementTwoName);
const iconColor = 'rgb(25, 92, 201)';
await umbracoApi.documentTypes.ensureNameNotExists(elementTwoName);
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const elementTwo = await umbracoApi.documentTypes.createDefaultElementType(elementTwoName, elementTwoAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withIconColor(iconColor)
.done()
.addBlock()
.withContentElementTypeKey(elementTwo['key'])
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Opens the content editor
await page.locator('[data-element="property-' + blockGridAlias + '"]').getByRole('button', {name: 'Add content'}).click();
// Assert
// Checks if the element has the set icon color
await expect(page.locator('umb-block-card', {hasText: elementName}).locator('.umb-icon')).toHaveAttribute('style', 'color:' + iconColor);
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementTwoName);
});
test('can see thumbnail in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
// Thumbnail
const imageName = "Umbraco";
const umbracoFileValue = {"src": "Umbraco.png"};
const imageFileName = "Umbraco.png";
const imagePath = 'mediaLibrary/' + imageFileName;
const imageMimeType = "image/png";
// ElementTwo
const elementTwoName = 'TheSecondElement';
const elementTwoAlias = AliasHelper.toAlias(elementTwoName);
await umbracoApi.media.ensureNameNotExists(imageName);
await umbracoApi.documentTypes.ensureNameNotExists(elementTwoName);
const imageData = await umbracoApi.media.createImageWithFile(imageName, umbracoFileValue, imageFileName, imagePath, imageMimeType);
const imageDataPath = imageData.mediaLink;
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const elementTwo = await umbracoApi.documentTypes.createDefaultElementType(elementTwoName, elementTwoAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withThumbnail(imageDataPath)
.done()
.addBlock()
.withContentElementTypeKey(elementTwo['key'])
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Opens the content editor
await page.locator('[data-element="property-' + blockGridAlias + '"]').getByRole('button', {name: 'Add content'}).click();
// Assert
// Checks if the element has the thumbnail
await expect(page.locator('umb-block-card', {hasText: elementName}).locator('.__showcase')).toHaveAttribute('style', 'background-image: url("' + imageDataPath + '?width=400");');
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementTwoName);
await umbracoApi.media.ensureNameNotExists(imageName);
});
});
});

View File

@@ -0,0 +1,617 @@
import {AliasHelper, ConstantHelper, test} from "@umbraco/playwright-testhelpers";
import {ContentBuilder, DocumentTypeBuilder, MediaBuilder, MediaFileBuilder} from "@umbraco/json-models-builders";
import {BlockGridDataTypeBuilder} from "@umbraco/json-models-builders/dist/lib/builders/dataTypes";
import {expect} from "@playwright/test";
test.describe('BlockGridEditorContent', () => {
const documentName = 'DocumentTest';
const blockGridName = 'BlockGridTest';
const elementName = 'ElementTest';
const documentAlias = AliasHelper.toAlias(documentName);
const blockGridAlias = AliasHelper.toAlias(blockGridName);
const elementAlias = AliasHelper.toAlias(elementName);
test.beforeEach(async ({page, umbracoApi, umbracoUi}, testInfo) => {
await umbracoApi.report.report(testInfo);
await umbracoApi.login();
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
});
test.afterEach(async ({page, umbracoApi, umbracoUi}) => {
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
});
test('can create content with a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, null, null);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Adds TestElement
await page.locator('[key="blockEditor_addThis"]', {hasText: elementName}).click();
await page.locator('[id="sub-view-0"]').locator('[id="title"]').fill('Hi there!');
await page.locator('[label="Create"]').click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the content was created
await expect(page.locator('.umb-block-grid__block--view')).toHaveCount(1);
await expect(page.locator('.umb-block-grid__block--view').first()).toHaveText(elementName);
});
test('can update content with a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const newContentValue = 'UpdatedTitle';
const newSettingValue = 'UpdatedSetting';
const element = await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, null, null, null);
await umbracoUi.navigateToContent(blockGridName);
// Updates the already created content text
await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName}).click();
await page.locator('[id="sub-view-0"]').locator('[id="title"]').fill(newContentValue);
await umbracoUi.clickDataElementByElementName('sub-view-settings');
// Adds text to the setting element
await page.locator('[id="sub-view-1"]').locator('[id="title"]').fill(newSettingValue);
await page.locator('[label="Submit"]').click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the Content and Setting were updated after it was saved
await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName}).click();
await expect(page.locator('[id="sub-view-0"]').locator('[id="title"]')).toHaveValue(newContentValue);
await umbracoUi.clickDataElementByElementName('sub-view-settings');
await expect(page.locator('[id="sub-view-1"]').locator('[id="title"]')).toHaveValue(newSettingValue);
});
test('can delete a block grid editor in content', async ({page, umbracoApi, umbracoUi}) => {
const element = await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, null, null, null);
await umbracoUi.navigateToContent(blockGridName);
// Deletes the block grid editor inside of the content
await page.getByTitle("Delete").click();
// Can't use our constant helper because the action for delete does not contain an s. The correct way is 'action-delete'
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey('actions_delete'));
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the content is actually deleted
await expect(page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName})).not.toBeVisible();
await expect(page.locator('.umb-block-grid__block--view')).toHaveCount(0);
});
test('can copy block grid content and paste it', async ({page, umbracoApi, umbracoUi}) => {
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, null, null, null);
await umbracoUi.navigateToContent(blockGridName);
// Checks to make sure that there is only one item
await expect(page.locator('.umb-block-grid__block--view')).toHaveCount(1);
// Copies the block grid content
await page.getByTitle("Copy").click();
await expect(page.locator('.alert-success', {hasText: 'Copied to clipboard'})).toBeVisible();
// Pastes block grid content
await page.getByTitle("Clipboard").click();
await page.locator('umb-block-card', {hasText: elementName}).click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
// Checks if there now are two blocks
await expect(page.locator('.umb-block-grid__block')).toHaveCount(2);
// Checks if the text was copied to the pasted block
await page.locator('.umb-block-grid__block--view').nth(1).click();
await expect(page.locator('[id="sub-view-0"] >> [name="textbox"]')).toHaveValue('aliasTest');
});
test('can copy block grid content and paste it into another group with the same block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const blockGridTwoName = 'BlockGridTwo';
const blockGridTwoAlias = AliasHelper.toAlias(blockGridTwoName);
const groupOne = 'BlockGridGroupOne';
const groupTwo = 'BlockGridGroupTwo';
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataType = await umbracoApi.dataTypes.createDefaultBlockGrid(umbracoApi, blockGridName, element);
const docType = new DocumentTypeBuilder()
.withName(documentName)
.withAlias(documentAlias)
.withAllowAsRoot(true)
.addGroup()
.withName(groupOne)
.addCustomProperty(dataType['id'])
.withLabel(blockGridName)
.withAlias(blockGridAlias)
.done()
.done()
.addGroup()
.withName(groupTwo)
.addCustomProperty(dataType['id'])
.withLabel(blockGridTwoName)
.withAlias(blockGridTwoAlias)
.done()
.done()
.build();
await umbracoApi.documentTypes.save(docType);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, true);
await umbracoUi.navigateToContent(blockGridName);
// Checks to make sure that there is only one item in the first group
await expect(page.locator('[data-element="group-a' + groupOne + '"] >> .umb-block-grid__block--view')).toHaveCount(1);
// Checks to make sure that there are no items in the second group
await expect(page.locator('[data-element="group-a' + groupTwo + '"] >> .umb-block-grid__block--view')).toHaveCount(0);
// Copies block grid content from the first group
await page.locator('[title="Copy"]').click();
await expect(page.locator('.alert-success', {hasText: 'Copied to clipboard'})).toBeVisible();
// Pastes into the second group
await page.locator('[title="Clipboard"]').nth(1).click();
await page.locator('umb-block-card', {hasText: elementName}).click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
await expect(page.locator('.alert-success', {hasText: 'Content Published'})).toBeVisible();
// Assert
// Checks if both groups has one item each
await expect(page.locator('[data-element="group-a' + groupOne + '"] >> .umb-block-grid__block--view')).toHaveCount(1);
await expect(page.locator('[data-element="group-a' + groupTwo + '"] >> .umb-block-grid__block--view')).toHaveCount(1);
// Opens the second group to see if the block grid item was copied with the correct text
await page.locator('[data-element="group-a' + groupTwo + '"] >> .umb-block-grid__block--view').click();
await expect(page.locator('[id="sub-view-0"] >> [name="textbox"]')).toHaveValue('aliasTest');
});
test.describe('Moving blocks', () => {
test('can move a block under another block', async ({page, umbracoApi, umbracoUi}) => {
const bottomBlock = "BottomBlock";
const topBlock = "TopBlock";
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
// We give the dataType a label so we can differentiate between the top and bottom block in the content editor.
const dataType = await umbracoApi.dataTypes.createDefaultBlockGrid(umbracoApi, blockGridName, element, '{{' + element.groups[0].properties[0].alias + '}}');
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, element, dataType);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, bottomBlock)
.done()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, topBlock)
.done()
.addLayout()
.withContentUdi(element['key'], 0)
.done()
.addLayout()
.withContentUdi(element['key'], 1)
.done()
.done()
.done()
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Drag and Drop
const dragFromLocator = await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: bottomBlock});
const dragToLocator = await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: topBlock});
await umbracoUi.dragAndDrop(dragFromLocator, dragToLocator, 10, -5, 15);
// Assert
// Checks if the BottomBlock is moved to be under TopBlock
await expect(page.locator('[data-content-element-type-key="' + element['key'] + '"]').nth(1)).toContainText(bottomBlock);
});
test('can move a block next to another block', async ({page, umbracoApi, umbracoUi}) => {
const leftBlock = "LeftBlock";
const rightBlock = "RightBlock";
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withLabel('{{' + element.groups[0].properties[0].alias +'}}')
.withContentElementTypeKey(element['key'])
.addColumnSpanOptions(6)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, element, dataType);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, rightBlock)
.done()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, leftBlock)
.done()
.addLayout()
.withContentUdi(element['key'], 0)
.done()
.addLayout()
.withContentUdi(element['key'], 1)
.done()
.done()
.done()
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Drag and Drop
const dragFromLocator = await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: rightBlock});
const dragToLocator = await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: leftBlock});
await umbracoUi.dragAndDrop(dragFromLocator, dragToLocator, -5, 20, 15);
// Assert
// Checks if the rightBlock is moved to the right side of the blocks
await expect(page.locator('[data-content-element-type-key="' + element['key'] + '"]').nth(1)).toContainText(rightBlock);
});
});
test('can create content with a image', async ({page, umbracoApi, umbracoUi}) => {
const imageName = "Umbraco";
await umbracoApi.media.ensureNameNotExists(imageName);
const element = new DocumentTypeBuilder()
.withName(elementName)
.withAlias(elementAlias)
.AsElementType()
.addGroup()
.withName("ImageGroup")
.withAlias('imageGroup')
.addImagePickerProperty()
.withLabel("Image")
.withAlias("image")
.done()
.done()
.build();
await umbracoApi.documentTypes.save(element);
await umbracoApi.media.createDefaultImage(imageName);
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, element, null);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.done()
.addLayout()
.withContentUdi(element['key'])
.done()
.done()
.done()
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Selects the created image for the block
await page.locator('[data-content-element-type-key="' + element['key'] + '"]').click();
await page.locator('[data-element="property-image"]').locator('[key="' + ConstantHelper.buttons.add + '"]').click();
await page.locator('[data-element="media-grid"] >> [title="' + imageName + '"]').click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.select));
await page.locator('[label="Submit"]').click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the image was added to the block
await page.locator('[data-content-element-type-key="' + element['key'] + '"]').click();
await expect(page.locator('.umb-media-card-grid__cell >> [title="' + imageName + '"]')).toBeVisible();
// Clean
await umbracoApi.media.ensureNameNotExists(imageName);
});
test.describe('Amount', () => {
test('can set a minimum of required blocks in content with a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.withMin(2)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, false);
await umbracoUi.navigateToContent(blockGridName);
// Checks if there is validation for needing 2 entries or more
await expect(page.locator('[key="validation_entriesShort"]')).toContainText('Minimum 2 entries');
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Checks if a validation error is thrown when trying to save when there is not enough blocks
await expect(page.locator('.alert-error')).toBeVisible();
// Adds another block
await page.locator('[key="blockEditor_addThis"]', {hasText: elementName}).click();
await page.locator('[label="Create"]').click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.getSuccessNotification();
// Checks if there are two blocks in the area
await expect(page.locator('[data-element="property-' + blockGridAlias + '"]').locator('umb-block-grid-entry')).toHaveCount(2);
});
test('can set a maximum of required blocks in content with a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.withMax(2)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, element, dataType);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, "aliasTest")
.done()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, "aliasTestes")
.done()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, "aliasTester")
.done()
.addLayout()
.withContentUdi(element['key'], 0)
.done()
.addLayout()
.withContentUdi(element['key'], 1)
.done()
.addLayout()
.withContentUdi(element['key'], 2)
.done()
.done()
.done()
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Checks if there is validation for needing 2 entries or less
await expect(page.locator('[key="validation_entriesExceed"]')).toContainText('Maximum 2 entries');
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Checks if a validation error is thrown when trying to save when there is too many blocks
await expect(page.locator('.alert-error')).toBeVisible();
// Deletes a block
await page.locator('[title="Delete"]').nth(2).click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey('actions_delete'));
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.getSuccessNotification();
// Checks if there are two blocks in the area
await expect(page.locator('[data-element="property-' + blockGridAlias + '"]').locator('umb-block-grid-entry')).toHaveCount(2);
});
});
test.describe('Live editing mode', () => {
test('can use live editing mode in content with a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const newText = 'LiveUpdatedContent';
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
// We use the a label so we can see if the block is live updated when content is being written to the element
.withLabel('{{' + element.groups[0].properties[0].alias + '}}')
.withContentElementTypeKey(element['key'])
.withEditorSize('small')
.done()
.withUseLiveEditing(true)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, false);
await umbracoUi.navigateToContent(blockGridName);
// Checks if the block contains the correct text before being edited
await expect(page.locator('[data-content-element-type-alias="'+elementAlias +'"]')).toContainText('aliasTest');
// Updates the text without saving the changes.
await page.locator('[data-content-element-type-key="' + element['key'] + '"]').click();
await page.locator('[id="sub-view-0"]').locator('[id="title"]').fill(newText);
// Checks if the block is being live updated as the content is being updated.
await expect(page.locator('[data-content-element-type-alias="'+elementAlias +'"]')).toContainText(newText);
});
});
test.describe('Editor width', () => {
test('can see updated editor width in a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const maxWidth = "40%";
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.withMaxPropertyWidth(maxWidth)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, false);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the max-width size is the same as defined in the block grid editor
await expect(page.locator('[data-element="property-' + blockGridAlias + '"] >> [style="max-width: ' + maxWidth + ';"]')).toBeVisible();
});
});
test.describe('Grid Columns', () => {
test('can see updated grid columns in content', async ({page, umbracoApi, umbracoUi}) => {
const gridColumns = 6;
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.withGridColumns(gridColumns)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, false);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the grid columns are the same as defined in the block grid editor
await expect(page.locator('[data-element="property-' + blockGridAlias + '"] >> [grid-columns="' + gridColumns + '"]')).toBeVisible();
});
});
test.describe('Layout Stylesheet', () => {
test('can use a layout stylesheet in content', async ({page, umbracoApi, umbracoUi}) => {
const stylesheetName = "StylesheetBlockGrid.css";
const stylesheetPath = "stylesheet/" + stylesheetName;
const stylesheetMimeType = "text/css";
await umbracoApi.media.ensureNameNotExists(stylesheetName);
const stylesheetData = await umbracoApi.media.createFileWithFile(stylesheetName, stylesheetName, stylesheetPath, stylesheetMimeType);
const stylesheetDataPath = stylesheetData.mediaLink;
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.withLayoutStylesheet(stylesheetDataPath)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the block has the correct template
await expect(page.locator('[data-element="property-'+blockGridAlias+'"]').locator('umb-block-grid-root')).toHaveAttribute('stylesheet', stylesheetDataPath);
// Clean
await umbracoApi.media.ensureNameNotExists(stylesheetName);
});
});
test.describe('Create Button Label', () => {
test('can see updated create button label in content', async ({page, umbracoApi, umbracoUi}) => {
const newButtonLabel = 'AddTestButton';
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.withCreateLabel(newButtonLabel)
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, false);
// Goes to the created Content
await umbracoUi.goToSection(ConstantHelper.sections.content);
await umbracoUi.refreshContentTree();
await umbracoUi.clickDataElementByElementName('tree-item-' + blockGridName);
// Assert
// Checks if the new button label is on the BlockGridEditor
await expect(page.locator('[data-element="property-' + blockGridAlias + '"] >> .umb-block-grid__actions')).toContainText(newButtonLabel);
// Checks if the button label can be clicked
await page.locator('[data-element="property-' + blockGridAlias + '"] >> .umb-block-grid__actions', {hasText: newButtonLabel}).click();
});
});
});

View File

@@ -0,0 +1,792 @@
import {AliasHelper, ConstantHelper, test} from "@umbraco/playwright-testhelpers";
import {ContentBuilder, DocumentTypeBuilder, PartialViewBuilder,} from "@umbraco/json-models-builders";
import {expect} from "@playwright/test";
import {BlockGridDataTypeBuilder} from "@umbraco/json-models-builders/dist/lib/builders/dataTypes";
import {umbracoConfig} from "@umbraco/playwright-testhelpers/dist/umbraco.config";
test.describe('BlockGridEditorRending', () => {
const documentName = 'DocumentTest';
const blockGridName = 'BlockGridTest';
const elementTitleName = 'ElementTitle';
const contentText = "ContentTest";
const documentAlias = 'documentTest';
const blockGridAlias = 'blockGridTest';
const elementTitleAlias = "elementTitle";
const elementTitleLabel = 'Title';
const elementTitleLabelAlias = AliasHelper.toAlias(elementTitleLabel);
test.beforeEach(async ({page, umbracoApi, umbracoUi}, testInfo) => {
await umbracoApi.report.report(testInfo);
await umbracoApi.login();
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementTitleName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
await umbracoApi.templates.ensureNameNotExists(documentName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementTitleAlias + '.cshtml')
});
test.afterEach(async ({page, umbracoApi, umbracoUi}) => {
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementTitleName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
await umbracoApi.templates.ensureNameNotExists(documentName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementTitleAlias + '.cshtml')
});
async function createElementWithRTE(umbracoApi, elementName, elementAlias, label, labelAlias){
const element = new DocumentTypeBuilder()
.withName(elementName)
.withAlias(elementAlias)
.AsElementType()
.addGroup()
.withName('TestString')
.withAlias('testString')
.addRichTextProperty()
.withLabel(label)
.withAlias(labelAlias)
.done()
.done()
.build();
return await umbracoApi.documentTypes.save(element);
}
async function createDocumentWithTemplateAndDataType(umbracoApi, dataType){
const docType = new DocumentTypeBuilder()
.withName(documentName)
.withAlias('documentTest')
.withDefaultTemplate('documentTest')
.withAllowAsRoot(true)
.addGroup()
.withName('BlockGridGroup')
.withAlias('blockGridGroup')
.addCustomProperty(dataType['id'])
.withLabel(blockGridName)
.withAlias(blockGridAlias)
.done()
.done()
.build();
return await umbracoApi.documentTypes.save(docType);
}
async function editDefaultTemplate(umbracoApi){
await umbracoApi.templates.edit(documentName, '@using Umbraco.Cms.Web.Common.PublishedModels;\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.' + documentName + '>\n' +
'@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;' + '\n' +
'@await Html.GetBlockGridHtmlAsync(Model.' + blockGridName + ')');
}
async function createPartialViewWithArea(umbracoApi, elementAlias, elementLabelAlias){
const partialViewElementTitle = new PartialViewBuilder()
.withName(elementAlias)
.withContent('@using Umbraco.Extensions' + '\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>' +
'\n' +
'<div>' + '\n' +
'<h1>@Model.Content.Value("' + elementLabelAlias + '")</h1>' + '\n' +
'<div>@await Html.GetBlockGridItemAreasHtmlAsync(Model)</div>' +
'</div>')
.build();
partialViewElementTitle.virtualPath = "/Views/Partials/blockgrid/Components/";
return await umbracoApi.partialViews.save(partialViewElementTitle);
}
async function createPartialViewWithBlock(umbracoApi,elementAlias, elementLabelAlias){
const partialViewElementBody = new PartialViewBuilder()
.withName(elementAlias)
.withContent('@using Umbraco.Extensions' + '\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>' +
'\n' +
'<div>' + '\n' +
'<h3>@Model.Content.Value("' + elementLabelAlias + '")</h3>' + '\n' +
'</div>')
.build();
partialViewElementBody.virtualPath = "/Views/Partials/blockgrid/Components/";
await umbracoApi.partialViews.save(partialViewElementBody);
}
test('can render content with a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const element = await createElementWithRTE(umbracoApi, elementTitleName, elementTitleAlias, elementTitleLabel, elementTitleLabelAlias);
const dataType = await umbracoApi.dataTypes.createDefaultBlockGrid(umbracoApi, blockGridName, element);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
await createPartialViewWithBlock(umbracoApi, elementTitleAlias, elementTitleLabelAlias);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, contentText)
.done()
.addLayout()
.withContentUdi(element['key'])
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor.png');
});
test('can render content with a block grid editor with two elements', async ({page, umbracoApi, umbracoUi}) => {
// ElementBody
const elementBodyName = "ElementBody";
const elementBodyAlias = AliasHelper.toAlias(elementBodyName);
const elementBodyLabel = 'Body';
const elementBodyLabelAlias = AliasHelper.toAlias(elementBodyLabel);
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
const element = await createElementWithRTE(umbracoApi, elementTitleName, elementTitleAlias, elementTitleLabel, elementTitleLabelAlias);
const elementBody = await createElementWithRTE(umbracoApi, elementBodyName, elementBodyAlias, elementBodyLabel, elementBodyLabelAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.addBlock()
.withContentElementTypeKey(elementBody['key'])
.done()
.build();
const dataType= await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
// Creates partial view for the ElementTitle
await createPartialViewWithBlock(umbracoApi, elementTitleAlias, elementTitleLabelAlias);
// Creates partial view for the ElementBody
await createPartialViewWithBlock(umbracoApi, elementBodyAlias, elementBodyLabelAlias);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, contentText)
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'Lorem Ipsum')
.done()
.addLayout()
.withContentUdi(element['key'])
.done()
.addLayout()
.withContentUdi(elementBody['key'])
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-two-elements.png');
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
});
test.describe('Rendering areas', () => {
test('can render a block grid with an area', async ({page, umbracoApi, umbracoUi}) => {
// ElementBody
const elementBodyName = "ElementBody";
const elementBodyAlias = AliasHelper.toAlias(elementBodyName);
const elementBodyLabel = 'Body';
const elementBodyLabelAlias = AliasHelper.toAlias(elementBodyLabel);
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
const element = await createElementWithRTE(umbracoApi, elementTitleName, elementTitleAlias, elementTitleLabel, elementTitleLabelAlias);
const elementBody = await createElementWithRTE(umbracoApi, elementBodyName, elementBodyAlias, elementBodyLabel, elementBodyLabelAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.addArea()
.withAlias('titleArea')
.done()
.done()
.addBlock()
.withContentElementTypeKey(elementBody['key'])
.done()
.build();
const dataType= await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
// Creates partial view for the ElementTitle
await createPartialViewWithArea(umbracoApi, elementTitleAlias, elementTitleLabelAlias);
// Creates partial view for the ElementBody
await createPartialViewWithBlock(umbracoApi, elementBodyAlias, elementBodyLabelAlias);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, contentText)
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'Lorem Ipsum')
.done()
.addLayout()
.withContentUdi(element['key'])
.addAreas()
.withKey(dataType.preValues[0].value[0].areas[0].key)
.addItems()
.withContentUdi(elementBody['key'])
.done()
.done()
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-area.png');
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
})
test('can render a block grid with multiple areas', async ({page, umbracoApi, umbracoUi}) => {
// ElementBody
const elementBodyName = "ElementBody";
const elementBodyAlias = AliasHelper.toAlias(elementBodyName);
const elementBodyLabel = 'Body';
const elementBodyLabelAlias = AliasHelper.toAlias(elementBodyLabel);
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
const element = await createElementWithRTE(umbracoApi, elementTitleName, elementTitleAlias, elementTitleLabel, elementTitleLabelAlias);
const elementBody = await createElementWithRTE(umbracoApi, elementBodyName, elementBodyAlias, elementBodyLabel, elementBodyLabelAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.addArea()
.withAlias('titleArea')
.done()
.done()
.addBlock()
.withContentElementTypeKey(elementBody['key'])
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
// Creates partial view for the ElementTitle
await createPartialViewWithArea(umbracoApi, elementTitleAlias, elementTitleLabelAlias);
// Creates partial view for the ElementBody
await createPartialViewWithBlock(umbracoApi, elementBodyAlias, elementBodyLabelAlias);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, contentText)
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'Lorem ipsum')
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'dolor sit amet,')
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'consectetuer adipiscing elit,')
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.')
.done()
.addLayout()
.withContentUdi(element['key'])
.addAreas()
.withKey(dataType.preValues[0].value[0].areas[0].key)
.addItems()
.withContentUdi(elementBody['key'],0)
.done()
.addItems()
.withContentUdi(elementBody['key'],1)
.done()
.addItems()
.withContentUdi(elementBody['key'],2)
.done()
.addItems()
.withContentUdi(elementBody['key'],3)
.done()
.done()
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-multiple-areas.png');
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
});
test('can render a block grid with an area that has another area', async ({page, umbracoApi, umbracoUi}) => {
// ElementBody
const elementBodyName = "ElementBody";
const elementBodyAlias = AliasHelper.toAlias(elementBodyName);
const elementBodyLabel = 'Body';
const elementBodyLabelAlias = AliasHelper.toAlias(elementBodyLabel);
// ElementFooter
const elementFooterName = "ElementFooter";
const elementFooterAlias = AliasHelper.toAlias(elementFooterName);
const elementFooterLabel = 'Footer';
const elementFooterLabelAlias = AliasHelper.toAlias(elementFooterLabel);
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.documentTypes.ensureNameNotExists(elementFooterName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementFooterAlias + '.cshtml');
const element = await createElementWithRTE(umbracoApi, elementTitleName, elementTitleAlias, elementTitleLabel, elementTitleLabelAlias);
const elementBody = await createElementWithRTE(umbracoApi, elementBodyName, elementBodyAlias, elementBodyLabel, elementBodyLabelAlias);
const elementFooter = await createElementWithRTE(umbracoApi, elementFooterName, elementFooterAlias, elementFooterLabel, elementFooterLabelAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.addArea()
.withAlias('titleArea')
.done()
.done()
.addBlock()
.withContentElementTypeKey(elementBody['key'])
.addArea()
.withAlias('bodyArea')
.done()
.done()
.addBlock()
.withContentElementTypeKey(elementFooter['key'])
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
// Creates partial view for the ElementTitle
await createPartialViewWithArea(umbracoApi, elementTitleAlias, elementTitleLabelAlias);
// Creates partial view for the ElementBody
await createPartialViewWithArea(umbracoApi, elementBodyAlias, elementBodyLabelAlias);
// Creates partial view for the ElementFooter
await createPartialViewWithBlock(umbracoApi, elementFooterAlias, elementFooterLabelAlias);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, contentText)
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'Lorem ipsum')
.done()
.addBlockGridEntry()
.withContentTypeKey(elementFooter['key'])
.appendContentProperties(elementFooter.groups[0].properties[0].alias, 'dolor sit amet')
.done()
.addLayout()
.withContentUdi(element['key'])
.addAreas()
.withKey(dataType.preValues[0].value[0].areas[0].key)
.addItems()
.withContentUdi(elementBody['key'])
.addAreas()
.withKey(dataType.preValues[0].value[1].areas[0].key)
.addItems()
.withContentUdi(elementFooter['key'])
.done()
.done()
.done()
.done()
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-area-with-area.png');
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.documentTypes.ensureNameNotExists(elementFooterName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementFooterAlias + '.cshtml');
});
});
test.describe('Layout Stylesheet', () => {
test('can render a block with a custom layout stylesheet', async ({page, umbracoApi, umbracoUi}) => {
const stylesheetName = "Title.css";
const stylesheetPath = "stylesheet/" + stylesheetName;
const stylesheetMimeType = "text/css";
await umbracoApi.media.ensureNameNotExists(stylesheetName);
const stylesheetData = await umbracoApi.media.createFileWithFile(stylesheetName, stylesheetName, stylesheetPath, stylesheetMimeType);
const stylesheetDataPath = stylesheetData.mediaLink;
const element = await umbracoApi.documentTypes.createDefaultElementType(elementTitleName, elementTitleAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withStylesheet(stylesheetDataPath)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
const partialViewElement = new PartialViewBuilder()
.withName(elementTitleAlias)
.withContent('@using Umbraco.Extensions' + '\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>' +
'\n' +
'<div>' + '\n' +
'<h1 class="title">@Model.Content.Value("' + elementTitleLabelAlias + '") </h1>' + '\n' +
'</div>' + '\n' +
'<link rel="stylesheet" href="@Url.Content("' + stylesheetDataPath + '")" />')
.build();
partialViewElement.virtualPath = "/Views/Partials/blockgrid/Components/";
await umbracoApi.partialViews.save(partialViewElement);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.appendContentProperties(element.groups[0].properties[0].alias, contentText)
.done()
.addLayout()
.withContentUdi(element['key'])
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-custom-stylesheet.png');
// Clean
await umbracoApi.media.ensureNameNotExists(stylesheetName);
});
test('can render a block with another area where each block has a different custom layout stylesheet', async ({page, umbracoApi, umbracoUi}) => {
// TitleStylesheet
const stylesheetTitleName = "Title.css";
const stylesheetTitlePath = "stylesheet/" + stylesheetTitleName;
const stylesheetMimeType = "text/css";
// BodyStylesheet
const stylesheetBodyName = "Body.css";
const stylesheetBodyPath = "stylesheet/" + stylesheetBodyName;
// ElementBody
const elementBodyName = "ElementBody";
const elementBodyAlias = AliasHelper.toAlias(elementBodyName);
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.media.ensureNameNotExists(stylesheetTitleName);
await umbracoApi.media.ensureNameNotExists(stylesheetBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
const stylesheetTitleData = await umbracoApi.media.createFileWithFile(stylesheetTitleName, stylesheetTitleName, stylesheetTitlePath, stylesheetMimeType);
const stylesheetBodyData = await umbracoApi.media.createFileWithFile(stylesheetBodyName, stylesheetBodyName, stylesheetBodyPath, stylesheetMimeType);
const stylesheetTitleDataPath = stylesheetTitleData.mediaLink;
const stylesheetBodyDataPath = stylesheetBodyData.mediaLink;
const elementTitle = await umbracoApi.documentTypes.createDefaultElementType(elementTitleName, elementTitleAlias);
const elementBody = await umbracoApi.documentTypes.createDefaultElementType(elementBodyName, elementBodyAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(elementTitle['key'])
.withStylesheet(stylesheetTitleDataPath)
.addArea()
.withAlias('TitleArea')
.done()
.done()
.addBlock()
.withContentElementTypeKey(elementBody['key'])
.withStylesheet(stylesheetBodyDataPath)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
const partialViewElementTitle = new PartialViewBuilder()
.withName(elementTitleAlias)
.withContent('@using Umbraco.Extensions' + '\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>' +
'\n' +
'<div>' + '\n' +
'<h1 class="title">@Model.Content.Value("' + elementTitleLabelAlias + '") </h1>' + '\n' +
'</div>' + '\n' +
'<link rel="stylesheet" href="@Url.Content("' + stylesheetTitleDataPath + '")" />' +
'<div>' + '\n' +
'@await Html.GetBlockGridItemAreasHtmlAsync(Model)'+ '\n' +
'</div>')
.build();
partialViewElementTitle.virtualPath = "/Views/Partials/blockgrid/Components/";
await umbracoApi.partialViews.save(partialViewElementTitle);
const partialViewElementBody = new PartialViewBuilder()
.withName(elementBodyAlias)
.withContent('@using Umbraco.Extensions' + '\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>' +
'\n' +
'<div>' + '\n' +
'<h1 class="body">@Model.Content.Value("' + elementTitleLabelAlias + '") </h1>' + '\n' +
'</div>' + '\n' +
'<link rel="stylesheet" href="@Url.Content("' + stylesheetBodyDataPath + '")" />')
.build();
partialViewElementBody.virtualPath = "/Views/Partials/blockgrid/Components/";
await umbracoApi.partialViews.save(partialViewElementBody);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName('BlockGridContent')
.withSave(true)
.withPublish(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(elementTitle['key'])
.appendContentProperties(elementTitle.groups[0].properties[0].alias, contentText)
.done()
.addBlockGridEntry()
.withContentTypeKey(elementBody['key'])
.appendContentProperties(elementBody.groups[0].properties[0].alias, 'Lorem Ipsum')
.done()
.addLayout()
.withContentUdi(elementTitle['key'])
.addAreas()
.withKey(dataType.preValues[0].value[0].areas[0].key)
.addItems()
.withContentUdi(elementBody['key'])
.done()
.done()
.done()
.done()
.done()
.done()
.withTemplateAlias(documentName)
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-two-custom-stylesheets.png');
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
await umbracoApi.media.ensureNameNotExists(stylesheetTitleName);
await umbracoApi.media.ensureNameNotExists(stylesheetBodyName);
await umbracoApi.partialViews.ensureNameNotExists('blockgrid/Components', elementBodyAlias + '.cshtml');
});
});
test.describe('Image', () => {
test('can render a block grid with an image', async ({page, umbracoApi, umbracoUi}) => {
// Image
const imageName = "Umbraco";
const umbracoFileValue = {"src": "Umbraco.png"};
const imageFileName = "Umbraco.png";
const imagePath = 'mediaLibrary/' + imageFileName;
const imageMimeType = "image/png";
await umbracoApi.media.ensureNameNotExists(imageName);
const imageData = await umbracoApi.media.createImageWithFile(imageName, umbracoFileValue, imageFileName, imagePath, imageMimeType);
const element = new DocumentTypeBuilder()
.withName(elementTitleName)
.withAlias(elementTitleAlias)
.AsElementType()
.addGroup()
.withName('ImageGroup')
.withAlias('imageGroup')
.addImagePickerProperty()
.withLabel('Image')
.withAlias('image')
.done()
.done()
.build();
await umbracoApi.documentTypes.save(element);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await createDocumentWithTemplateAndDataType(umbracoApi, dataType);
await editDefaultTemplate(umbracoApi);
const partialViewImage = new PartialViewBuilder()
.withName(elementTitleAlias)
.withContent('@using Umbraco.Extensions' + '\n' +
'@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockGridItem>' + '\n' +
'\n' +
'@{' + '\n' +
'var typedMediaPickerSingle = Model.Content.Value<Umbraco.Cms.Core.Models.MediaWithCrops>("image");' + '\n' +
'<img src="@typedMediaPickerSingle.MediaUrl()" style="object-fit:cover; width:100%; height:100%;" alt="Umbraco"/>' + '\n' +
'}')
.build();
partialViewImage.virtualPath = "/Views/Partials/blockgrid/Components/";
await umbracoApi.partialViews.save(partialViewImage);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.publish)
.addVariant()
.withName(blockGridName)
.withSave(true)
.addProperty()
.withAlias(blockGridAlias)
.addBlockGridValue()
.addBlockGridEntry()
.withContentTypeKey(element['key'])
.addImage()
.withMediaKey(imageData.key)
.done()
.done()
.addLayout()
.withContentUdi(element['key'])
.done()
.done()
.done()
.done()
.build();
await umbracoApi.content.save(rootContentNode);
// Assert
await page.goto(umbracoConfig.environment.baseUrl);
await expect(page).toHaveScreenshot('Block-grid-editor-with-image.png');
// Clean
await umbracoApi.media.ensureNameNotExists(imageName);
});
});
});

View File

@@ -0,0 +1,155 @@
import {AliasHelper, ConstantHelper, test} from "@umbraco/playwright-testhelpers";
import {BlockGridDataTypeBuilder} from "@umbraco/json-models-builders/dist/lib/builders/dataTypes";
import {expect} from "@playwright/test";
import {ContentBuilder} from "@umbraco/json-models-builders";
test.describe('BlockGridEditorSettings', () => {
const documentName = 'DocumentTest';
const blockGridName = 'BlockGridTest';
const elementName = 'ElementTitle';
const documentAlias = AliasHelper.toAlias(documentName);
const blockGridAlias = AliasHelper.toAlias(blockGridName);
const elementAlias = AliasHelper.toAlias(elementName);
test.beforeEach(async ({page, umbracoApi, umbracoUi}, testInfo) => {
await umbracoApi.report.report(testInfo);
await umbracoApi.login();
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
});
test.afterEach(async ({page, umbracoApi, umbracoUi}) => {
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
await umbracoApi.dataTypes.ensureNameNotExists(blockGridName);
});
test.describe('General', () => {
test('can see label in content for a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const newLabel = "New Label";
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withLabel(newLabel + '{{}}')
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the element contains the correct label
await expect(page.locator('[data-content-element-type-alias="' + elementAlias + '"]')).toContainText(newLabel);
// Checks if the element is clickable
await page.locator('[data-content-element-type-alias="' + elementAlias + '"]').click();
});
});
test.describe('Permissions', () => {
test('can set allow in root to false for a element in a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.withAllowAtRoot(false)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.documentTypes.createDefaultDocumentWithBlockGridEditor(umbracoApi, element, dataType);
const rootContentNode = new ContentBuilder()
.withContentTypeAlias(documentAlias)
.withAction(ConstantHelper.actions.save)
.addVariant()
.withName(blockGridName)
.withSave(true)
.done()
.build();
await umbracoApi.content.save(rootContentNode);
await umbracoUi.navigateToContent(blockGridName);
// Checks if adding a block is disabled
await expect(page.locator('[data-element="property-'+blockGridAlias+'"]').locator('umb-block-grid-root').locator('[disabled="disabled"]')).toBeDisabled();
// Checks if the button is not clickable
await expect(page.locator('[data-element="property-' + blockGridAlias + '"]').locator('[key="blockEditor_addBlock"]')).not.toBeEnabled();
});
test('can set allow in areas to false for an element in a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const elementBodyName = 'BodyElement';
const elementBodyAlias = AliasHelper.toAlias(elementBodyName);
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const elementBody = await umbracoApi.documentTypes.createDefaultElementType(elementBodyName, elementBodyAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(elementBody['key'])
.withAllowInAreas(false)
.done()
.addBlock()
.withContentElementTypeKey(element['key'])
.addArea()
.withAlias('titleArea')
.done()
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi,element,dataType,false);
await umbracoUi.navigateToContent(blockGridName);
// Assert
// Checks if the elementTitle is the only element selectable to be in a area
await expect(page.locator('[data-area-alias="titleArea"]').locator('[key="blockEditor_addThis"]')).toContainText('Add ' + elementName);
// Clean
await umbracoApi.documentTypes.ensureNameNotExists(elementBodyName);
});
});
test.describe('Size options', () => {
test('can resize a block to another column span for an element in a block grid editor', async ({page, umbracoApi, umbracoUi}) => {
const element = await umbracoApi.documentTypes.createDefaultElementType(elementName, elementAlias);
const dataTypeBlockGrid = new BlockGridDataTypeBuilder()
.withName(blockGridName)
.addBlock()
.withContentElementTypeKey(element['key'])
.addColumnSpanOptions(12)
.addColumnSpanOptions(6)
.done()
.build();
const dataType = await umbracoApi.dataTypes.save(dataTypeBlockGrid);
await umbracoApi.content.createDefaultContentWithABlockGridEditor(umbracoApi, element, dataType, null);
await umbracoUi.navigateToContent(blockGridName);
// Drags the blocks from a columnSpan of 12 to 6
const dragFrom = await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName}).locator('[title="Drag to scale"]');
const dragTo = await page.locator('[data-content-element-type-key="' + element['key'] + '"]', {hasText: elementName});
await umbracoUi.dragAndDrop(dragFrom,dragTo, 0, 0 ,10);
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the block is resized to a column span of 6
await expect(page.locator('[data-content-element-type-key="' + element['key'] + '"], [data-col-span="6"]', {hasText: elementName})).toBeVisible();
});
});
});

View File

@@ -259,7 +259,9 @@ test.describe('BlockGridEditorDataTypeBlock', () => {
await umbracoApi.documentTypes.ensureNameNotExists(elementNameThree);
});
test('can create a block grid datatype with multiple groups and multiple element in each group', async ({page, umbracoApi, umbracoUi}) => {
test('can create a block grid datatype with multiple groups and multiple element in each group', async ({page, umbracoApi, umbracoUi},testInfo) => {
await testInfo.slow();
const GroupOne = 'GroupOne';
const elementNameFourth = 'FourthElement';
const elementFourthAlias = AliasHelper.toAlias(elementNameFourth);
@@ -581,7 +583,10 @@ test.describe('BlockGridEditorDataTypeBlock', () => {
await umbracoUi.navigateToDataType(blockGridName);
// Drags the element from the default group to the 'MoveToHere' Group.
await page.locator('.umb-block-card-group').nth(0).locator('[data-content-element-type-key="' + element['key'] + '"]').dragTo(page.locator('[key="blockEditor_addBlockType"]').nth(1));
const dragFrom = await page.locator('.umb-block-card-group').nth(0).locator('[data-content-element-type-key="' + element['key'] + '"]');
const dragTo = await page.locator('[key="blockEditor_addBlockType"]').nth(1);
await umbracoUi.dragAndDrop(dragFrom, dragTo, 0, 0, 15);
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
// Assert
@@ -618,7 +623,10 @@ test.describe('BlockGridEditorDataTypeBlock', () => {
await umbracoUi.navigateToDataType(blockGridName);
// Drags the group GroupMove under GroupNotMoving
await page.locator('.umb-block-card-group >> [icon="icon-navigation"]').nth(0).dragTo(page.locator('[key="blockEditor_addBlockType"]').nth(2));
const dragFrom = await page.locator('.umb-block-card-group >> [icon="icon-navigation"]').nth(0);
const dragTo = await page.locator('[key="blockEditor_addBlockType"]').nth(2);
await umbracoUi.dragAndDrop(dragFrom, dragTo, 0, 0, 15);
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
// Assert
@@ -632,7 +640,9 @@ test.describe('BlockGridEditorDataTypeBlock', () => {
await umbracoUi.doesDataTypeExist(blockGridName);
});
test('can move a group with elements in a block grid editor ', async ({page, umbracoApi, umbracoUi}) => {
test('can move a group with elements in a block grid editor', async ({page, umbracoApi, umbracoUi}, testInfo) => {
await testInfo.slow();
const GroupMove = 'GroupMove';
const GroupNotMoving = 'GroupNotMoving';
@@ -672,17 +682,12 @@ test.describe('BlockGridEditorDataTypeBlock', () => {
await umbracoUi.navigateToDataType(blockGridName);
// Drags the group GroupMove under GroupNotMoving
await page.locator('.umb-block-card-group >> [icon="icon-navigation"]').nth(0).hover();
await page.mouse.down();
await page.mouse.move(0, -20);
await page.locator('[key="blockEditor_addBlockType"]').nth(2).hover({
position: {
x: 0, y: 20
}
});
await page.mouse.up();
const dragFrom = await page.locator('.umb-block-card-group >> [icon="icon-navigation"]').nth(0);
const dragTo = await page.locator('[key="blockEditor_addBlockType"]').nth(2);
await umbracoUi.dragAndDrop(dragFrom, dragTo, 20, 0, 15);
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
// Assert
await umbracoUi.isSuccessNotificationVisible();
// Checks if the elements were moved with their group

View File

@@ -4,7 +4,6 @@ import {MediaBuilder, MediaFileBuilder, StylesheetBuilder} from "@umbraco/json-m
import {BlockListDataTypeBuilder} from "@umbraco/json-models-builders/dist/lib/builders/dataTypes";
test.describe('BlockListEditorDataType', () => {
const documentName = 'DocumentName'
const blockListName = 'BlockListTest';
const elementName = 'TestElement';
@@ -13,13 +12,11 @@ test.describe('BlockListEditorDataType', () => {
test.beforeEach(async ({page, umbracoApi, umbracoUi}, testInfo) => {
await umbracoApi.report.report(testInfo);
await umbracoApi.login();
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.dataTypes.ensureNameNotExists(blockListName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
});
test.afterEach(async({page, umbracoApi, umbracoUi}) => {
await umbracoApi.documentTypes.ensureNameNotExists(documentName);
await umbracoApi.dataTypes.ensureNameNotExists(blockListName);
await umbracoApi.documentTypes.ensureNameNotExists(elementName);
})
@@ -152,7 +149,10 @@ test.describe('BlockListEditorDataType', () => {
await expect(page.locator('[block-config-model="block"]')).toHaveCount(1);
});
test('can edit a block list editor', async ({page, umbracoApi, umbracoUi}) => {
test('can edit a block list editor', async ({page, umbracoApi, umbracoUi}, testInfo) => {
// We need to increase the timeout because the test is taking too long to end
await testInfo.slow()
const elementNameTwo = 'SecondElement';
const elementTwoAlias = AliasHelper.toAlias(elementNameTwo);
const stylesheetName = 'TestStyleSheet';
@@ -160,7 +160,7 @@ test.describe('BlockListEditorDataType', () => {
const imageName = "Umbraco";
const umbracoFileValue = {"src": "Umbraco.png"};
const fileName = "Umbraco.png";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "image/png";
await umbracoApi.documentTypes.ensureNameNotExists(elementNameTwo);

View File

@@ -120,7 +120,6 @@ test.describe('DataTypes', () => {
});
test('Test Url Picker', async ({page, umbracoApi, umbracoUi}) => {
const urlPickerDocTypeName = 'Url Picker Test';
const pickerDocTypeAlias = AliasHelper.toAlias(urlPickerDocTypeName);
@@ -155,18 +154,18 @@ test.describe('DataTypes', () => {
await page.locator('.umb-tree-root').click({button: "right"});
await page.locator('[data-element="action-create"]').click();
await page.locator('[data-element="action-create-' + pickerDocTypeAlias + '"] > .umb-action-link').click();
// Fill out content
await umbracoUi.setEditorHeaderName('UrlPickerContent');
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
await umbracoUi.isSuccessNotificationVisible();
await page.locator('span:has-text("×")').click();
await page.locator('.umb-node-preview-add').click();
// Should really try and find a better way to do this, but umbracoTreeItem tries to click the content pane in the background
await page.locator('#treePicker >> [data-element="tree-item-UrlPickerContent"]').click();
await page.locator('.umb-editor-footer-content__right-side > [button-style="success"] > .umb-button > .btn > .umb-button__content').click();
await expect(await page.locator('.umb-node-preview__name').first()).toBeVisible();
await page.locator('[data-element="editor-container"]').locator('[data-element="tree-item-UrlPickerContent"]').click();
await expect(page.locator('[alias="urlLinkPicker"]').locator('input[id="urlLinkPicker"]')).toHaveValue('/');
await page.locator('.umb-editor-footer-content__right-side').locator('[label-key="' + ConstantHelper.buttons.submit + '"]').click();
await expect(page.locator('.umb-node-preview__name').first()).toBeVisible();
// Save and publish
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));

View File

@@ -59,19 +59,19 @@ test.describe('Languages', () => {
await expect(doesExistEN).toBe(true);
// Delete UK Language
await page.locator('umb-button[label-key="general_delete"]').last().click();
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey('contentTypeEditor_yesDelete'));
await page.getByRole('button', {name: language2}).locator('[label-key=' + ConstantHelper.buttons.delete + ']').click();
await umbracoUi.clickDataElementByElementName('button-overlaySubmit');
// Assert the da language still exists and that the uk is deleted
// DA
doesExistDA = await umbracoApi.languages.exists(language1);
await expect(doesExistDA).toBe(true);
// EN
await expect(page.getByRole('button', {name: language2})).not.toBeVisible();
doesExistEN = await umbracoApi.languages.exists(language2);
await expect(doesExistEN).toBe(false);
// Cleanup
await umbracoApi.languages.ensureCultureNotExists(language1);
await umbracoApi.languages.ensureCultureNotExists(language2);
});
});

View File

@@ -14,7 +14,7 @@ test.describe('media File Types', () => {
test('create Article', async ({page, umbracoApi, umbracoUi}) => {
const articleName = "Article";
const fileName = "Article.pdf";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "application/pdf";
await umbracoApi.media.ensureNameNotExists(articleName);
@@ -32,7 +32,7 @@ test.describe('media File Types', () => {
test('create Audio', async ({page, umbracoApi, umbracoUi}) => {
const audioName = "Audio";
const fileName = "Audio.mp3";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "audio/mp3"
await umbracoApi.media.ensureNameNotExists(audioName);
@@ -50,7 +50,7 @@ test.describe('media File Types', () => {
test('create File', async ({page, umbracoApi, umbracoUi}) => {
const fileItemName = "File";
const fileName = "File.txt";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "*/*";
await umbracoApi.media.ensureNameNotExists(fileItemName);
@@ -84,7 +84,7 @@ test.describe('media File Types', () => {
const imageName = "Umbraco";
const umbracoFileValue = {"src": "Umbraco.png"};
const fileName = "Umbraco.png"
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "image/png";
await umbracoApi.media.ensureNameNotExists(imageName);
@@ -102,7 +102,7 @@ test.describe('media File Types', () => {
test('create VectorGraphics(SVG)', async ({page, umbracoApi, umbracoUi}) => {
const vectorGraphicsName = 'VectorGraphics';
const fileName = "VectorGraphics.svg";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "image/svg+xml";
await umbracoApi.media.ensureNameNotExists(vectorGraphicsName);
@@ -120,7 +120,7 @@ test.describe('media File Types', () => {
test('create Video', async ({page, umbracoApi, umbracoUi}) => {
const videoName = "Video";
const fileName = "Video.mp4";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "video/mp4";
await umbracoApi.media.ensureNameNotExists(videoName);
@@ -367,7 +367,7 @@ test.describe('media File Types', () => {
const fileItemNameOld = "File";
const fileItemNameNew = "UpdatedFile";
const fileName = "File.txt";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const mimeType = "*/*";
await umbracoApi.media.ensureNameNotExists(fileItemNameOld);
@@ -389,7 +389,7 @@ test.describe('media File Types', () => {
test('Update existing File with new File', async ({page, umbracoApi, umbracoUi}) => {
const fileItemName = "File";
const fileName = "File.txt";
const path = fileName;
const path = 'mediaLibrary/' + fileName;
const fileNameNew = "UpdatedFile.txt"
const pathNew = "./fixtures/mediaLibrary/" + fileNameNew;
const mimeType = "*/*";

View File

@@ -7,7 +7,13 @@ test.describe('Media', () => {
await umbracoApi.report.report(testInfo);
await umbracoApi.login();
await umbracoUi.goToSection(ConstantHelper.sections.media);
await umbracoApi.media.deleteAllMedia()
await umbracoApi.media.deleteAllMedia();
await umbracoApi.media.clearRecycleBin();
});
test.afterEach(async ({page, umbracoApi, umbracoUi}, testInfo) => {
await umbracoApi.media.deleteAllMedia();
await umbracoApi.media.clearRecycleBin();
});
test('move one of each Files into a Folder', async ({page, umbracoApi, umbracoUi}) => {
@@ -28,10 +34,7 @@ test.describe('Media', () => {
{fileTypeNames: vectorGraphicsName},
{fileTypeNames: videoName}
];
await umbracoApi.media.deleteAllFiles(articleName,audioName,fileName,folderName,imageName,vectorGraphicsName,videoName);
await umbracoApi.media.ensureNameNotExists(folderToMoveTooName);
// Action
await umbracoApi.media.createAllFileTypes(articleName, audioName, fileName, folderName, imageName, vectorGraphicsName, videoName);
await umbracoApi.media.createDefaultFolder(folderToMoveTooName);
@@ -60,20 +63,13 @@ test.describe('Media', () => {
await expect(page.locator('[data-element="media-grid"]', {hasText: names.fileTypeNames})).toBeVisible();
}
await expect(page.locator(".umb-folder-grid", {hasText: folderName})).toBeVisible();
// Clean
await umbracoApi.media.deleteAllFiles(articleName, audioName, fileName, folderName, imageName, vectorGraphicsName, videoName);
await umbracoApi.media.ensureNameNotExists(folderToMoveTooName);
});
test('sort by Name', async ({page, umbracoApi, umbracoUi}) => {
const FolderNameA = 'A';
const FolderNameB = 'B';
const FolderNameC = 'C';
await umbracoApi.media.ensureNameNotExists(FolderNameA);
await umbracoApi.media.ensureNameNotExists(FolderNameB);
await umbracoApi.media.ensureNameNotExists(FolderNameC);
// Action
await umbracoApi.media.createDefaultFolder(FolderNameC);
await umbracoApi.media.createDefaultFolder(FolderNameB);
@@ -88,16 +84,10 @@ test.describe('Media', () => {
// Assert
const item = await page.locator('[ui-sortable="vm.sortableOptions"]').locator("xpath=/*[1]")
await expect(item).toContainText(FolderNameA);
// Clean
await umbracoApi.media.ensureNameNotExists(FolderNameA);
await umbracoApi.media.ensureNameNotExists(FolderNameB);
await umbracoApi.media.ensureNameNotExists(FolderNameC);
});
test('search after a specific Folder', async ({page, umbracoApi, umbracoUi}) => {
const FolderSearchName = 'SearchMe';
await umbracoApi.media.ensureNameNotExists(FolderSearchName);
// Action
await umbracoApi.media.createDefaultFolder(FolderSearchName)
@@ -106,16 +96,11 @@ test.describe('Media', () => {
// Assert
await expect(page.locator(".umb-folder-grid__folder-description", {hasText: FolderSearchName})).toBeVisible();
// Clean
await umbracoApi.media.ensureNameNotExists(FolderSearchName);
});
test('change Grid to List', async ({page, umbracoApi, umbracoUi}) => {
const FolderOneName = 'FolderOne';
const FolderTwoName = 'FolderTwo';
await umbracoApi.media.ensureNameNotExists(FolderOneName);
await umbracoApi.media.ensureNameNotExists(FolderTwoName);
// Action
await umbracoApi.media.createDefaultFolder(FolderOneName);
@@ -126,17 +111,11 @@ test.describe('Media', () => {
// Assert
await expect(page.locator('[icon="icon-list"]')).toBeVisible();
// Clean
await umbracoApi.media.ensureNameNotExists(FolderOneName);
await umbracoApi.media.ensureNameNotExists(FolderTwoName);
});
test('change List to Grid', async ({page, umbracoApi, umbracoUi}) => {
const FolderOneName = 'FolderOne';
const FolderTwoName = 'FolderTwo';
await umbracoApi.media.ensureNameNotExists(FolderOneName);
await umbracoApi.media.ensureNameNotExists(FolderTwoName);
// Action
await umbracoApi.media.createDefaultFolder(FolderOneName);
@@ -150,9 +129,5 @@ test.describe('Media', () => {
// Assert
await expect(page.locator('[icon="icon-thumbnails-small"]')).toBeVisible();
// Clean
await umbracoApi.media.ensureNameNotExists(FolderOneName);
await umbracoApi.media.ensureNameNotExists(FolderTwoName);
});
});

View File

@@ -193,7 +193,9 @@ test.describe('Modelsbuilder tests', () => {
await umbracoApi.templates.ensureNameNotExists(docTypeName);
});
test('Can update view and document type', async ({page, umbracoApi, umbracoUi}) => {
test('Can update view and document type', async ({page, umbracoApi, umbracoUi},testInfo) => {
await testInfo.slow();
const docTypeName = "TestDocument";
const docTypeAlias = AliasHelper.toAlias(docTypeName);
const propertyAlias = "title";
@@ -263,7 +265,7 @@ test.describe('Modelsbuilder tests', () => {
// We only have to type out the opening tag, the editor adds the closing tag automatically.
await editor.type("<p>@Model.Bod");
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
await umbracoUi.isSuccessNotificationVisible({timeout: 10000});
await umbracoUi.isSuccessNotificationVisible({timeout: 20000});
await page.locator('span:has-text("×")').click();
// Navigate to the content section and update the content
@@ -273,6 +275,8 @@ test.describe('Modelsbuilder tests', () => {
await page.locator("#bod").type("Fancy body text");
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.saveAndPublish));
await page.waitForTimeout(2000);
await umbracoApi.content.verifyRenderedContent("/", "<h1>" + propertyValue + "</h1><p>Fancy body text</p>", true);
await umbracoApi.content.deleteAllContent();

View File

@@ -79,6 +79,7 @@ test.describe('Packages', () => {
// Fill out package creation form
// Waits until the element package Content is visible
await page.locator('[key="packager_packageContent"]').isVisible();
await expect(page.locator('[label="@treeHeaders_documentTypes"]').locator('[text="' + rootDocTypeName + '"]')).toBeVisible();
await page.locator("#headerName").type(packageName);
await page.locator('.controls > .umb-node-preview-add').click();
await page.locator('.umb-tree-item__label').first().click();

View File

@@ -23,7 +23,7 @@ test.describe('Partial Views', () => {
const name = "TestPartialView";
const fileName = name + ".cshtml";
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
await openPartialViewsCreatePanel(page, umbracoUi);
@@ -31,23 +31,23 @@ test.describe('Partial Views', () => {
await page.locator('.menu-label localize[key="create_newEmptyPartialView"]').click();
//Type name
await umbracoUi.setEditorHeaderName(name);
await page.locator('[data-element="editor-name-field"]').type(name);
//Save
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
//Assert
await umbracoUi.isSuccessNotificationVisible({timeout:10000});
await umbracoUi.isSuccessNotificationVisible({timeout: 20000});
//Clean up
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
});
test('Create partial view from snippet', async ({page, umbracoApi, umbracoUi}) => {
const name = "TestPartialViewFromSnippet";
const fileName = name + ".cshtml";
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
await openPartialViewsCreatePanel(page, umbracoUi);
@@ -63,10 +63,10 @@ test.describe('Partial Views', () => {
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
// Assert
await umbracoUi.isSuccessNotificationVisible({timeout:10000});
await umbracoUi.isSuccessNotificationVisible({timeout:20000});
// Clean up
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
});
test('Partial view with no name', async ({page, umbracoApi, umbracoUi}) => {
@@ -90,7 +90,7 @@ test.describe('Partial Views', () => {
const name = "TestDeletePartialView";
const fileName = name + ".cshtml";
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
// Build and save partial view
const partialView = new PartialViewBuilder()
@@ -111,14 +111,14 @@ test.describe('Partial Views', () => {
await expect(await page.locator("body", { hasText: fileName})).not.toBeVisible();
// Clean
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
});
test('Edit partial view', async ({page, umbracoApi, umbracoUi}) => {
const name = 'EditPartialView';
const fileName = name + ".cshtml";
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
const partialView = new PartialViewBuilder()
.withName(name)
@@ -135,9 +135,9 @@ test.describe('Partial Views', () => {
await umbracoUi.clickElement(umbracoUi.getButtonByLabelKey(ConstantHelper.buttons.save));
// Assert
await umbracoUi.isSuccessNotificationVisible({timeout:10000});
await umbracoUi.isSuccessNotificationVisible({timeout:20000});
// Clean
await umbracoApi.partialViews.ensureNameNotExists(fileName);
await umbracoApi.partialViews.ensureNameNotExists('', fileName);
});
});