Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Creates role with given permissions.
|
||||
*
|
||||
* @param {object} settings
|
||||
* Settings object
|
||||
* @param {array} settings.permissions
|
||||
* The list of roles granted for the user.
|
||||
* @param {string} [settings.name=null]
|
||||
* The role name.
|
||||
* @param {function} callback
|
||||
* A callback which will be called, when creating the role is finished.
|
||||
* @return {object}
|
||||
* The drupalCreateRole command.
|
||||
*/
|
||||
exports.command = function drupalCreateRole(
|
||||
{ permissions, name = null },
|
||||
callback,
|
||||
) {
|
||||
const self = this;
|
||||
const roleName = name || Math.random().toString(36).substring(2, 15);
|
||||
|
||||
let machineName;
|
||||
this.drupalLoginAsAdmin(async () => {
|
||||
this.drupalRelativeURL('/admin/people/roles/add');
|
||||
this.setValue('input[name="label"]', roleName);
|
||||
|
||||
this.execute(() => {
|
||||
jQuery('input[name="label"]').trigger('formUpdated');
|
||||
});
|
||||
// Wait for the machine name to appear so that it can be used later to
|
||||
// select the permissions from the permission page.
|
||||
this.expect
|
||||
.element('.user-role-form .machine-name-value')
|
||||
.to.be.visible.before(2000);
|
||||
|
||||
machineName = await this.getText('.user-role-form .machine-name-value');
|
||||
this.submitForm('#user-role-form').assert.textContains(
|
||||
'[data-drupal-messages]',
|
||||
`Role ${roleName} has been added.`,
|
||||
);
|
||||
|
||||
this.drupalRelativeURL('/admin/people/permissions').waitForElementVisible(
|
||||
'table.permissions',
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
permissions.map(async (permission) =>
|
||||
this.click(`input[name="${machineName}[${permission}]"]`),
|
||||
),
|
||||
);
|
||||
|
||||
this.submitForm('#user-admin-permissions').assert.textContains(
|
||||
'[data-drupal-messages]',
|
||||
'The changes have been saved.',
|
||||
);
|
||||
}).perform(() => {
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self, machineName);
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Logs into Drupal as the given user.
|
||||
*
|
||||
* @param {object} settings
|
||||
* Settings object
|
||||
* @param {string} settings.name
|
||||
* The user name.
|
||||
* @param {string} settings.password
|
||||
* The user password.
|
||||
* @param {array} [settings.permissions=[]]
|
||||
* The list of permissions granted for the user.
|
||||
* @param {function} callback
|
||||
* A callback which will be called when creating the user is finished.
|
||||
* @return {object}
|
||||
* The drupalCreateUser command.
|
||||
*/
|
||||
exports.command = function drupalCreateUser(
|
||||
{ name, password, permissions = [] },
|
||||
callback,
|
||||
) {
|
||||
const self = this;
|
||||
|
||||
// Define the name here because the callback from drupalCreateRole can be
|
||||
// undefined in some cases.
|
||||
const roleName = Math.random()
|
||||
.toString(36)
|
||||
.replace(/[^\w\d]/g, '')
|
||||
.substring(2, 15);
|
||||
this.perform((client, done) => {
|
||||
if (permissions.length) {
|
||||
this.drupalCreateRole({ permissions, name: roleName }, done);
|
||||
}
|
||||
}).drupalLoginAsAdmin(async () => {
|
||||
this.drupalRelativeURL('/admin/people/create')
|
||||
.setValue('input[name="name"]', name)
|
||||
.setValue('input[name="pass[pass1]"]', password)
|
||||
.setValue('input[name="pass[pass2]"]', password)
|
||||
.perform((client, done) => {
|
||||
if (permissions.length) {
|
||||
client.click(`input[name="roles[${roleName}]`, () => {
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
})
|
||||
.submitForm('#user-register-form')
|
||||
.assert.textContains(
|
||||
'[data-drupal-messages]',
|
||||
'Created a new user account',
|
||||
`User "${name}" was created successfully.`,
|
||||
);
|
||||
});
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Enable a given theme.
|
||||
*
|
||||
* @param themeMachineName
|
||||
* The theme machine name to enable
|
||||
* @param adminTheme
|
||||
* If true, install the theme as the admin theme instead of default.
|
||||
* @return {object}
|
||||
* The drupalEnableTheme command.
|
||||
*/
|
||||
exports.command = function drupalEnableTheme(
|
||||
themeMachineName,
|
||||
adminTheme = false,
|
||||
) {
|
||||
this.drupalLoginAsAdmin(() => {
|
||||
const path = adminTheme
|
||||
? '/admin/theme/install_admin/'
|
||||
: '/admin/theme/install_default/';
|
||||
this.drupalRelativeURL(`${path}${themeMachineName}`).waitForElementPresent(
|
||||
'#theme-installed',
|
||||
10000,
|
||||
);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
69
web/core/tests/Drupal/Nightwatch/Commands/drupalInstall.js
Normal file
69
web/core/tests/Drupal/Nightwatch/Commands/drupalInstall.js
Normal file
@ -0,0 +1,69 @@
|
||||
const { execSync } = require('node:child_process');
|
||||
const { URL } = require('node:url');
|
||||
const { commandAsWebserver } = require('../globals');
|
||||
|
||||
/**
|
||||
* Installs a Drupal test site.
|
||||
*
|
||||
* @param {object} [settings={}]
|
||||
* Settings object
|
||||
* @param {string} [settings.setupFile='']
|
||||
* Setup file used by TestSiteApplicationTest
|
||||
* @param {string} [settings.installProfile='']
|
||||
* The install profile to use.
|
||||
* @param {string} [settings.langcode='']
|
||||
* The language to install the site in.
|
||||
* @param {function} callback
|
||||
* A callback which will be called, when the installation is finished.
|
||||
* @return {object}
|
||||
* The 'browser' object.
|
||||
*/
|
||||
exports.command = function drupalInstall(
|
||||
{ setupFile = '', installProfile = 'nightwatch_testing', langcode = '' } = {},
|
||||
callback,
|
||||
) {
|
||||
const self = this;
|
||||
|
||||
// Ensure no session cookie exists anymore; they won't work on this newly installed Drupal site anyway.
|
||||
this.cookies.deleteAll();
|
||||
|
||||
try {
|
||||
setupFile = setupFile ? `--setup-file "${setupFile}"` : '';
|
||||
installProfile = `--install-profile "${installProfile}"`;
|
||||
const langcodeOption = langcode ? `--langcode "${langcode}"` : '';
|
||||
const dbOption =
|
||||
process.env.DRUPAL_TEST_DB_URL.length > 0
|
||||
? `--db-url "${process.env.DRUPAL_TEST_DB_URL}"`
|
||||
: '';
|
||||
const install = execSync(
|
||||
commandAsWebserver(
|
||||
`php ./scripts/test-site.php install ${setupFile} ${installProfile} ${langcodeOption} --base-url ${process.env.DRUPAL_TEST_BASE_URL} ${dbOption} --json`,
|
||||
),
|
||||
);
|
||||
const installData = JSON.parse(install.toString());
|
||||
this.globals.drupalDbPrefix = installData.db_prefix;
|
||||
this.globals.drupalSitePath = installData.site_path;
|
||||
const url = new URL(process.env.DRUPAL_TEST_BASE_URL);
|
||||
this.url(process.env.DRUPAL_TEST_BASE_URL).setCookie({
|
||||
name: 'SIMPLETEST_USER_AGENT',
|
||||
// Colons need to be URL encoded to be valid.
|
||||
value: encodeURIComponent(installData.user_agent),
|
||||
path: url.pathname,
|
||||
});
|
||||
// Set the HTTP_USER_AGENT environment variable to detect the test
|
||||
// environment in the command line.
|
||||
process.env.HTTP_USER_AGENT = installData.user_agent;
|
||||
} catch (error) {
|
||||
this.assert.fail(error);
|
||||
}
|
||||
|
||||
// Nightwatch doesn't like it when no actions are added in a command file.
|
||||
// https://github.com/nightwatchjs/nightwatch/issues/1792
|
||||
this.pause(1);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Install the given module.
|
||||
*
|
||||
* @param {string} module
|
||||
* The module machine name to enable.
|
||||
* @param {boolean} force
|
||||
* Force to install dependencies if applicable.
|
||||
* @param {function} callback
|
||||
* A callback which will be called, when the module has been enabled.
|
||||
* @return {object}
|
||||
* The drupalInstallModule command.
|
||||
*/
|
||||
exports.command = function drupalInstallModule(module, force, callback) {
|
||||
const self = this;
|
||||
this.drupalLoginAsAdmin(() => {
|
||||
this.drupalRelativeURL('/admin/modules')
|
||||
// Filter module list to ensure that collapsable <details> elements are expanded.
|
||||
.updateValue(
|
||||
'form.system-modules [data-drupal-selector="edit-text"]',
|
||||
module,
|
||||
)
|
||||
.waitForElementVisible(
|
||||
`form.system-modules [name="modules[${module}][enable]"]`,
|
||||
10000,
|
||||
)
|
||||
.click(`form.system-modules [name="modules[${module}][enable]"]`)
|
||||
.submitForm('form.system-modules');
|
||||
if (force) {
|
||||
// Click `Continue` if applicable.
|
||||
this.waitForElementPresent(
|
||||
'#system-modules-confirm-form, #system-modules-non-stable-confirm-form',
|
||||
10000,
|
||||
false,
|
||||
() => self.click('input[value=Continue]'),
|
||||
);
|
||||
}
|
||||
// Wait for the checkbox for the module to be disabled as a sign that the
|
||||
// module has been enabled.
|
||||
this.waitForElementPresent(
|
||||
`form.system-modules [name="modules[${module}][enable]"]:disabled`,
|
||||
10000,
|
||||
);
|
||||
}).perform(() => {
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
27
web/core/tests/Drupal/Nightwatch/Commands/drupalLogAndEnd.js
Normal file
27
web/core/tests/Drupal/Nightwatch/Commands/drupalLogAndEnd.js
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Ends the browser session and logs the console log if there were any errors.
|
||||
* See globals.js.
|
||||
*
|
||||
* @param {Object}
|
||||
* (optional) Settings object
|
||||
* @param onlyOnError
|
||||
* (optional) Only writes out the console log file if the test failed.
|
||||
* @param {function} callback
|
||||
* A callback which will be called.
|
||||
* @return {object}
|
||||
* The 'browser' object.
|
||||
*/
|
||||
exports.command = function drupalLogAndEnd({ onlyOnError = true }, callback) {
|
||||
const self = this;
|
||||
this.drupalLogConsole = true;
|
||||
this.drupalLogConsoleOnlyOnError = onlyOnError;
|
||||
|
||||
// Nightwatch doesn't like it when no actions are added in a command file.
|
||||
// https://github.com/nightwatchjs/nightwatch/issues/1792
|
||||
this.pause(1);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
36
web/core/tests/Drupal/Nightwatch/Commands/drupalLogin.js
Normal file
36
web/core/tests/Drupal/Nightwatch/Commands/drupalLogin.js
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Logs into Drupal as the given user.
|
||||
*
|
||||
* @param {string} name
|
||||
* The user name.
|
||||
* @param {string} password
|
||||
* The user password.
|
||||
* @return {object}
|
||||
* The drupalUserIsLoggedIn command.
|
||||
*/
|
||||
exports.command = function drupalLogin({ name, password }) {
|
||||
this.drupalUserIsLoggedIn((sessionExists) => {
|
||||
// Log the current user out if necessary.
|
||||
if (sessionExists) {
|
||||
this.drupalLogout();
|
||||
}
|
||||
// Log in with the given credentials.
|
||||
this.drupalRelativeURL('/user/login')
|
||||
.setValue('input[name="name"]', name)
|
||||
.setValue('input[name="pass"]', password)
|
||||
.submitForm('#user-login-form');
|
||||
// MongoDB needs a moment, because it is using a replica set and the
|
||||
// members of the replica set need to synchronize.
|
||||
this.pause(50);
|
||||
// Assert that a user is logged in.
|
||||
this.drupalUserIsLoggedIn((sessionExists) => {
|
||||
this.assert.equal(
|
||||
sessionExists,
|
||||
true,
|
||||
`The user "${name}" was logged in.`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -0,0 +1,40 @@
|
||||
const { execSync } = require('node:child_process');
|
||||
const { commandAsWebserver } = require('../globals');
|
||||
|
||||
/**
|
||||
* Logs in as the admin user.
|
||||
*
|
||||
* @param {function} callback
|
||||
* A callback which will allow running commands as an administrator.
|
||||
* @return {object}
|
||||
* The drupalLoginAsAdmin command.
|
||||
*/
|
||||
exports.command = function drupalLoginAsAdmin(callback) {
|
||||
const self = this;
|
||||
this.drupalUserIsLoggedIn((sessionExists) => {
|
||||
if (sessionExists) {
|
||||
this.drupalLogout();
|
||||
}
|
||||
const userLink = execSync(
|
||||
commandAsWebserver(
|
||||
`php ./scripts/test-site.php user-login 1 --site-path ${this.globals.drupalSitePath}`,
|
||||
),
|
||||
);
|
||||
|
||||
this.drupalRelativeURL(userLink.toString());
|
||||
|
||||
this.drupalUserIsLoggedIn((sessionExists) => {
|
||||
if (!sessionExists) {
|
||||
throw new Error('Logging in as an admin user failed.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
|
||||
this.drupalLogout({ silent: true });
|
||||
|
||||
return this;
|
||||
};
|
||||
39
web/core/tests/Drupal/Nightwatch/Commands/drupalLogout.js
Normal file
39
web/core/tests/Drupal/Nightwatch/Commands/drupalLogout.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Logs out from a Drupal site.
|
||||
*
|
||||
* @param {object} [settings={}]
|
||||
* The settings object.
|
||||
* @param {boolean} [settings.silent=false]
|
||||
* If the command should be run silently.
|
||||
* @param {function} callback
|
||||
* A callback which will be called, when the logout is finished.
|
||||
* @return {object}
|
||||
* The drupalLogout command.
|
||||
*/
|
||||
exports.command = function drupalLogout({ silent = false } = {}, callback) {
|
||||
const self = this;
|
||||
|
||||
this.drupalRelativeURL('/user/logout/confirm').submitForm(
|
||||
'#user-logout-confirm',
|
||||
);
|
||||
|
||||
// MongoDB needs a moment, because it is using a replica set and the
|
||||
// members of the replica set need to synchronize.
|
||||
this.pause(50);
|
||||
|
||||
this.drupalUserIsLoggedIn((sessionExists) => {
|
||||
if (silent) {
|
||||
if (sessionExists) {
|
||||
throw new Error('Logging out failed.');
|
||||
}
|
||||
} else {
|
||||
this.assert.equal(sessionExists, false, 'The user was logged out.');
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Concatenate a DRUPAL_TEST_BASE_URL variable and a pathname.
|
||||
*
|
||||
* This provides a custom command, .relativeURL()
|
||||
*
|
||||
* @param {string} pathname
|
||||
* The relative path to append to DRUPAL_TEST_BASE_URL
|
||||
* @param {function} callback
|
||||
* A callback which will be called.
|
||||
* @return {object}
|
||||
* The 'browser' object.
|
||||
*/
|
||||
exports.command = function drupalRelativeURL(pathname, callback) {
|
||||
const self = this;
|
||||
this.url(`${process.env.DRUPAL_TEST_BASE_URL}${pathname}`);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
46
web/core/tests/Drupal/Nightwatch/Commands/drupalUninstall.js
Normal file
46
web/core/tests/Drupal/Nightwatch/Commands/drupalUninstall.js
Normal file
@ -0,0 +1,46 @@
|
||||
const { execSync } = require('node:child_process');
|
||||
const { commandAsWebserver } = require('../globals');
|
||||
|
||||
/**
|
||||
* Uninstalls a test Drupal site.
|
||||
*
|
||||
* @param {function} callback
|
||||
* A callback which will be called, when the uninstallation is finished.
|
||||
* @return {object}
|
||||
* The 'browser' object.
|
||||
*/
|
||||
exports.command = function drupalUninstall(callback) {
|
||||
const self = this;
|
||||
const prefix = this.globals.drupalDbPrefix;
|
||||
|
||||
// Check for any existing errors, because running this will cause Nightwatch to hang.
|
||||
if (!this.currentTest.results.errors && !this.currentTest.results.failed) {
|
||||
const dbOption =
|
||||
process.env.DRUPAL_TEST_DB_URL.length > 0
|
||||
? `--db-url "${process.env.DRUPAL_TEST_DB_URL}"`
|
||||
: '';
|
||||
try {
|
||||
if (!prefix || !prefix.length) {
|
||||
throw new Error(
|
||||
'Missing database prefix parameter, unable to uninstall Drupal (the initial install was probably unsuccessful).',
|
||||
);
|
||||
}
|
||||
execSync(
|
||||
commandAsWebserver(
|
||||
`php ./scripts/test-site.php tear-down ${prefix} ${dbOption}`,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
this.assert.fail(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Nightwatch doesn't like it when no actions are added in a command file.
|
||||
// https://github.com/nightwatchjs/nightwatch/issues/1792
|
||||
this.pause(1);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(self);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Checks if a user is logged in.
|
||||
*
|
||||
* @param {function} callback
|
||||
* A callback which will be called, when the login status has been checked.
|
||||
* @return {object}
|
||||
* The drupalUserIsLoggedIn command.
|
||||
*/
|
||||
exports.command = function drupalUserIsLoggedIn(callback) {
|
||||
if (typeof callback === 'function') {
|
||||
this.cookies.getAll((cookies) => {
|
||||
const sessionExists = cookies.value.some((cookie) =>
|
||||
cookie.name.match(/^S?SESS/),
|
||||
);
|
||||
|
||||
callback.call(this, sessionExists);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
Reference in New Issue
Block a user