Initial Drupal 11 with DDEV setup
This commit is contained in:
		@ -0,0 +1,101 @@
 | 
			
		||||
const mainContent = '.region-content';
 | 
			
		||||
const mainMessagesContainer =
 | 
			
		||||
  '[data-drupal-messages] > .messages-list__wrapper';
 | 
			
		||||
const secondaryMessagesContainer = '[data-drupal-messages-other]';
 | 
			
		||||
 | 
			
		||||
const mainButtons = {
 | 
			
		||||
  addStatus: '#add--status',
 | 
			
		||||
  removeStatus: '#remove--status',
 | 
			
		||||
  addError: '#add--error',
 | 
			
		||||
  removeError: '#remove--error',
 | 
			
		||||
  addWarning: '#add--warning',
 | 
			
		||||
  removeWarning: '#remove--warning',
 | 
			
		||||
  clearAll: '#clear-all',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const secondaryButtons = {
 | 
			
		||||
  addStatus: '[id="add-[data-drupal-messages-other]-status"]',
 | 
			
		||||
  removeStatus: '[id="remove-[data-drupal-messages-other]-status"]',
 | 
			
		||||
  addError: '[id="add-[data-drupal-messages-other]-error"]',
 | 
			
		||||
  removeError: '[id="remove-[data-drupal-messages-other]-error"]',
 | 
			
		||||
  addWarning: '[id="add-[data-drupal-messages-other]-warning"]',
 | 
			
		||||
  removeWarning: '[id="remove-[data-drupal-messages-other]-warning"]',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'claro'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall()
 | 
			
		||||
      .drupalInstallModule('js_message_test')
 | 
			
		||||
      .drupalEnableTheme('claro');
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify default placement of javascript-created messages': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/js_message_test_link_with_system_messages')
 | 
			
		||||
      .waitForElementVisible(mainContent)
 | 
			
		||||
      .assert.elementPresent(mainMessagesContainer)
 | 
			
		||||
 | 
			
		||||
      // We should load 3 messages on page load from \Drupal::messenger()
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages-list__item`, 3)
 | 
			
		||||
 | 
			
		||||
      // We should have one message of each type
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--status`, 1)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--warning`, 1)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--error`, 1)
 | 
			
		||||
 | 
			
		||||
      // Trigger new messages via javascript
 | 
			
		||||
      .click(mainButtons.addStatus)
 | 
			
		||||
      .click(mainButtons.addWarning)
 | 
			
		||||
      .click(mainButtons.addError)
 | 
			
		||||
 | 
			
		||||
      // We should have 6 total messages
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages-list__item`, 6)
 | 
			
		||||
 | 
			
		||||
      // We should have 2 messages of each type
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--status`, 2)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--warning`, 2)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--error`, 2);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Verify customized placement of javascript-created messages': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/js_message_test_link_with_system_messages')
 | 
			
		||||
      .waitForElementVisible(mainContent)
 | 
			
		||||
      .assert.elementPresent(secondaryMessagesContainer)
 | 
			
		||||
 | 
			
		||||
      // We should load 3 messages on page load from \Drupal::messenger()
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages-list__item`,
 | 
			
		||||
        0,
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      // Trigger new messages via javascript
 | 
			
		||||
      .click(secondaryButtons.addStatus)
 | 
			
		||||
      .click(secondaryButtons.addWarning)
 | 
			
		||||
      .click(secondaryButtons.addError)
 | 
			
		||||
 | 
			
		||||
      // We should have 6 total messages
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages-list__item`,
 | 
			
		||||
        3,
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      // We should have 2 messages of each type
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages--status`,
 | 
			
		||||
        1,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages--warning`,
 | 
			
		||||
        1,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages--error`,
 | 
			
		||||
        1,
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,51 @@
 | 
			
		||||
// This test is a duplicate of oliveroPrimaryTabsTest.js tagged for claro
 | 
			
		||||
const primaryTabsWrapper = '[data-drupal-nav-tabs]';
 | 
			
		||||
const activeTab = '.tabs__tab.is-active';
 | 
			
		||||
const inactiveTab = '.tabs__tab:not(.is-active)';
 | 
			
		||||
const mobileToggle = `${activeTab} .tabs__trigger`;
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'claro'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteClaroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['administer nodes'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' });
 | 
			
		||||
    browser.window.setSize(1600, 800);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify desktop primary tab display': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node/1')
 | 
			
		||||
      .waitForElementVisible(primaryTabsWrapper)
 | 
			
		||||
      .assert.visible(activeTab)
 | 
			
		||||
      .assert.visible(inactiveTab)
 | 
			
		||||
      .assert.not.visible(mobileToggle);
 | 
			
		||||
  },
 | 
			
		||||
  'Verify mobile tab display and click functionality': (browser) => {
 | 
			
		||||
    browser.window
 | 
			
		||||
      .setSize(699, 800)
 | 
			
		||||
      .drupalRelativeURL('/node/1')
 | 
			
		||||
      .waitForElementVisible(primaryTabsWrapper)
 | 
			
		||||
      .assert.visible(activeTab)
 | 
			
		||||
      .assert.not.visible(inactiveTab)
 | 
			
		||||
      .assert.visible(mobileToggle)
 | 
			
		||||
      .assert.attributeEquals(mobileToggle, 'aria-expanded', 'false')
 | 
			
		||||
      .click(mobileToggle)
 | 
			
		||||
      .waitForElementVisible(inactiveTab)
 | 
			
		||||
      .assert.attributeEquals(mobileToggle, 'aria-expanded', 'true')
 | 
			
		||||
      .click(mobileToggle)
 | 
			
		||||
      .waitForElementNotVisible(inactiveTab)
 | 
			
		||||
      .assert.attributeEquals(mobileToggle, 'aria-expanded', 'false');
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,134 @@
 | 
			
		||||
const selectors = {
 | 
			
		||||
  schemePicker: '[data-drupal-selector="edit-color-scheme"]',
 | 
			
		||||
  primaryColor: {
 | 
			
		||||
    text: 'input[type="text"][name="base_primary_color"]',
 | 
			
		||||
    color: 'input[type="color"][name="base_primary_color_visual"]',
 | 
			
		||||
  },
 | 
			
		||||
  submit: '[data-drupal-selector="edit-submit"]',
 | 
			
		||||
  siteHeader: '.site-header__initial',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const colorSchemes = {
 | 
			
		||||
  default: {
 | 
			
		||||
    base_primary_color: '#1b9ae4',
 | 
			
		||||
  },
 | 
			
		||||
  firehouse: {
 | 
			
		||||
    base_primary_color: '#a30f0f',
 | 
			
		||||
  },
 | 
			
		||||
  ice: {
 | 
			
		||||
    base_primary_color: '#57919e',
 | 
			
		||||
  },
 | 
			
		||||
  plum: {
 | 
			
		||||
    base_primary_color: '#7a4587',
 | 
			
		||||
  },
 | 
			
		||||
  slate: {
 | 
			
		||||
    base_primary_color: '#47625b',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      // Create user that can search.
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['administer themes', 'view the administration theme'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Olivero Settings - color schemes update individual values': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/admin/appearance/settings/olivero')
 | 
			
		||||
      .waitForElementVisible(selectors.schemePicker)
 | 
			
		||||
      .click(`${selectors.schemePicker} option[value="firehouse"]`)
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.text,
 | 
			
		||||
        colorSchemes.firehouse.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.color,
 | 
			
		||||
        colorSchemes.firehouse.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .click(`${selectors.schemePicker} option[value="ice"]`)
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.text,
 | 
			
		||||
        colorSchemes.ice.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.color,
 | 
			
		||||
        colorSchemes.ice.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .click(`${selectors.schemePicker} option[value="plum"]`)
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.text,
 | 
			
		||||
        colorSchemes.plum.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.color,
 | 
			
		||||
        colorSchemes.plum.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .click(`${selectors.schemePicker} option[value="slate"]`)
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.text,
 | 
			
		||||
        colorSchemes.slate.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.color,
 | 
			
		||||
        colorSchemes.slate.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .click(`${selectors.schemePicker} option[value="default"]`)
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.text,
 | 
			
		||||
        colorSchemes.default.base_primary_color,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.valueEquals(
 | 
			
		||||
        selectors.primaryColor.color,
 | 
			
		||||
        colorSchemes.default.base_primary_color,
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'Olivero Settings - color inputs stay synchronized': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/admin/appearance/settings/olivero')
 | 
			
		||||
      .waitForElementVisible(selectors.primaryColor.text)
 | 
			
		||||
      .waitForElementVisible(selectors.primaryColor.color)
 | 
			
		||||
      .updateValue(selectors.primaryColor.text, '#ff0000')
 | 
			
		||||
      .assert.valueEquals(selectors.primaryColor.color, '#ff0000')
 | 
			
		||||
      .updateValue(selectors.primaryColor.text, '#00ff00')
 | 
			
		||||
      .assert.valueEquals(selectors.primaryColor.color, '#00ff00')
 | 
			
		||||
      .updateValue(selectors.primaryColor.text, '#0000ff')
 | 
			
		||||
      .assert.valueEquals(selectors.primaryColor.color, '#0000ff');
 | 
			
		||||
  },
 | 
			
		||||
  'Olivero Settings - color selections impact olivero theme': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/admin/appearance/settings/olivero')
 | 
			
		||||
      .waitForElementVisible(selectors.primaryColor.color)
 | 
			
		||||
      .updateValue(selectors.primaryColor.text, '#ff0000') // hsl(0, 100%, 50%)
 | 
			
		||||
      .click(selectors.submit)
 | 
			
		||||
      .waitForElementVisible(selectors.primaryColor.color)
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible(selectors.siteHeader)
 | 
			
		||||
      .expect.element(selectors.siteHeader)
 | 
			
		||||
      .to.have.css('backgroundColor', 'rgb(255, 0, 0)');
 | 
			
		||||
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/admin/appearance/settings/olivero')
 | 
			
		||||
      .waitForElementVisible(selectors.primaryColor.color)
 | 
			
		||||
      .updateValue(selectors.primaryColor.text, '#7a4587') // hsl(0, 100%, 50%)
 | 
			
		||||
      .click(selectors.submit)
 | 
			
		||||
      .waitForElementVisible(selectors.primaryColor.color)
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible(selectors.siteHeader)
 | 
			
		||||
      .expect.element(selectors.siteHeader)
 | 
			
		||||
      .to.have.css('backgroundColor', 'rgb(122, 69, 135)');
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
const commentTitleSelector = 'h2.comments__title';
 | 
			
		||||
const commentCountSelector = 'h2.comments__title .comments__count';
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: [
 | 
			
		||||
          'access comments',
 | 
			
		||||
          'post comments',
 | 
			
		||||
          'skip comment approval',
 | 
			
		||||
        ],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Article without comments should not display count': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node/1')
 | 
			
		||||
      .assert.textContains('body', 'Article without comments')
 | 
			
		||||
      .assert.not.elementPresent(commentCountSelector);
 | 
			
		||||
  },
 | 
			
		||||
  'Article with comments should display count': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node/2')
 | 
			
		||||
      .assert.textContains('body', 'Article with comments')
 | 
			
		||||
      .assert.elementPresent(commentTitleSelector)
 | 
			
		||||
      .assert.elementPresent(commentCountSelector)
 | 
			
		||||
      .assert.textContains(commentCountSelector, '2');
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,98 @@
 | 
			
		||||
const headerNavSelector = '#header-nav';
 | 
			
		||||
const linkSubMenuId = 'primary-menu-item-1';
 | 
			
		||||
const buttonSubMenuId = 'primary-menu-item-12';
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      // Login and change max-nesting depth so we can verify that menu levels
 | 
			
		||||
      // greater than 2 do not break the site.
 | 
			
		||||
      .drupalLoginAsAdmin(() => {
 | 
			
		||||
        browser
 | 
			
		||||
          .drupalRelativeURL('/admin/structure/block/manage/olivero_main_menu')
 | 
			
		||||
          .waitForElementVisible('[data-drupal-selector="edit-settings-depth"]')
 | 
			
		||||
          .setValue('[data-drupal-selector="edit-settings-depth"]', 'Unlimited')
 | 
			
		||||
          .click('[data-drupal-selector="edit-actions-submit"]')
 | 
			
		||||
          .waitForElementVisible('body');
 | 
			
		||||
      });
 | 
			
		||||
    browser.window.setSize(1600, 800);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify Olivero desktop menu click functionality': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .waitForElementVisible(headerNavSelector)
 | 
			
		||||
      .assert.not.visible(`#${linkSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${linkSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'false',
 | 
			
		||||
      )
 | 
			
		||||
      .click(`[aria-controls="${linkSubMenuId}"]`)
 | 
			
		||||
      .assert.visible(`#${linkSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${linkSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'true',
 | 
			
		||||
      )
 | 
			
		||||
      // Verify tertiary menu item exists.
 | 
			
		||||
      .assert.visible('#primary-menu-item-11 .primary-nav__menu-link--level-3')
 | 
			
		||||
      // Test interactions for route:<button> menu links.
 | 
			
		||||
      .assert.not.visible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${buttonSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'false',
 | 
			
		||||
      )
 | 
			
		||||
      .click(`[aria-controls="${buttonSubMenuId}"]`)
 | 
			
		||||
      .assert.visible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${buttonSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'true',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'Verify Olivero desktop menu hover functionality': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .waitForElementVisible(headerNavSelector)
 | 
			
		||||
      .assert.visible(headerNavSelector)
 | 
			
		||||
      .assert.not.visible(`#${linkSubMenuId}`)
 | 
			
		||||
      .moveToElement(`[aria-controls="${linkSubMenuId}"]`, 1, 1)
 | 
			
		||||
      .assert.visible(`#${linkSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${linkSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'true',
 | 
			
		||||
      )
 | 
			
		||||
      .assert.not.visible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .moveToElement(`[aria-controls="${buttonSubMenuId}"]`, 1, 1)
 | 
			
		||||
      .assert.visible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${buttonSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'true',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'Verify desktop menu converts to mobile if it gets too long': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .waitForElementVisible('body')
 | 
			
		||||
      .assert.not.elementPresent('body.is-always-mobile-nav')
 | 
			
		||||
      .setWindowSize(1220, 800)
 | 
			
		||||
      .execute(() => {
 | 
			
		||||
        // Directly modify the width of the site branding name so that it causes
 | 
			
		||||
        // the primary navigation to be too long, and switch into mobile mode.
 | 
			
		||||
        document.querySelector('.site-branding__name').style.width = '350px';
 | 
			
		||||
      }, [])
 | 
			
		||||
      .assert.elementPresent('body.is-always-mobile-nav');
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,101 @@
 | 
			
		||||
const mainContent = '#block-olivero-content';
 | 
			
		||||
const mainMessagesContainer = '[data-drupal-messages] > .messages__wrapper';
 | 
			
		||||
const secondaryMessagesContainer = '[data-drupal-messages-other]';
 | 
			
		||||
 | 
			
		||||
const mainButtons = {
 | 
			
		||||
  addStatus: '#add--status',
 | 
			
		||||
  removeStatus: '#remove--status',
 | 
			
		||||
  addError: '#add--error',
 | 
			
		||||
  removeError: '#remove--error',
 | 
			
		||||
  addWarning: '#add--warning',
 | 
			
		||||
  removeWarning: '#remove--warning',
 | 
			
		||||
  clearAll: '#clear-all',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const secondaryButtons = {
 | 
			
		||||
  addStatus: '[id="add-[data-drupal-messages-other]-status"]',
 | 
			
		||||
  removeStatus: '[id="remove-[data-drupal-messages-other]-status"]',
 | 
			
		||||
  addError: '[id="add-[data-drupal-messages-other]-error"]',
 | 
			
		||||
  removeError: '[id="remove-[data-drupal-messages-other]-error"]',
 | 
			
		||||
  addWarning: '[id="add-[data-drupal-messages-other]-warning"]',
 | 
			
		||||
  removeWarning: '[id="remove-[data-drupal-messages-other]-warning"]',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile:
 | 
			
		||||
        'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
      installProfile: 'minimal',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify default placement of javascript-created messages': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/js_message_test_link_with_system_messages')
 | 
			
		||||
      .waitForElementVisible(mainContent)
 | 
			
		||||
      .assert.elementPresent(mainMessagesContainer)
 | 
			
		||||
 | 
			
		||||
      // We should load 3 messages on page load from \Drupal::messenger()
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages-list__item`, 3)
 | 
			
		||||
 | 
			
		||||
      // We should have one message of each type
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--status`, 1)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--warning`, 1)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--error`, 1)
 | 
			
		||||
 | 
			
		||||
      // Trigger new messages via javascript
 | 
			
		||||
      .click(mainButtons.addStatus)
 | 
			
		||||
      .click(mainButtons.addWarning)
 | 
			
		||||
      .click(mainButtons.addError)
 | 
			
		||||
 | 
			
		||||
      // We should have 6 total messages
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages-list__item`, 6)
 | 
			
		||||
 | 
			
		||||
      // We should have 2 messages of each type
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--status`, 2)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--warning`, 2)
 | 
			
		||||
      .assert.elementCount(`${mainMessagesContainer} > .messages--error`, 2);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Verify customized placement of javascript-created messages': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/js_message_test_link_with_system_messages')
 | 
			
		||||
      .waitForElementVisible(mainContent)
 | 
			
		||||
      .assert.elementPresent(secondaryMessagesContainer)
 | 
			
		||||
 | 
			
		||||
      // We should load 3 messages on page load from \Drupal::messenger()
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages-list__item`,
 | 
			
		||||
        0,
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      // Trigger new messages via javascript
 | 
			
		||||
      .click(secondaryButtons.addStatus)
 | 
			
		||||
      .click(secondaryButtons.addWarning)
 | 
			
		||||
      .click(secondaryButtons.addError)
 | 
			
		||||
 | 
			
		||||
      // We should have 6 total messages
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages-list__item`,
 | 
			
		||||
        3,
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      // We should have 2 messages of each type
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages--status`,
 | 
			
		||||
        1,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages--warning`,
 | 
			
		||||
        1,
 | 
			
		||||
      )
 | 
			
		||||
      .assert.elementCount(
 | 
			
		||||
        `${secondaryMessagesContainer} > .messages--error`,
 | 
			
		||||
        1,
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,66 @@
 | 
			
		||||
const preloadFontPaths = [
 | 
			
		||||
  'core/themes/olivero/fonts/metropolis/Metropolis-Regular.woff2',
 | 
			
		||||
  'core/themes/olivero/fonts/metropolis/Metropolis-SemiBold.woff2',
 | 
			
		||||
  'core/themes/olivero/fonts/metropolis/Metropolis-Bold.woff2',
 | 
			
		||||
  'core/themes/olivero/fonts/lora/lora-v14-latin-regular.woff2',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile:
 | 
			
		||||
        'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
      installProfile: 'minimal',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify font loading': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible('body')
 | 
			
		||||
      // Check that <link rel="preload"> tags properly reference font.
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (preloadFontPaths) {
 | 
			
		||||
          const basePath = drupalSettings.path.baseUrl;
 | 
			
		||||
          let selectorsExist = true;
 | 
			
		||||
          preloadFontPaths.forEach((path) => {
 | 
			
		||||
            if (!document.head.querySelector(`[href="${basePath + path}"]`)) {
 | 
			
		||||
              selectorsExist = false;
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          return selectorsExist;
 | 
			
		||||
        },
 | 
			
		||||
        [preloadFontPaths],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'Check that <link rel="preload"> tags properly reference font.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      // Check that the CSS @font-face declaration has loaded the font.
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function () {
 | 
			
		||||
          document.fonts.load('16px metropolis');
 | 
			
		||||
          document.fonts.load('16px Lora');
 | 
			
		||||
          return (
 | 
			
		||||
            document.fonts.check('16px metropolis') &&
 | 
			
		||||
            document.fonts.check('16px Lora')
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'Check that the CSS @font-face declaration has loaded the font.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,200 @@
 | 
			
		||||
const mobileNavButtonSelector = 'button.mobile-nav-button';
 | 
			
		||||
const headerNavSelector = '#header-nav';
 | 
			
		||||
const linkSubMenuId = 'primary-menu-item-1';
 | 
			
		||||
const buttonSubMenuId = 'primary-menu-item-12';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sends arbitrary number of tab keys, and then checks that the last focused
 | 
			
		||||
 * element is within the given parent selector.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {object} browser - Nightwatch Browser object
 | 
			
		||||
 * @param {string} parentSelector - Selector to which to test focused element against.
 | 
			
		||||
 * @param {number} tabCount - Amount of tab presses to send to browser
 | 
			
		||||
 * @param {boolean} [tabBackwards] - Hold down the SHIFT key when sending tabs
 | 
			
		||||
 */
 | 
			
		||||
const focusTrapCheck = (browser, parentSelector, tabCount, tabBackwards) => {
 | 
			
		||||
  if (tabBackwards === true) {
 | 
			
		||||
    browser.perform(function () {
 | 
			
		||||
      return this.actions().keyDown(browser.Keys.SHIFT);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  for (let i = 0; i < tabCount; i++) {
 | 
			
		||||
    browser.perform(function () {
 | 
			
		||||
      return this.actions().sendKeys(browser.Keys.TAB).pause(50);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  browser
 | 
			
		||||
    .execute(
 | 
			
		||||
      // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
      function (parentSelector) {
 | 
			
		||||
        // Verify focused element is still within the focus trap.
 | 
			
		||||
        return document.activeElement.matches(parentSelector);
 | 
			
		||||
      },
 | 
			
		||||
      [parentSelector],
 | 
			
		||||
      (result) => {
 | 
			
		||||
        browser.assert.ok(result.value);
 | 
			
		||||
      },
 | 
			
		||||
    )
 | 
			
		||||
    // Release SHIFT key.
 | 
			
		||||
    .perform(function () {
 | 
			
		||||
      return this.actions().keyUp(browser.Keys.SHIFT);
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      .setWindowSize(1000, 800);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify mobile menu and submenu functionality': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .assert.not.visible(headerNavSelector)
 | 
			
		||||
      .click(mobileNavButtonSelector)
 | 
			
		||||
      .waitForElementVisible(headerNavSelector)
 | 
			
		||||
      // Test interactions for normal <a> menu links.
 | 
			
		||||
      .assert.not.visible(`#${linkSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${linkSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'false',
 | 
			
		||||
      )
 | 
			
		||||
      .waitForElementVisible(`[aria-controls="${linkSubMenuId}"]`)
 | 
			
		||||
      .click(`[aria-controls="${linkSubMenuId}"]`)
 | 
			
		||||
      .waitForElementVisible(`#${linkSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${linkSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'true',
 | 
			
		||||
      )
 | 
			
		||||
      // Test interactions for route:<button> menu links.
 | 
			
		||||
      .assert.not.visible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${buttonSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'false',
 | 
			
		||||
      )
 | 
			
		||||
      .click(`[aria-controls="${buttonSubMenuId}"]`)
 | 
			
		||||
      .assert.visible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        `[aria-controls="${buttonSubMenuId}"]`,
 | 
			
		||||
        'aria-expanded',
 | 
			
		||||
        'true',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'Verify mobile menu focus trap': (browser) => {
 | 
			
		||||
    browser.drupalRelativeURL('/').click(mobileNavButtonSelector);
 | 
			
		||||
    focusTrapCheck(
 | 
			
		||||
      browser,
 | 
			
		||||
      `${headerNavSelector} *, ${mobileNavButtonSelector}`,
 | 
			
		||||
      17,
 | 
			
		||||
    );
 | 
			
		||||
    focusTrapCheck(
 | 
			
		||||
      browser,
 | 
			
		||||
      `${headerNavSelector} *, ${mobileNavButtonSelector}`,
 | 
			
		||||
      19,
 | 
			
		||||
      true,
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
  'Verify parent <button> focus on ESC in narrow navigation': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      // Verify functionality on regular link's button.
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .waitForElementVisible('body')
 | 
			
		||||
      .click(mobileNavButtonSelector)
 | 
			
		||||
      .waitForElementVisible(headerNavSelector)
 | 
			
		||||
      .waitForElementVisible(`[aria-controls="${linkSubMenuId}"]`)
 | 
			
		||||
      .click(`[aria-controls="${linkSubMenuId}"]`)
 | 
			
		||||
      .waitForElementVisible(`#${linkSubMenuId}`)
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions().sendKeys(browser.Keys.TAB);
 | 
			
		||||
      })
 | 
			
		||||
      .pause(50)
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (linkSubMenuId) {
 | 
			
		||||
          return document.activeElement.matches(`#${linkSubMenuId} *`);
 | 
			
		||||
        },
 | 
			
		||||
        [linkSubMenuId],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(result.value);
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions().sendKeys(browser.Keys.ESCAPE);
 | 
			
		||||
      })
 | 
			
		||||
      .pause(50)
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (linkSubMenuId) {
 | 
			
		||||
          return document.activeElement.matches(
 | 
			
		||||
            `[aria-controls="${linkSubMenuId}"]`,
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        [linkSubMenuId],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(result.value);
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      // Verify functionality on route:<button> button.
 | 
			
		||||
      .click(`[aria-controls="${buttonSubMenuId}"]`)
 | 
			
		||||
      .waitForElementVisible(`#${buttonSubMenuId}`)
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions().sendKeys(browser.Keys.TAB);
 | 
			
		||||
      })
 | 
			
		||||
      .pause(50)
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (buttonSubMenuId) {
 | 
			
		||||
          return document.activeElement.matches(`#${buttonSubMenuId} *`);
 | 
			
		||||
        },
 | 
			
		||||
        [buttonSubMenuId],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(result.value);
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions().sendKeys(browser.Keys.ESCAPE);
 | 
			
		||||
      })
 | 
			
		||||
      .pause(50)
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (buttonSubMenuId) {
 | 
			
		||||
          return document.activeElement.matches(
 | 
			
		||||
            `[aria-controls="${buttonSubMenuId}"]`,
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        [buttonSubMenuId],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(result.value);
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'Verify clicks on hashes close mobile menu': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .waitForElementVisible('body')
 | 
			
		||||
      .click(mobileNavButtonSelector)
 | 
			
		||||
      .waitForElementVisible(headerNavSelector)
 | 
			
		||||
      .click('[href="#footer"]')
 | 
			
		||||
      .waitForElementNotVisible(headerNavSelector);
 | 
			
		||||
  },
 | 
			
		||||
  'Verify mobile menu works when Big Pipe when authenticated': (browser) => {
 | 
			
		||||
    browser.drupalInstallModule('big_pipe').drupalLoginAsAdmin(() => {
 | 
			
		||||
      browser
 | 
			
		||||
        .drupalRelativeURL('/')
 | 
			
		||||
        .assert.not.visible(headerNavSelector)
 | 
			
		||||
        .click(mobileNavButtonSelector)
 | 
			
		||||
        .waitForElementVisible(headerNavSelector);
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
const tableSelector = '#edit-field-multiple-value-form-field-wrapper table';
 | 
			
		||||
const tableHeaderSelector = '#edit-field-multiple-value-form-field-wrapper th';
 | 
			
		||||
const headerSelector = '#edit-field-multiple-value-form-field-wrapper h4';
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['access site-wide contact form'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'correct classes added to table and header': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(1400, 800)
 | 
			
		||||
      .drupalRelativeURL('/contact/olivero_test_contact_form')
 | 
			
		||||
      .waitForElementVisible(tableSelector, 1000)
 | 
			
		||||
      .assert.hasClass(tableSelector, [
 | 
			
		||||
        'tabledrag-disabled',
 | 
			
		||||
        'js-tabledrag-disabled',
 | 
			
		||||
      ])
 | 
			
		||||
      .assert.hasClass(tableHeaderSelector, 'is-disabled')
 | 
			
		||||
      .assert.hasClass(headerSelector, [
 | 
			
		||||
        'form-item__label',
 | 
			
		||||
        'form-item__label--multiple-value-form',
 | 
			
		||||
        'js-form-required',
 | 
			
		||||
        'form-required',
 | 
			
		||||
      ]);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,112 @@
 | 
			
		||||
const checkboxSelector = '#edit-form-checkboxes-title-attribute';
 | 
			
		||||
 | 
			
		||||
const inputTypes = [
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-textfield-test-title-and-required',
 | 
			
		||||
    type: 'text',
 | 
			
		||||
    api: 'textfield',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-email-title-no-xss',
 | 
			
		||||
    type: 'email',
 | 
			
		||||
    api: 'email',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-tel-title-no-xss',
 | 
			
		||||
    type: 'tel',
 | 
			
		||||
    api: 'tel',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-number-title-no-xss',
 | 
			
		||||
    type: 'number',
 | 
			
		||||
    api: 'number',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-search-title-no-xss',
 | 
			
		||||
    type: 'search',
 | 
			
		||||
    api: 'search',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-password-title-no-xss',
 | 
			
		||||
    type: 'password',
 | 
			
		||||
    api: 'password',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-date-title-no-xss',
 | 
			
		||||
    type: 'date',
 | 
			
		||||
    api: 'date',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-datetime-title-no-xss-time',
 | 
			
		||||
    type: 'time',
 | 
			
		||||
    api: 'date',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-file-title-no-xss',
 | 
			
		||||
    type: 'file',
 | 
			
		||||
    api: 'file',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-color-title-no-xss',
 | 
			
		||||
    type: 'color',
 | 
			
		||||
    api: 'color',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-url-title-no-xss',
 | 
			
		||||
    type: 'url',
 | 
			
		||||
    api: 'url',
 | 
			
		||||
  },
 | 
			
		||||
  // TODO - Cover datetime-local, month, week - no test form input examples are easily available
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const booleanInputTypes = [
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-checkboxes-test-first-checkbox',
 | 
			
		||||
    type: 'checkbox',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    selector: '#edit-form-radios-title-attribute-first-radio',
 | 
			
		||||
    type: 'radio',
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile:
 | 
			
		||||
        'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
      installProfile: 'minimal',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Confirm that title attribute exists if set to display': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(1400, 800)
 | 
			
		||||
      .drupalRelativeURL('/form_test/form-labels')
 | 
			
		||||
      .waitForElementVisible(checkboxSelector, 1000)
 | 
			
		||||
      .assert.attributeEquals(
 | 
			
		||||
        checkboxSelector,
 | 
			
		||||
        'title',
 | 
			
		||||
        'Checkboxes test (Required)',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'Check form element classes by type': (browser) => {
 | 
			
		||||
    browser.drupalRelativeURL('/form_test/form-labels');
 | 
			
		||||
    inputTypes.forEach((inputType) => {
 | 
			
		||||
      browser.assert.hasClass(inputType.selector, [
 | 
			
		||||
        'form-element',
 | 
			
		||||
        `form-element--type-${inputType.type}`,
 | 
			
		||||
        `form-element--api-${inputType.api}`,
 | 
			
		||||
      ]);
 | 
			
		||||
    });
 | 
			
		||||
    booleanInputTypes.forEach((booleanInputType) => {
 | 
			
		||||
      browser.assert.hasClass(booleanInputType.selector, [
 | 
			
		||||
        'form-boolean',
 | 
			
		||||
        `form-boolean--type-${booleanInputType.type}`,
 | 
			
		||||
      ]);
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
const primaryTabsWrapper = '[data-drupal-nav-primary-tabs]';
 | 
			
		||||
const activeTab = '.tabs__tab.is-active';
 | 
			
		||||
const inactiveTab = '.tabs__tab:not(.is-active)';
 | 
			
		||||
const mobileToggle = `${activeTab} .tabs__trigger`;
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['administer nodes'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' });
 | 
			
		||||
    browser.window.setSize(1600, 800);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify desktop primary tab display': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node/1')
 | 
			
		||||
      .waitForElementVisible(primaryTabsWrapper)
 | 
			
		||||
      .assert.visible(activeTab)
 | 
			
		||||
      .assert.visible(inactiveTab)
 | 
			
		||||
      .assert.not.visible(mobileToggle);
 | 
			
		||||
  },
 | 
			
		||||
  'Verify mobile tab display and click functionality': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(699, 800)
 | 
			
		||||
      .drupalRelativeURL('/node/1')
 | 
			
		||||
      .waitForElementVisible(primaryTabsWrapper)
 | 
			
		||||
      .assert.visible(activeTab)
 | 
			
		||||
      .assert.not.visible(inactiveTab)
 | 
			
		||||
      .assert.visible(mobileToggle)
 | 
			
		||||
      .assert.attributeEquals(mobileToggle, 'aria-expanded', 'false')
 | 
			
		||||
      .click(mobileToggle)
 | 
			
		||||
      .waitForElementVisible(inactiveTab)
 | 
			
		||||
      .assert.attributeEquals(mobileToggle, 'aria-expanded', 'true')
 | 
			
		||||
      .click(mobileToggle)
 | 
			
		||||
      .waitForElementNotVisible(inactiveTab)
 | 
			
		||||
      .assert.attributeEquals(mobileToggle, 'aria-expanded', 'false');
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,57 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLoginAsAdmin(() => {
 | 
			
		||||
        browser
 | 
			
		||||
          .drupalRelativeURL('/admin/structure/block')
 | 
			
		||||
 | 
			
		||||
          // Disable narrow search form block.
 | 
			
		||||
          .click(
 | 
			
		||||
            '[data-drupal-selector="edit-blocks-olivero-search-form-narrow-operations"] .dropbutton-toggle button',
 | 
			
		||||
          )
 | 
			
		||||
          .click('[href*="olivero_search_form_narrow/disable"]')
 | 
			
		||||
 | 
			
		||||
          // Disable main menu block.
 | 
			
		||||
          .click(
 | 
			
		||||
            '[data-drupal-selector="edit-blocks-olivero-main-menu-operations"] .dropbutton-toggle button',
 | 
			
		||||
          )
 | 
			
		||||
          .click('[href*="olivero_main_menu/disable"]')
 | 
			
		||||
 | 
			
		||||
          // Disable wide search form block.
 | 
			
		||||
          .click(
 | 
			
		||||
            '[data-drupal-selector="edit-blocks-olivero-search-form-wide-operations"] .dropbutton-toggle button',
 | 
			
		||||
          )
 | 
			
		||||
          .click('[href*="olivero_search_form_wide/disable"]')
 | 
			
		||||
 | 
			
		||||
          // Disable user account menu block.
 | 
			
		||||
          .click(
 | 
			
		||||
            '[data-drupal-selector="edit-blocks-olivero-account-menu-operations"] .dropbutton-toggle button',
 | 
			
		||||
          )
 | 
			
		||||
          .click('[href*="olivero_account_menu/disable"]');
 | 
			
		||||
      });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Verify no console errors': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible('body')
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function () {
 | 
			
		||||
          return Drupal.errorLog.length === 0;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(result.value, 'Verify no console errors exist.');
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,129 @@
 | 
			
		||||
const mobileNavButtonSelector = 'button.mobile-nav-button';
 | 
			
		||||
const headerNavSelector = '#header-nav';
 | 
			
		||||
const searchButtonSelector = 'button.block-search-wide__button';
 | 
			
		||||
const searchFormSelector = '.search-form.search-block-form';
 | 
			
		||||
const searchWideSelector = '.block-search-wide__wrapper';
 | 
			
		||||
const searchWideInputSelector = '#edit-keys--2';
 | 
			
		||||
const searchNarrowSelector = '.block-search-narrow';
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall({
 | 
			
		||||
        setupFile:
 | 
			
		||||
          'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
        installProfile: 'minimal',
 | 
			
		||||
      })
 | 
			
		||||
      // Create user that can search.
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['search content', 'use advanced search'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'search wide form is accessible and altered': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(1400, 800)
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible(searchButtonSelector)
 | 
			
		||||
      .assert.attributeEquals(searchButtonSelector, 'aria-expanded', 'false')
 | 
			
		||||
      .click(searchButtonSelector)
 | 
			
		||||
      .waitForElementVisible(searchWideInputSelector)
 | 
			
		||||
      .assert.attributeEquals(searchButtonSelector, 'aria-expanded', 'true')
 | 
			
		||||
      .assert.attributeContains(
 | 
			
		||||
        searchWideInputSelector,
 | 
			
		||||
        'placeholder',
 | 
			
		||||
        'Search by keyword or phrase.',
 | 
			
		||||
      )
 | 
			
		||||
      .assert.attributeContains(
 | 
			
		||||
        searchWideInputSelector,
 | 
			
		||||
        'title',
 | 
			
		||||
        'Enter the terms you wish to search for.',
 | 
			
		||||
      )
 | 
			
		||||
      .assert.elementPresent('button.search-form__submit')
 | 
			
		||||
      // Assert wide search form closes when element moves to body.
 | 
			
		||||
      .click('body')
 | 
			
		||||
      .waitForElementNotVisible(searchWideSelector)
 | 
			
		||||
      .assert.attributeEquals(searchButtonSelector, 'aria-expanded', 'false');
 | 
			
		||||
  },
 | 
			
		||||
  'Test focus management': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible(searchButtonSelector)
 | 
			
		||||
      .click(searchButtonSelector)
 | 
			
		||||
      .waitForElementVisible(searchWideInputSelector)
 | 
			
		||||
      .pause(400) // Wait for transitionend event to fire.
 | 
			
		||||
      // Assert that focus is moved to wide search text input.
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (searchWideInputSelector) {
 | 
			
		||||
          return document.activeElement.matches(searchWideInputSelector);
 | 
			
		||||
        },
 | 
			
		||||
        [searchWideInputSelector],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'Assert that focus moves to wide search form on open.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      // Assert that search form is still visible when focus is on disclosure button.
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions()
 | 
			
		||||
          .keyDown(browser.Keys.SHIFT)
 | 
			
		||||
          .sendKeys(browser.Keys.TAB);
 | 
			
		||||
      })
 | 
			
		||||
      .pause(50)
 | 
			
		||||
      .isVisible(searchWideSelector)
 | 
			
		||||
      // Assert that search form is NOT visible when focus moves back to menu item.
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions().sendKeys(browser.Keys.TAB);
 | 
			
		||||
      })
 | 
			
		||||
      .pause(50)
 | 
			
		||||
      .waitForElementNotVisible(searchWideSelector)
 | 
			
		||||
      // Release SHIFT key.
 | 
			
		||||
      .perform(function () {
 | 
			
		||||
        return this.actions().keyUp(browser.Keys.SHIFT);
 | 
			
		||||
      });
 | 
			
		||||
  },
 | 
			
		||||
  'search narrow form is accessible': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(1000, 800)
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .click(mobileNavButtonSelector)
 | 
			
		||||
      .waitForElementVisible(headerNavSelector)
 | 
			
		||||
      .waitForElementVisible(`${searchNarrowSelector} ${searchFormSelector}`);
 | 
			
		||||
  },
 | 
			
		||||
  'submit button styled as primary on forms with <= 2 actions': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(1400, 800)
 | 
			
		||||
      .drupalRelativeURL('/form-test/object-controller-builder')
 | 
			
		||||
      .assert.elementPresent(
 | 
			
		||||
        '#edit-actions input[type=submit].button--primary',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
  'search page is altered': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .setWindowSize(1400, 800)
 | 
			
		||||
      .drupalRelativeURL('/search')
 | 
			
		||||
      .assert.attributeContains(
 | 
			
		||||
        '.search-form input[name=keys]',
 | 
			
		||||
        'placeholder',
 | 
			
		||||
        'Search by keyword or phrase.',
 | 
			
		||||
      )
 | 
			
		||||
      .assert.attributeContains(
 | 
			
		||||
        '.search-form input[name=keys]',
 | 
			
		||||
        'title',
 | 
			
		||||
        'Enter the terms you wish to search for.',
 | 
			
		||||
      )
 | 
			
		||||
      .assert.elementPresent('#edit-basic input[type=submit].button--primary')
 | 
			
		||||
      .assert.elementPresent(
 | 
			
		||||
        '#edit-advanced input[type=submit].button--primary',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
const buttonSelector = 'button.sticky-header-toggle';
 | 
			
		||||
const mainMenuSelector = '#block-olivero-main-menu';
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'olivero'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile:
 | 
			
		||||
        'core/tests/Drupal/TestSite/TestSiteOliveroInstallTestScript.php',
 | 
			
		||||
      installProfile: 'minimal',
 | 
			
		||||
    });
 | 
			
		||||
    browser.window.setSize(1400, 800);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'On scroll, menu collapses to burger 🍔 menu': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .assert.not.visible(buttonSelector)
 | 
			
		||||
      .assert.attributeEquals(buttonSelector, 'aria-checked', 'false')
 | 
			
		||||
      .click('.block-system-powered-by-block .drupal-logo')
 | 
			
		||||
      .assert.visible(buttonSelector)
 | 
			
		||||
      .assert.not.visible('#site-header__inner')
 | 
			
		||||
      .assert.not.visible(mainMenuSelector)
 | 
			
		||||
      .click(buttonSelector)
 | 
			
		||||
      .assert.visible(mainMenuSelector)
 | 
			
		||||
      .assert.attributeEquals(buttonSelector, 'aria-checked', 'true')
 | 
			
		||||
 | 
			
		||||
      // Sticky header should remain open after page reload in open state.
 | 
			
		||||
      .drupalRelativeURL('/node')
 | 
			
		||||
      .assert.visible(mainMenuSelector)
 | 
			
		||||
      .assert.attributeEquals(buttonSelector, 'aria-checked', 'true');
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										84
									
								
								web/core/tests/Drupal/Nightwatch/Tests/a11yTestAdmin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								web/core/tests/Drupal/Nightwatch/Tests/a11yTestAdmin.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
const argv = require('minimist')(process.argv.slice(2));
 | 
			
		||||
 | 
			
		||||
const adminTest = {
 | 
			
		||||
  '@tags': ['core', 'a11y', 'a11y:admin'],
 | 
			
		||||
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({ installProfile: 'nightwatch_a11y_testing' });
 | 
			
		||||
    // If an admin theme other than Claro is being used for testing, install it.
 | 
			
		||||
    if (argv.adminTheme && argv.adminTheme !== browser.globals.adminTheme) {
 | 
			
		||||
      browser.drupalEnableTheme(argv.adminTheme, true);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
const testCases = [
 | 
			
		||||
  { name: 'User Edit', path: '/user/1/edit' },
 | 
			
		||||
  {
 | 
			
		||||
    name: 'Create Article',
 | 
			
		||||
    path: '/node/add/article?destination=/admin/content',
 | 
			
		||||
  },
 | 
			
		||||
  { name: 'Create Page', path: '/node/add/page?destination=/admin/content' },
 | 
			
		||||
  { name: 'Content Page', path: '/admin/content' },
 | 
			
		||||
  { name: 'Structure Page', path: '/admin/structure' },
 | 
			
		||||
  { name: 'Add content type', path: '/admin/structure/types/add' },
 | 
			
		||||
  { name: 'Add vocabulary', path: '/admin/structure/taxonomy/add' },
 | 
			
		||||
  {
 | 
			
		||||
    // Tests long breadcrumb for https://drupal.org/i/3223147.
 | 
			
		||||
    name: 'Manage text format, mobile',
 | 
			
		||||
    path: '/admin/config/content/formats/manage/restricted_html',
 | 
			
		||||
    windowSize: {
 | 
			
		||||
      // Dimensions used by Lighthouse for mobile.
 | 
			
		||||
      width: 415,
 | 
			
		||||
      height: 823,
 | 
			
		||||
    },
 | 
			
		||||
    options: {
 | 
			
		||||
      runOnly: {
 | 
			
		||||
        type: 'tag',
 | 
			
		||||
        values: [
 | 
			
		||||
          'wcag2a',
 | 
			
		||||
          'wcag2aa',
 | 
			
		||||
          'wcag21a',
 | 
			
		||||
          'wcag21aa',
 | 
			
		||||
          'best-practice',
 | 
			
		||||
          'wcag22a',
 | 
			
		||||
          'wcag22aa',
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  // @todo remove the skipped rules below in https://drupal.org/i/3318394.
 | 
			
		||||
  {
 | 
			
		||||
    name: 'Structure | Block',
 | 
			
		||||
    path: '/admin/structure/block',
 | 
			
		||||
    options: {
 | 
			
		||||
      rules: {
 | 
			
		||||
        'color-contrast': { enabled: false },
 | 
			
		||||
        'duplicate-id-active': { enabled: false },
 | 
			
		||||
        region: { enabled: false },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
testCases.forEach((testCase) => {
 | 
			
		||||
  adminTest[`Accessibility - Admin Theme: ${testCase.name}`] = (browser) => {
 | 
			
		||||
    if (testCase.windowSize) {
 | 
			
		||||
      browser.setWindowSize(
 | 
			
		||||
        testCase.windowSize.width,
 | 
			
		||||
        testCase.windowSize.height,
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    browser.drupalLoginAsAdmin(() => {
 | 
			
		||||
      browser
 | 
			
		||||
        .drupalRelativeURL(testCase.path)
 | 
			
		||||
        .axeInject()
 | 
			
		||||
        .axeRun('body', testCase.options || {});
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = adminTest;
 | 
			
		||||
							
								
								
									
										67
									
								
								web/core/tests/Drupal/Nightwatch/Tests/a11yTestDefault.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								web/core/tests/Drupal/Nightwatch/Tests/a11yTestDefault.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
			
		||||
const argv = require('minimist')(process.argv.slice(2));
 | 
			
		||||
 | 
			
		||||
const a11yThemeTest = {
 | 
			
		||||
  '@tags': ['core', 'a11y', 'a11y:default'],
 | 
			
		||||
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({ installProfile: 'nightwatch_a11y_testing' });
 | 
			
		||||
    // If the default theme is set to something other than Olivero, install it.
 | 
			
		||||
    if (
 | 
			
		||||
      argv.defaultTheme &&
 | 
			
		||||
      argv.defaultTheme !== browser.globals.defaultTheme
 | 
			
		||||
    ) {
 | 
			
		||||
      browser.drupalEnableTheme(argv.defaultTheme);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const testCases = [
 | 
			
		||||
  {
 | 
			
		||||
    name: 'Homepage',
 | 
			
		||||
    path: '/',
 | 
			
		||||
    // @todo remove the disabled 'region' rule in https://drupal.org/i/3318396.
 | 
			
		||||
    options: {
 | 
			
		||||
      rules: {
 | 
			
		||||
        region: { enabled: false },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    name: 'Login',
 | 
			
		||||
    path: '/user/login',
 | 
			
		||||
    // @todo remove the disabled 'region' rule in https://drupal.org/i/3318396.
 | 
			
		||||
    options: {
 | 
			
		||||
      rules: {
 | 
			
		||||
        region: { enabled: false },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  // @todo remove the heading and duplicate id rules below in
 | 
			
		||||
  //   https://drupal.org/i/3318398.
 | 
			
		||||
  {
 | 
			
		||||
    name: 'Search',
 | 
			
		||||
    path: '/search/node',
 | 
			
		||||
    options: {
 | 
			
		||||
      rules: {
 | 
			
		||||
        'heading-order': { enabled: false },
 | 
			
		||||
        'duplicate-id-aria': { enabled: false },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
testCases.forEach((testCase) => {
 | 
			
		||||
  a11yThemeTest[`Accessibility - Default Theme: ${testCase.name}`] = (
 | 
			
		||||
    browser,
 | 
			
		||||
  ) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL(testCase.path)
 | 
			
		||||
      .axeInject()
 | 
			
		||||
      .axeRun('body', testCase.options || {});
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = a11yThemeTest;
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'ajax'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalInstallModule('ajax_test', true);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test Execution Order': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/ajax-test/promise-form')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .click('[data-drupal-selector="edit-test-execution-order-button"]')
 | 
			
		||||
      .waitForElementVisible('#ajax_test_form_promise_wrapper', 1000)
 | 
			
		||||
      .assert.textContains(
 | 
			
		||||
        '#ajax_test_form_promise_wrapper',
 | 
			
		||||
        '12345',
 | 
			
		||||
        'Ajax commands execution order confirmed',
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,67 @@
 | 
			
		||||
// cspell:ignore is-autocompleting
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalInstall()
 | 
			
		||||
      .drupalInstallModule('form_test', true)
 | 
			
		||||
      .drupalLoginAsAdmin(() => {
 | 
			
		||||
        browser
 | 
			
		||||
          .drupalRelativeURL('/admin/appearance')
 | 
			
		||||
          .click('[title="Install Claro as default theme"]')
 | 
			
		||||
          .waitForElementVisible('.system-themes-list', 10000); // Confirm installation.
 | 
			
		||||
      });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Test Claro autocomplete': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['access autocomplete test'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' })
 | 
			
		||||
      .drupalRelativeURL('/form-test/autocomplete')
 | 
			
		||||
      .waitForElementVisible('body', 1000);
 | 
			
		||||
 | 
			
		||||
    // Tests that entering a character from the
 | 
			
		||||
    // data-autocomplete-first-character-denylist doesn't start the
 | 
			
		||||
    // autocomplete process.
 | 
			
		||||
    browser
 | 
			
		||||
      .setValue('[name="autocomplete_4"]', '/')
 | 
			
		||||
      .pause(1000)
 | 
			
		||||
      .waitForElementNotPresent('.is-autocompleting');
 | 
			
		||||
 | 
			
		||||
    // Tests both the autocomplete-message nor the autocomplete dropdown are
 | 
			
		||||
    // present when nothing has been entered in autocomplete-3.
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line no-unused-expressions
 | 
			
		||||
    browser.expect.element(
 | 
			
		||||
      '.js-form-item-autocomplete-3 [data-drupal-selector="autocomplete-message"]',
 | 
			
		||||
    ).to.not.visible;
 | 
			
		||||
    // eslint-disable-next-line no-unused-expressions
 | 
			
		||||
    browser.expect.element('#ui-id-3.ui-autocomplete').to.not.visible;
 | 
			
		||||
 | 
			
		||||
    // Tests that upon entering some text in autocomplete-3, first the
 | 
			
		||||
    // autocomplete-message appears and then the autocomplete dropdown with a
 | 
			
		||||
    // result. At that point the autocomplete-message should be invisible again.
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line no-unused-expressions
 | 
			
		||||
    browser
 | 
			
		||||
      .setValue('[name="autocomplete_3"]', '123')
 | 
			
		||||
      .waitForElementVisible(
 | 
			
		||||
        '.js-form-item-autocomplete-3 [data-drupal-selector="autocomplete-message"]',
 | 
			
		||||
      )
 | 
			
		||||
      .waitForElementVisible('#ui-id-3.ui-autocomplete')
 | 
			
		||||
      .expect.element(
 | 
			
		||||
        '.js-form-item-autocomplete-3 [data-drupal-selector="autocomplete-message"]',
 | 
			
		||||
      ).to.not.visible;
 | 
			
		||||
 | 
			
		||||
    browser.drupalLogAndEnd({ onlyOnError: false });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										123
									
								
								web/core/tests/Drupal/Nightwatch/Tests/htmx/htmxTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								web/core/tests/Drupal/Nightwatch/Tests/htmx/htmxTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
			
		||||
// The javascript that creates dropbuttons is not present on the /page at
 | 
			
		||||
// initial load.  If the once data property is added then the JS was loaded
 | 
			
		||||
// and triggered on the inserted content.
 | 
			
		||||
// @see \Drupal\test_htmx\Controller\HtmxTestAttachmentsController
 | 
			
		||||
// @see core/modules/system/tests/modules/test_htmx/js/reveal-merged-settings.js
 | 
			
		||||
 | 
			
		||||
const scriptSelector = 'script[src*="test_htmx/js/behavior.js"]';
 | 
			
		||||
const cssSelector = 'link[rel="stylesheet"][href*="test_htmx/css/style.css"]';
 | 
			
		||||
const elementSelector = '.ajax-content';
 | 
			
		||||
const elementInitSelector = `${elementSelector}[data-once="htmx-init"]`;
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core', 'htmx'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile: 'core/tests/Drupal/TestSite/HtmxAssetLoadTestSetup.php',
 | 
			
		||||
      installProfile: 'minimal',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  afterEach(browser) {
 | 
			
		||||
    browser.drupalLogAndEnd({ onlyOnError: true });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Asset Load': (browser) => {
 | 
			
		||||
    // Load the route htmx will use for the request on click and confirm the
 | 
			
		||||
    // markup we will be looking for is present in the source markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/replace')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.elementPresent(elementInitSelector);
 | 
			
		||||
    // Now load the page with the htmx enhanced button and verify the absence
 | 
			
		||||
    // of the markup to be inserted. Click the button
 | 
			
		||||
    // and check for inserted javascript and markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/page')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.not.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.not.elementPresent(cssSelector)
 | 
			
		||||
      .waitForElementVisible('[name="replace"]', 1000)
 | 
			
		||||
      .click('[name="replace"]')
 | 
			
		||||
      .waitForElementVisible(elementSelector, 1100)
 | 
			
		||||
      .waitForElementVisible(elementInitSelector, 1100)
 | 
			
		||||
      .assert.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.elementPresent(cssSelector);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Swap Before': (browser) => {
 | 
			
		||||
    // Load the route htmx will use for the request on click and confirm the
 | 
			
		||||
    // markup we will be looking for is present in the source markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/replace')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.elementPresent(elementInitSelector);
 | 
			
		||||
    // Now load the page with the htmx enhanced button and verify the absence
 | 
			
		||||
    // of the markup to be inserted. Click the button
 | 
			
		||||
    // and check for inserted javascript and markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/before')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.not.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.not.elementPresent(cssSelector)
 | 
			
		||||
      .waitForElementVisible('[name="replace"]', 1000)
 | 
			
		||||
      .click('[name="replace"]')
 | 
			
		||||
      .waitForElementVisible(elementSelector, 1100)
 | 
			
		||||
      .waitForElementVisible(elementInitSelector, 1100)
 | 
			
		||||
      .assert.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.elementPresent(cssSelector);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Swap After': (browser) => {
 | 
			
		||||
    // Load the route htmx will use for the request on click and confirm the
 | 
			
		||||
    // markup we will be looking for is present in the source markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/replace')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.elementPresent(elementInitSelector);
 | 
			
		||||
    // Now load the page with the htmx enhanced button and verify the absence
 | 
			
		||||
    // of the markup to be inserted. Click the button
 | 
			
		||||
    // and check for inserted javascript and markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/after')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.not.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.not.elementPresent(cssSelector)
 | 
			
		||||
      .waitForElementVisible('[name="replace"]', 1000)
 | 
			
		||||
      .click('[name="replace"]')
 | 
			
		||||
      .waitForElementVisible(elementSelector, 1100)
 | 
			
		||||
      .waitForElementVisible(elementInitSelector, 1100)
 | 
			
		||||
      .assert.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.elementPresent(cssSelector);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Ajax Load HTMX Element': (browser) => {
 | 
			
		||||
    // Load the route htmx will use for the request on click and confirm the
 | 
			
		||||
    // markup we will be looking for is present in the source markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/replace')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.elementPresent(scriptSelector);
 | 
			
		||||
    // Now load the page with the ajax powered button. Click the button
 | 
			
		||||
    // to insert an htmx enhanced button and verify the absence
 | 
			
		||||
    // of the markup to be inserted. Click the button
 | 
			
		||||
    // and check for inserted javascript and markup.
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/htmx-test-attachments/ajax')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.not.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.not.elementPresent(cssSelector)
 | 
			
		||||
      .waitForElementVisible('[data-drupal-selector="edit-ajax-button"]', 1000)
 | 
			
		||||
      .pause(1000)
 | 
			
		||||
      .click('[data-drupal-selector="edit-ajax-button"]')
 | 
			
		||||
      .waitForElementVisible('[name="replace"]', 1000)
 | 
			
		||||
      .pause(1000)
 | 
			
		||||
      .click('[name="replace"]')
 | 
			
		||||
      .waitForElementVisible(elementSelector, 1100)
 | 
			
		||||
      .waitForElementVisible(elementInitSelector, 1100)
 | 
			
		||||
      .assert.elementPresent(scriptSelector)
 | 
			
		||||
      .assert.elementPresent(cssSelector);
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										19
									
								
								web/core/tests/Drupal/Nightwatch/Tests/installProfileTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/core/tests/Drupal/Nightwatch/Tests/installProfileTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile: 'core/tests/Drupal/TestSite/TestSiteInstallTestScript.php',
 | 
			
		||||
      installProfile: 'demo_umami',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test umami profile': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/test-page')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.elementPresent('#block-umami-branding')
 | 
			
		||||
      .drupalLogAndEnd({ onlyOnError: false });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										2388
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jQueryUIPositionShimTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2388
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jQueryUIPositionShimTest.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										22
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jsDeprecationTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jsDeprecationTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalInstallModule('js_deprecation_test');
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test JavaScript deprecations': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/js_deprecation_test')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.textContains('h1', 'JsDeprecationTest')
 | 
			
		||||
      .assert.deprecationErrorExists(
 | 
			
		||||
        'This function is deprecated for testing purposes.',
 | 
			
		||||
      )
 | 
			
		||||
      .assert.deprecationErrorExists(
 | 
			
		||||
        'This property is deprecated for testing purposes.',
 | 
			
		||||
      )
 | 
			
		||||
      .drupalLogAndEnd({ onlyOnError: false });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										126
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jsDisplace.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jsDisplace.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
const testValues = {
 | 
			
		||||
  top: 200,
 | 
			
		||||
  right: 110,
 | 
			
		||||
  bottom: 145,
 | 
			
		||||
  left: 310,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const testElements = `
 | 
			
		||||
  <div
 | 
			
		||||
    data-offset-top
 | 
			
		||||
    style="
 | 
			
		||||
      background-color: red;
 | 
			
		||||
      height: 110px;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      right: 0;
 | 
			
		||||
      top: 90px;
 | 
			
		||||
      width: 100%;"
 | 
			
		||||
  ></div>
 | 
			
		||||
 | 
			
		||||
  <div
 | 
			
		||||
    data-offset-right
 | 
			
		||||
    style="
 | 
			
		||||
      background-color: blue;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      right: 10px;
 | 
			
		||||
      top: 0;
 | 
			
		||||
      width: 100px;"
 | 
			
		||||
  ></div>
 | 
			
		||||
 | 
			
		||||
  <div
 | 
			
		||||
    data-offset-bottom
 | 
			
		||||
    style="
 | 
			
		||||
      background-color: yellow;
 | 
			
		||||
      bottom: 45px;
 | 
			
		||||
      height: 100px;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      right: 0;
 | 
			
		||||
      width: 100%;"
 | 
			
		||||
  ></div>
 | 
			
		||||
 | 
			
		||||
  <div
 | 
			
		||||
    data-offset-left
 | 
			
		||||
    style="
 | 
			
		||||
      background-color: orange;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      left: 10px;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      top: 0;
 | 
			
		||||
      width: 300px;"
 | 
			
		||||
  ></div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalInstallModule('js_displace');
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test Drupal.displace() JavaScript API': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/')
 | 
			
		||||
      .waitForElementVisible('body')
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (testValues, testElements) {
 | 
			
		||||
          const testElementsContainer = document.createElement('div');
 | 
			
		||||
 | 
			
		||||
          testElementsContainer.innerHTML = testElements;
 | 
			
		||||
          document.body.append(testElementsContainer);
 | 
			
		||||
 | 
			
		||||
          const displaceOutput = Drupal.displace();
 | 
			
		||||
          return (
 | 
			
		||||
            displaceOutput.top === testValues.top &&
 | 
			
		||||
            displaceOutput.right === testValues.right &&
 | 
			
		||||
            displaceOutput.bottom === testValues.bottom &&
 | 
			
		||||
            displaceOutput.left === testValues.left
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        [testValues, testElements],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'Drupal.displace() JS returns proper offsets for all edges.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (testValues) {
 | 
			
		||||
          const rootStyles = getComputedStyle(document.documentElement);
 | 
			
		||||
          const topOffsetStyle = rootStyles.getPropertyValue(
 | 
			
		||||
            '--drupal-displace-offset-top',
 | 
			
		||||
          );
 | 
			
		||||
          const rightOffsetStyle = rootStyles.getPropertyValue(
 | 
			
		||||
            '--drupal-displace-offset-right',
 | 
			
		||||
          );
 | 
			
		||||
          const bottomOffsetStyle = rootStyles.getPropertyValue(
 | 
			
		||||
            '--drupal-displace-offset-bottom',
 | 
			
		||||
          );
 | 
			
		||||
          const leftOffsetStyle = rootStyles.getPropertyValue(
 | 
			
		||||
            '--drupal-displace-offset-left',
 | 
			
		||||
          );
 | 
			
		||||
          return (
 | 
			
		||||
            topOffsetStyle === `${testValues.top}px` &&
 | 
			
		||||
            rightOffsetStyle === `${testValues.right}px` &&
 | 
			
		||||
            bottomOffsetStyle === `${testValues.bottom}px` &&
 | 
			
		||||
            leftOffsetStyle === `${testValues.left}px`
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        [testValues],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.ok(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'Drupal.displace() properly sets CSS variables.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										125
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jsOnceTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								web/core/tests/Drupal/Nightwatch/Tests/jsOnceTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalInstallModule('js_once_test');
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test simple once call': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/js_once_test')
 | 
			
		||||
      .waitForElementVisible('[data-drupal-item]', 1000)
 | 
			
		||||
      // prettier-ignore
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once('js_once_test', '[data-drupal-item]');
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            5,
 | 
			
		||||
            '5 items returned and "once-d"',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      // Check that follow-up calls to once return an empty array.
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once('js_once_test', '[data-drupal-item]');
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            0,
 | 
			
		||||
            '0 items returned',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once(
 | 
			
		||||
            'js_once_test_extra',
 | 
			
		||||
            '[data-drupal-item="1"],[data-drupal-item="2"]',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            2,
 | 
			
		||||
            '2 items returned and "once-d"',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once(
 | 
			
		||||
            'js_once_test_extra',
 | 
			
		||||
            '[data-drupal-item="1"],[data-drupal-item="2"]',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            0,
 | 
			
		||||
            '0 items returned',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once.remove('js_once_test', '[data-drupal-item]');
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            5,
 | 
			
		||||
            '5 items returned and "de-once-d"',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once.remove('js_once_test', '[data-drupal-item]');
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            0,
 | 
			
		||||
            '0 items returned',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once.remove(
 | 
			
		||||
            'js_once_test_extra',
 | 
			
		||||
            '[data-drupal-item="1"],[data-drupal-item="2"]',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            2,
 | 
			
		||||
            '2 items returned and "de-once-d"',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .execute(
 | 
			
		||||
        function () {
 | 
			
		||||
          return once.remove(
 | 
			
		||||
            'js_once_test_extra',
 | 
			
		||||
            '[data-drupal-item="1"],[data-drupal-item="2"]',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.strictEqual(
 | 
			
		||||
            result.value.length,
 | 
			
		||||
            0,
 | 
			
		||||
            '0 items returned',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .drupalLogAndEnd({ onlyOnError: false });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										19
									
								
								web/core/tests/Drupal/Nightwatch/Tests/langcodeTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/core/tests/Drupal/Nightwatch/Tests/langcodeTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall({
 | 
			
		||||
      setupFile:
 | 
			
		||||
        'core/tests/Drupal/TestSite/TestSiteMultilingualInstallTestScript.php',
 | 
			
		||||
      langcode: 'fr',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test page with langcode': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/test-page')
 | 
			
		||||
      .assert.attributeEquals('html', 'lang', 'fr')
 | 
			
		||||
      .drupalLogAndEnd({ onlyOnError: false });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										24
									
								
								web/core/tests/Drupal/Nightwatch/Tests/loginTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								web/core/tests/Drupal/Nightwatch/Tests/loginTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall();
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  'Test login': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalCreateUser({
 | 
			
		||||
        name: 'user',
 | 
			
		||||
        password: '123',
 | 
			
		||||
        permissions: ['access site reports', 'administer site configuration'],
 | 
			
		||||
      })
 | 
			
		||||
      .drupalLogin({ name: 'user', password: '123' })
 | 
			
		||||
      .drupalRelativeURL('/admin/reports')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .assert.textContains('h1', 'Reports')
 | 
			
		||||
      .assert.noDeprecationErrors();
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,262 @@
 | 
			
		||||
// cSpell:disable
 | 
			
		||||
const MachineNameTestArray = [
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Bob',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'bob',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Äwesome',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'awesome',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'B?!"@\\/-ob@e',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'b_ob_e',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Bob@e\\0',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9_.~@]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'bob@e_0',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Bobby',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'bobby',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ǍǎǏ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'aai',
 | 
			
		||||
  },
 | 
			
		||||
  // The expected machine name are modified because we don't have
 | 
			
		||||
  // the removeDiacritics() function present in PhpTranliteration.php.
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'aaaaaaaeceeeeiiii',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ÐÑÒÓÔÕÖרÙÚÛÜÝÞß',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'dnoooooxouuuuuthss',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'àáâãäåæçèéêëìíîï',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'aaaaaaaeceeeeiiii',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ðñòóôõö÷øùúûüýþÿ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'dnooooo_ouuuuythy',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ĀāĂ㥹ĆćĈĉĊċČčĎď',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'aaaaaaccccccccdd',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ĐđĒēĔĕĖėĘęĚěĜĝĞğ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'ddeeeeeeeeeegggg',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ĠġĢģĤĥĦħĨĩĪīĬĭĮį',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'gggghhhhiiiiiiii',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'İıIJijĴĵĶķĸĹĺĻļĽľĿ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'iiijijjjkkklllllll',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ŀŁłŃńŅņŇňʼnŊŋŌōŎŏ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'lllnnnnnn_nngngoooo',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ŐőŒœŔŕŖŗŘřŚśŜŝŞş',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'oooeoerrrrrrssssss',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ŠšŢţŤťŦŧŨũŪūŬŭŮů',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'ssttttttuuuuuuuu',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ŰűŲųŴŵŶŷŸŹźŻżŽž',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'uuuuwwyyyzzzzzz',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'ioouuuuuuuuuu_aa',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'aaaeaeggggkkoooozhzh',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'jdzddzgghvwnnaaaeaeoo',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'aaaaeeeeiiiioooo',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'rrrruuuussttyyhh',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'ndououzzaaeeoooooo',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'ooyylntjdbqpacclts',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'ɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏ',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'z_buveejjqqrryy',
 | 
			
		||||
  },
 | 
			
		||||
  // Test for maximum length of machine-name
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'This is the test for max length',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 20,
 | 
			
		||||
    expectedMachineName: 'this_is_the_test_for',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Ma@Chi!~',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 5,
 | 
			
		||||
    expectedMachineName: 'ma_ch',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Test for custom replace character',
 | 
			
		||||
    replacePattern: '[^a-zA-Z0-9-_.~]+',
 | 
			
		||||
    replaceChar: '-',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'test-for-custom-replace-character',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'Test for unusual replace pattern',
 | 
			
		||||
    replacePattern: '([^a-z0-9_]+)|(^custom$)',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: 'test_for_unusual_replace_pattern',
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    machineName: 'custom',
 | 
			
		||||
    replacePattern: '([^a-z0-9_]+)|(^custom$)',
 | 
			
		||||
    replaceChar: '_',
 | 
			
		||||
    maxlength: 64,
 | 
			
		||||
    expectedMachineName: '_',
 | 
			
		||||
  },
 | 
			
		||||
  // cSpell:enable
 | 
			
		||||
];
 | 
			
		||||
module.exports = {
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalLoginAsAdmin(() => {
 | 
			
		||||
      browser
 | 
			
		||||
        .drupalRelativeURL('/admin/modules')
 | 
			
		||||
        .setValue('input[type="search"]', 'FormAPI')
 | 
			
		||||
        .waitForElementVisible('input[name="modules[form_test][enable]"]', 1000)
 | 
			
		||||
        .click('input[name="modules[form_test][enable]"]')
 | 
			
		||||
        .click('input[type="submit"]') // Submit module form.
 | 
			
		||||
        .click('input[type="submit"]'); // Confirm installation of dependencies.
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Machine name generation test': (browser) => {
 | 
			
		||||
    browser.drupalRelativeURL('/form-test/machine-name');
 | 
			
		||||
    MachineNameTestArray.forEach((iteration) => {
 | 
			
		||||
      browser.execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback, no-shadow
 | 
			
		||||
        function (object) {
 | 
			
		||||
          return Drupal.behaviors.machineName.transliterate(
 | 
			
		||||
            object.machineName,
 | 
			
		||||
            {
 | 
			
		||||
              replace_pattern: object.replacePattern,
 | 
			
		||||
              replace: object.replaceChar,
 | 
			
		||||
              maxlength: object.maxlength,
 | 
			
		||||
            },
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        [iteration],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(result.value, iteration.expectedMachineName);
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										37
									
								
								web/core/tests/Drupal/Nightwatch/Tests/statesTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/core/tests/Drupal/Nightwatch/Tests/statesTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalInstallModule('form_test', true);
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'Test form with state API': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/form-test/javascript-states-form')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .waitForElementNotVisible('input[name="textfield"]', 1000)
 | 
			
		||||
      .assert.noDeprecationErrors();
 | 
			
		||||
  },
 | 
			
		||||
  'Test number trigger with spinner widget': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/form-test/javascript-states-form')
 | 
			
		||||
      .waitForElementVisible('body', 1000)
 | 
			
		||||
      .waitForElementNotVisible(
 | 
			
		||||
        '#edit-item-visible-when-number-trigger-filled-by-spinner',
 | 
			
		||||
        1000,
 | 
			
		||||
      )
 | 
			
		||||
      .execute(() => {
 | 
			
		||||
        // Emulate usage of the spinner browser widget on number inputs
 | 
			
		||||
        // on modern browsers.
 | 
			
		||||
        const numberTrigger = document.getElementById('edit-number-trigger');
 | 
			
		||||
        numberTrigger.value = 1;
 | 
			
		||||
        numberTrigger.dispatchEvent(new Event('change'));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    browser.waitForElementVisible(
 | 
			
		||||
      '#edit-item-visible-when-number-trigger-filled-by-spinner',
 | 
			
		||||
      1000,
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										182
									
								
								web/core/tests/Drupal/Nightwatch/Tests/tabbingManagerTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								web/core/tests/Drupal/Nightwatch/Tests/tabbingManagerTest.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  '@tags': ['core'],
 | 
			
		||||
  before(browser) {
 | 
			
		||||
    browser.drupalInstall().drupalInstallModule('tabbingmanager_test');
 | 
			
		||||
  },
 | 
			
		||||
  after(browser) {
 | 
			
		||||
    browser.drupalUninstall();
 | 
			
		||||
  },
 | 
			
		||||
  'test tabbingmanager': (browser) => {
 | 
			
		||||
    browser
 | 
			
		||||
      .drupalRelativeURL('/tabbingmanager-test')
 | 
			
		||||
      .waitForElementPresent('#tabbingmanager-test-container', 1000);
 | 
			
		||||
 | 
			
		||||
    // Tab through the form without tabbing constrained. Tabbing out of the
 | 
			
		||||
    // third input should focus the fourth.
 | 
			
		||||
    browser
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          document.querySelector('#first').focus();
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'first',
 | 
			
		||||
            '[not constrained] First element focused after calling focus().',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#first', [browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'second',
 | 
			
		||||
            '[not constrained] Tabbing first element focuses second element.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#second', [browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'third',
 | 
			
		||||
            '[not constrained] Tabbing second element focuses third element.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#third', [browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'fourth',
 | 
			
		||||
            '[not constrained] Tabbing third element focuses fourth element.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    // Tab through the form with tabbing constrained to the container that has
 | 
			
		||||
    // the first, second, and third inputs. Tabbing out of the third (final)
 | 
			
		||||
    // input should move focus back to the first one.
 | 
			
		||||
    browser
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          Drupal.tabbingManager.constrain(
 | 
			
		||||
            document.querySelector('#tabbingmanager-test-container'),
 | 
			
		||||
            { trapFocus: true },
 | 
			
		||||
          );
 | 
			
		||||
          document.querySelector('#first').focus();
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'first',
 | 
			
		||||
            '[constrained] First element focused after calling focus().',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#first', [browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'second',
 | 
			
		||||
            '[constrained] Tabbing first element focuses second element',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#second', [browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'third',
 | 
			
		||||
            '[constrained] Tabbing second element focuses the third.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#third', [browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'first',
 | 
			
		||||
            '[constrained] Tabbing final element focuses the first.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    // Confirm shift+tab on the first element focuses the third (final).
 | 
			
		||||
    browser
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          document.querySelector('#first').focus();
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'first',
 | 
			
		||||
            '[constrained] First element focused after calling focus().',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      )
 | 
			
		||||
      .setValue('#first', [browser.Keys.SHIFT, browser.Keys.TAB])
 | 
			
		||||
      .execute(
 | 
			
		||||
        // eslint-disable-next-line func-names, prefer-arrow-callback
 | 
			
		||||
        function () {
 | 
			
		||||
          return document.activeElement.id;
 | 
			
		||||
        },
 | 
			
		||||
        [],
 | 
			
		||||
        (result) => {
 | 
			
		||||
          browser.assert.equal(
 | 
			
		||||
            result.value,
 | 
			
		||||
            'third',
 | 
			
		||||
            '[constrained] Shift+tab the first element moves focus to the last element.',
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    browser.drupalLogAndEnd({ onlyOnError: false });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user