mercury_editor-2.0.x-dev/tests/cypress/cypress/e2e/mercury-editor/mercury-editor-component-outline.cy.js
tests/cypress/cypress/e2e/mercury-editor/mercury-editor-component-outline.cy.js
/**
* Mercury Editor component outline e2e tests.
*/
import '@4tw/cypress-drag-drop'
Cypress.config('defaultCommandTimeout', 10000);
describe('Mercury Editor component outline e2e tests.', () => {
before(() => {
// Install the Mercury Editor test module.
cy.drush('en mercury_editor_setup_test');
// Clear the cache.
cy.drush('cr');
// Give us a taller viewport to work with.
cy.viewport(1000, 800);
});
beforeEach(() => {
// Login as admin.
cy.loginUserByUid(1);
});
it('opens and closes the component outline', () => {
// Create a new page.
cy.visit('/node/add/me_test_ct');
// Wait for the Mercury Editor interface to fully load
cy.get('#me-preview').its('0.contentDocument');
// Check that the component outline button exists
cy.openComponentOutline();
// Wait for the component outline to be loaded via AJAX
cy.get('.me-component-outline')
.should('exist');
// Close the outline
cy.closeComponentOutline();
// Ensure it's closed.
cy.get('.me-component-outline')
.should('not.exist');
});
describe('Component Outline with Nested Layouts', () => {
before(() => {
cy.loginUserByUid(1);
// Adjust content type to support nested layouts.
cy.visit('admin/structure/types/manage/me_test_ct/form-display');
cy.get('[data-drupal-selector="edit-fields-field-me-test-content-settings-edit"]').click();
cy.get('[data-drupal-selector="edit-fields-field-me-test-content-settings-edit-form-settings-nesting-depth"]').select('1');
cy.get('input[name="field_me_test_content_plugin_settings_update"]').click();
cy.contains('You have unsaved changes.');
cy.get('input[value="Save"]').click();
// Create a new page.
cy.visit('/node/add/me_test_ct');
// Wait for the Mercury Editor interface to fully load
cy.get('#me-preview').its('0.contentDocument');
// Set the title of the page
cy.get('input[name="title[0][value]"]').clear();
cy.get('input[name="title[0][value]"]').type('Component Outline Test');
cy.iframe('#me-preview').find('.page-title').contains('Component Outline Test');
// Create nested structure:
// - Section 1 (Two Column)
// - left: Text Component A
// - right: Section 2 (Two Column)
// - Left: Text Component B
// - Right: Text Component C
// - Text Component D
// - Section 3 (Two Column)
// - left: Text Component D
// - right: Text Component E
// First section
cy.meAddComponent('me_test_section');
cy.meChooseLayout('layout_twocol');
cy.meSaveComponent().then((section1) => {
cy.meSelectComponent(section1.attr('data-uuid'));
cy.meAddComponent('me_test_text', { region: 'first', section: section1 });
cy.meSetCKEditor5Value('field_me_test_text', 'Text A');
cy.meSaveComponent();
// Nested section
cy.meSelectComponent(section1.attr('data-uuid'));
cy.meAddComponent('me_test_section', { region: 'second', section: section1 });
cy.meChooseLayout('layout_twocol');
cy.meSaveComponent().then((section2) => {
cy.meSelectComponent(section2.attr('data-uuid'));
cy.meAddComponent('me_test_text', { region: 'first', section: section2 });
cy.meSetCKEditor5Value('field_me_test_text', 'Text B');
cy.meSaveComponent();
cy.meSelectComponent(section2.attr('data-uuid'));
cy.meAddComponent('me_test_text', { region: 'second', section: section2 });
cy.meSetCKEditor5Value('field_me_test_text', 'Text C');
cy.meSaveComponent();
});
cy.meSelectComponent(section1.attr('data-uuid'));
cy.meAddComponent('me_test_section', { after: section1 });
cy.meChooseLayout('layout_twocol');
cy.meSaveComponent().then((section3) => {
cy.meSelectComponent(section3.attr('data-uuid'));
cy.meAddComponent('me_test_text', { region: 'first', section: section3 });
cy.meSetCKEditor5Value('field_me_test_text', 'Text D');
cy.meSaveComponent();
cy.meSelectComponent(section3.attr('data-uuid'));
cy.meAddComponent('me_test_text', { region: 'second', section: section3 });
cy.meSetCKEditor5Value('field_me_test_text', 'Text E');
cy.meSaveComponent();
});
});
cy.meSavePage();
});
beforeEach(() => {
// Login as admin.
cy.loginUserByUid(1);
// Find the page we created.
cy.visit('/admin/content');
cy.get('a[aria-label="Edit Component Outline Test"]').first().click({force: true});
});
it('displays components in an outline', () => {
// Open the component outline
cy.openComponentOutline();
// Ensure the component outline is visible
cy.get('.me-component-outline__list[role="tree"]')
.should('exist');
// Close the outline
cy.closeComponentOutline();
});
it('updates the outline when items are reordered', () => {
// Open the component outline
cy.openComponentOutline();
// Before reordering, ensure the outline is correct.
cy
.get('.me-component-outline')
.find('.me-component-outline__component .me-component-outline__component')
.find('.me-component-outline__regions .me-component-outline__region:nth-child(2)')
.contains('Text');
cy
.get('.me-component-outline')
.find('.me-component-outline__component .me-component-outline__component')
.find('.me-component-outline__regions .me-component-outline__region:nth-child(3)')
.contains('Text');
cy.meFindComponent('Text B').then((component) => {
cy.meSelectComponent(component.attr('data-uuid'));
});
// Move the selected component (Text B) down
cy.iframe('#me-preview').find('[data-active="true"] .lpb-down').click();
// After reordering, ensure the outline is updated.
cy
.get('.me-component-outline')
.find('.me-component-outline__component .me-component-outline__component')
.find('.me-component-outline__regions .me-component-outline__region:nth-child(2)')
.should('not.contain', 'Text');
cy
.get('.me-component-outline')
.find('.me-component-outline__component .me-component-outline__component')
.find('.me-component-outline__regions .me-component-outline__region:nth-child(3)')
.find('.me-component-outline__component:nth-child(1)')
.contains('Text');
cy
.get('.me-component-outline')
.find('.me-component-outline__component .me-component-outline__component')
.find('.me-component-outline__regions .me-component-outline__region:nth-child(3)')
.find('.me-component-outline__component:nth-child(2)')
.contains('Text');
// Close the outline
cy.closeComponentOutline();
});
it('syncs highlighted state with the preview', () => {
// Open the component outline
cy.openComponentOutline();
// No item should be highlighted initially
cy.get('.me-component-outline__component.is-highlighted').should('not.exist');
// Click on the controls of the first section component in the outline
cy.get('.me-component-outline__component[data-uuid] .me-component-outline__component-controls')
.first()
.click()
.then((controls) => {
const uuid = controls.attr('data-uuid');
// Ensure the corresponding item in the outline is highlighted
cy.get(`.me-component-outline__component[data-uuid="${uuid}"]`)
.should('have.class', 'is-highlighted');
// Ensure the section component with the matching UUID is active in the preview
cy.iframe('#me-preview').find(`[data-uuid="${uuid}"][data-active="true"]`).should('exist');
});
// Click on the first text component in the preview
cy.iframe('#me-preview').find('[data-type="me_test_text"]')
.first()
.click()
.then((textComponent) => {
const textUuid = textComponent.attr('data-uuid');
// Ensure the corresponding item in the outline is highlighted
cy.get(`.me-component-outline__component[data-uuid="${textUuid}"]`)
.should('have.class', 'is-highlighted');
});
// Close the outline
cy.closeComponentOutline();
// Reopen the outline
cy.openComponentOutline();
// Ensure the previously highlighted item is still highlighted
cy.iframe('#me-preview').find('[data-active="true"]').then(($activeComponent) => {
const activeUuid = $activeComponent.attr('data-uuid');
cy.get(`.me-component-outline__component[data-uuid="${activeUuid}"]`)
.should('have.class', 'is-highlighted');
});
// Click on the h1.page-title in the preview
cy.iframe('#me-preview').find('h1.page-title').click();
// Ensure no component in the preview is active
cy.iframe('#me-preview').find('[data-active="true"]').should('not.exist');
// Ensure no item in the outline is highlighted
cy.get('.me-component-outline__component.is-highlighted').should('not.exist');
// Close the outline
cy.closeComponentOutline();
// Reopen the outline
cy.openComponentOutline();
// Ensure no item in the outline is highlighted
cy.get('.me-component-outline__component.is-highlighted').should('not.exist');
// Focus on the first section component in the outline
cy.get('.me-component-outline__component[role="treeitem"]')
.first()
.focus();
// Typing Enter key should activate an outline item
cy.focused().type('{enter}')
.then((item) => {
const uuid = item.attr('data-uuid');
// Ensure the corresponding item in the outline is highlighted
cy.get(`.me-component-outline__component[data-uuid="${uuid}"]`)
.should('have.class', 'is-highlighted');
// Ensure the section component with the matching UUID is active in the preview
cy.iframe('#me-preview').find(`[data-uuid="${uuid}"][data-active="true"]`).should('exist');
});
});
it('implements proper ARIA attributes and roles', () => {
// Open the component outline
cy.openComponentOutline();
// Check tree structure has proper ARIA roles
cy.getComponentOutline().should('have.attr', 'role', 'tree');
cy.getComponentOutline().should('have.attr', 'aria-label');
// Check that tree items exist
cy.get('.me-component-outline__component[role="treeitem"]')
.should('have.length', 8)
// Check that sections are expandable
cy.get('.me-component-outline__component[role="treeitem"][aria-expanded]')
.should('have.length', 3)
// Check that sections have toggles
cy.get('.me-component-outline__component[role="treeitem"][aria-expanded] .me-component-outline__component-toggle')
.should('have.length', 3);
// Check regions have proper group role
cy.get('.me-component-outline__regions[role="group"]').should('exist');
// Check that only one item has tabindex="0" (roving tabindex)
cy.getTreeItems().then(($items) => {
const focusableItems = Array.from($items).filter(item => item.tabIndex === 0);
expect(focusableItems).to.have.length(1);
});
});
it('supports arrow key navigation', () => {
// Open the component outline
cy.openComponentOutline();
// Focus first tree item
cy.getTreeItems().first().focus();
// Test Down Arrow - moves to next visible item
cy.getTreeItems().first().type('{downarrow}');
cy.getVisibleTreeItems().eq(1).should('be.focused');
// Test Up Arrow - moves to previous visible item
cy.focused().type('{uparrow}');
cy.getVisibleTreeItems().eq(0).should('be.focused');
// Test End - moves to last visible item
cy.focused().type('{end}');
cy.getVisibleTreeItems().last().should('be.focused');
// Test Home - moves to first item
cy.focused().type('{home}');
cy.getVisibleTreeItems().first().should('be.focused');
});
it('supports Right Arrow key for expansion', () => {
// Open the component outline
cy.openComponentOutline();
// Focus first section (should be expandable)
cy.getTreeItemByLabel('Section - Two column').first().focus();
// Right arrow on collapsed node should expand it
cy.focused().type('{rightarrow}');
cy.isTreeItemExpanded(cy.getTreeItemByLabel('Section - Two column').first());
// Right arrow on expanded node should move to first child
cy.focused().type('{rightarrow}');
// Should focus on top region
cy.focused()
.find('.me-component-outline__region-label').first()
.should('contain', 'Top')
.should('be.visible');
// Move to first section
cy.focused().type('{downarrow}');
// Should focus first section
cy.focused()
.find('.me-component-outline__region-label').first()
.should('contain', 'First')
.should('be.visible');
// Right arrow on expanded node should move to first child
cy.focused().type('{rightarrow}');
// Should focus first child component
cy.focused()
.find('.me-component-outline__component-label--component').first()
.should('contain', 'Text')
.should('be.visible');
});
it('supports Left Arrow key for collapse and parent navigation', () => {
// Open the component outline
cy.openComponentOutline();
// Expand first section
cy.getTreeItemByLabel('Section - Two column').first().focus();
cy.focused().type('{rightarrow}'); // Expand
cy.isTreeItemExpanded(cy.getTreeItemByLabel('Section - Two column').first());
cy.focused().type('{rightarrow}'); // Move to child
cy.focused().type('{downarrow}'); // Move to next region
cy.focused().type('{rightarrow}'); // Move to child
cy.getTreeItemByLabel('Text').first().should('be.focused');
// Left arrow on child should move to parent
cy.focused().type('{leftarrow}');
// Should focus parent region
cy.focused()
.find('.me-component-outline__region-label').first()
.should('contain', 'First')
.should('be.visible');
// Left arrow on child should move to parent
cy.focused().type('{leftarrow}');
cy.getTreeItemByLabel('Section - Two column').first().should('be.focused');
// Left arrow on expanded parent should collapse it
cy.focused().type('{leftarrow}');
cy.isTreeItemCollapsed(cy.getTreeItemByLabel('Section - Two column').first());
});
it('supports Enter key activation', () => {
// Open the component outline
cy.openComponentOutline();
// Focus a component (not section)
cy.getTreeItemByLabel('Section - Two column').first().focus();
cy.focused().type('{rightarrow}'); // Expand
cy.focused().type('{rightarrow}'); // Move to child component
// Enter should activate the component (select it in the editor)
cy.focused().type('{enter}');
// This should trigger component selection in the preview frame
// We can verify this by checking if a message was sent to the iframe
// Note: In a real test, you might need to spy on postMessage calls
});
it('supports type-ahead search', () => {
// Open the component outline
cy.openComponentOutline();
// Expand sections to make components visible
cy.getTreeItemByLabel('Section - Two column').first().focus();
cy.focused().type('{rightarrow}'); // Expand first section
// Type 'T' to search for 'Text'
cy.focused().type('t');
// Should focus on first item starting with 'T'
cy.focused().should('contain.text', 'Text');
// Type 'e' to continue search for 'Te'
cy.focused().type('e');
// Should still be on a Text component
cy.focused().should('contain.text', 'Text');
});
it('maintains focus visibility and roving tabindex', () => {
// Open the component outline
cy.openComponentOutline();
// Focus first item
cy.getVisibleTreeItems().first().focus();
cy.getVisibleTreeItems().first().should('have.attr', 'tabindex', '0');
// Move to next item
cy.focused().type('{downarrow}');
// Previous item should have tabindex="-1", current should have tabindex="0"
cy.getVisibleTreeItems().first().should('have.attr', 'tabindex', '-1');
cy.getVisibleTreeItems().eq(1).should('have.attr', 'tabindex', '0');
});
it('implements proper ARIA attributes for menu buttons', () => {
// Open the component outline
cy.openComponentOutline();
// Check menu toggle buttons have proper attributes
cy.get('.me-component-outline__component-menu-toggle').each(($button) => {
cy.wrap($button).should('have.attr', 'aria-haspopup', 'true');
cy.wrap($button).should('have.attr', 'aria-expanded', 'false');
});
// Check menu dialogs have proper attributes when closed
cy.get('.me-component-outline__component-menu-dialog').each(($dialog) => {
cy.wrap($dialog).should('have.attr', 'role', 'menu');
cy.wrap($dialog).should('have.attr', 'aria-hidden', 'true');
cy.wrap($dialog).should('not.have.attr', 'open');
});
});
it('opens menu with Space and Enter keys', () => {
// Open the component outline
cy.openComponentOutline();
// Focus first tree item, then tab to menu button
cy.getTreeItems().first().focus();
cy.focused().find('.me-component-outline__component-menu-toggle').first().focus();
// Space key should open menu and focus on first item
cy.focused().type(' ').should('have.attr', 'aria-expanded', 'true');
cy.getMenuItems().first().should('be.focused');
// Close menu and refocus on treeitem
cy.focused().type('{esc}');
cy.focused().should('have.attr', 'role', 'treeitem');
cy.focused().find('.me-component-outline__component-menu-toggle').first().focus();
// Enter key should also open menu
cy.focused().type('{enter}');
cy.getMenuItems().first().should('be.focused');
});
it('opens menu with Down Arrow and focuses first item', () => {
// Open the component outline
cy.openComponentOutline();
cy.getTreeItems().first().focus();
cy.focused().find('.me-component-outline__component-menu-toggle').first().focus();
// Down arrow should open menu and focus first menu item
cy.focused().type('{downarrow}').should('have.attr', 'aria-expanded', 'true');
cy.getMenuItems().first().should('be.focused');
});
it('supports menu item navigation with arrow keys', () => {
// Open the component outline
cy.openComponentOutline();
// Open menu
cy.getTreeItems().first().focus();
cy.focused().find('.me-component-outline__component-menu-toggle').first().click();
// Focus first menu item
cy.getMenuItems().first().focus();
// Down arrow moves to next item
cy.focused().type('{downarrow}');
cy.getMenuItems().eq(1).should('be.focused');
// Up arrow moves back
cy.focused().type('{uparrow}');
cy.getMenuItems().first().should('be.focused');
// Down arrow at last item wraps to first
cy.getMenuItems().last().focus();
cy.focused().type('{downarrow}');
cy.getMenuItems().first().should('be.focused');
// Up arrow at first item wraps to last
cy.focused().type('{uparrow}');
cy.getMenuItems().last().should('be.focused');
});
it('closes menu when clicking outside', () => {
// Open the component outline
cy.openComponentOutline();
// Open menu
cy.getTreeItems().first().focus();
cy.focused().find('.me-component-outline__component-menu-toggle').first().click();
cy.get('.me-component-outline__component-menu-dialog[open]').should('exist');
// Click outside
cy.get('body').click();
cy.get('.me-component-outline__component-menu-dialog[open]').should('not.exist');
});
// TODO: Revisit this once we've upgraded to Cypress 14.3+ when the `cy.press()` command was introduced.
// it('supports Tab key to leave menu', () => {
// // Open the component outline
// cy.openComponentOutline();
// // Open menu and focus menu item
// cy.getTreeItems().first().focus();
// cy.focused().find('.me-component-outline__component-menu-toggle').first().click();
// cy.getMenuItems().first().focus();
// // Tab should close menu and move focus to next focusable element
// cy.focused().press(Cypress.Keyboard.Keys.TAB);
// cy.get('.me-component-outline__component-menu-dialog[open]').should('not.exist');
// });
it('maintains only one menu open at a time', () => {
// Open the component outline
cy.openComponentOutline();
// Open first menu
cy.getVisibleTreeItems().eq(0).find('.me-component-outline__component-menu-toggle').first().click();
cy.get('.me-component-outline__component-menu-dialog[open]').should('have.length', 1);
// Open second menu
cy.getVisibleTreeItems().eq(1).find('.me-component-outline__component-menu-toggle').first().click({force: true});
// Only second menu should be open
cy.getVisibleTreeItems().eq(1).find('.me-component-outline__component-menu-dialog[open]').first().should('have.length', 1);
cy.getVisibleTreeItems().eq(1).find('.me-component-outline__component-menu-toggle').first().should('have.attr', 'aria-expanded', 'true');
cy.getVisibleTreeItems().eq(0).find('.me-component-outline__component-menu-toggle').first().should('have.attr', 'aria-expanded', 'false');
});
it('remembers expanded/collapsed states across when menu is reopened or page reloads', () => {
// Open the component outline
cy.openComponentOutline();
cy.getVisibleTreeItems().should('have.length', 2);
// Focus first tree item
cy.getVisibleTreeItems().first().focus();
// Test Right Arrow - opens menu
cy.focused().type('{rightarrow}');
cy.getVisibleTreeItems().should('have.length', 8);
// 0 items should be visible when closed.
cy.closeComponentOutline();
cy.getTreeItems().should('not.exist');
// 4 items should still be visible when reopened.
cy.openComponentOutline();
cy.getVisibleTreeItems().should('have.length', 8);
// Reload page
cy.reload();
// 4 items should still be visible when reopened.
cy.openComponentOutline();
cy.getVisibleTreeItems().should('have.length', 8);
});
it('edits, duplicates, and deletes components via the menu', () => {
cy.openComponentOutline();
// Edit Text A
cy.getVisibleTreeItems().eq(0).find('.me-component-outline__component-toggle').first().click();
cy.getVisibleTreeItems().eq(3).find('.me-component-outline__component-menu-toggle').first().click();
cy.getMenuItems().contains('Edit').click();
cy.get('mercury-dialog[id^="lpb-dialog-"]').find('.layout-paragraphs-component-form').should('exist');
cy.meSetCKEditor5Value('field_me_test_text', 'Text A - edited');
cy.meSaveComponent();
cy.iframe('#me-preview').find('[data-type="me_test_text"]').first().should('contain.text', 'Text A - edited');
// Duplicate Text A
cy.getVisibleTreeItems().eq(3).find('.me-component-outline__component-menu-toggle').first().click();
cy.getMenuItems().contains('Duplicate').click();
cy.iframe('#me-preview')
.find('[data-type="me_test_text"]')
.filter(':contains("Text A - edited")')
.should('have.length', 2);
// Delete duplicated Text A.
cy.getVisibleTreeItems().eq(4).find('.me-component-outline__component-menu-toggle').first().click();
cy.getMenuItems().contains('Delete').click();
cy.get('mercury-dialog[id^="lpb-dialog-"]').contains('Really delete this "Text" component?').should('exist');
cy.get('[slot="footer"] .lpb-btn--confirm-delete').click();
cy.iframe('#me-preview')
.find('[data-type="me_test_text"]')
.filter(':contains("Text A - edited")')
.should('have.length', 1);
});
it('drags elements to reorder them', () => {
cy.openComponentOutline();
// Expand all sections.
cy.get('.me-component-outline__component-toggle').click({
multiple: true,
force: true,
});
// Drag and drop a text element from one region to another.
cy.get('#me-component-outline-wrapper').then(($wrapper) => {
$wrapper[0].classList.add('cy-is-updating');
});
cy
.get('.me-component-outline__component[data-type="me_test_text"]')
.first()
.drag('.me-component-outline__region[data-region="top"] .me-component-outline__components');
cy
.get('.me-component-outline__region[data-region="top"]')
.find('.me-component-outline__component[data-type="me_test_text"]')
.should('have.length', 1);
// Assert wrapper is no longer updating.
cy.get('#me-component-outline-wrapper').should('not.have.class', 'cy-is-updating');
// Drag and drop a section to the first top region.
cy.get('#me-component-outline-wrapper').then(($wrapper) => {
$wrapper[0].classList.add('cy-is-updating');
});
cy
.get('[data-region="top"] ul')
.first()
.then(($dest) => {
cy
.get('[data-is-layout="true"]')
.eq(2)
.drag(
$dest,
{
source: { x: 20, y: 5 },
target: { x: 20, y: 1 }
},
);
});
// Assert wrapper is no longer updating.
cy.get('#me-component-outline-wrapper').should('not.have.class', 'cy-is-updating');
cy
.get('[data-region="top"] [data-is-layout="true"]')
.should('have.length', 1);
// Drag and drop a text element to the top level.
cy.get('#me-component-outline-wrapper').then(($wrapper) => {
$wrapper[0].classList.add('cy-is-updating');
});
cy
.get('[data-type="me_test_text"]')
.eq(0)
.drag(
'.me-component-outline > .me-component-outline__list :first-child',
{
source: { x: 20, y: 5 },
target: { x: 20, y: 5 }
}
);
cy
.get('[data-type="me_test_text"][style="--me-treeitem-depth: 0;"]')
.should('have.length', 1);
// Assert wrapper is no longer updating.
cy.get('#me-component-outline-wrapper').should('not.have.class', 'cy-is-updating');
});
it('cannot drag a section deeper than the allowed nesting depth', () => {
cy.openComponentOutline();
cy.get('.me-component-outline__component-toggle').click({
multiple: true,
force: true,
});
cy
.get('[data-is-layout="true"]')
.eq(2)
.drag(
'[data-is-layout="true"] [data-is-layout="true"] [data-region="top"] ul',
{
source: { x: 20, y: 5 }
},
);
cy
.get('[data-is-layout="true"] [data-is-layout="true"] [data-is-layout="true"]')
.should('have.length', 0);
});
it('respects "require section" setting when dragging components', () => {
// Adjust content type to require sections.
cy.visit('admin/structure/types/manage/me_test_ct/form-display');
cy.get('[data-drupal-selector="edit-fields-field-me-test-content-settings-edit"]').click();
cy.get('[data-drupal-selector="edit-fields-field-me-test-content-settings-edit-form-settings-require-layouts"]').check();
cy.get('input[name="field_me_test_content_plugin_settings_update"]').click();
cy.contains('You have unsaved changes.');
cy.get('input[value="Save"]').click();
// Find the page we created.
cy.visit('/admin/content');
cy.get('a[aria-label="Edit Component Outline Test"]').first().click({force: true});
cy.openComponentOutline();
cy.get('.me-component-outline__component-toggle').click({
multiple: true,
force: true,
});
cy.get('[data-type="me_test_text"]').eq(0).drag(
'.me-component-outline > .me-component-outline__list :first-child',
{
source: { x: 20, y: 5 },
target: { x: 20, y: 5 }
}
);
cy
.get('.me-component-outline > [data-type="me_test_text"]')
.should('have.length', 0);
// Adjust content type to require sections.
cy.visit('admin/structure/types/manage/me_test_ct/form-display');
cy.get('[data-drupal-selector="edit-fields-field-me-test-content-settings-edit"]').click();
cy.get('[data-drupal-selector="edit-fields-field-me-test-content-settings-edit-form-settings-require-layouts"]').uncheck();
cy.get('input[name="field_me_test_content_plugin_settings_update"]').click();
cy.contains('You have unsaved changes.');
cy.get('input[value="Save"]').click();
});
});
});
