This library provides a set of handy helper functions for running TestCafe tests on your Drupal application.
Example tests are provided are provided in the project's /example/tests
directory.
npm init
npm install --save-dev testcafe-drupal testcafe testcafe-browser-provider-puppeteer @ffmpeg-installer/ffmpeg
or yarn add -D ...
tests
in the root of your projectconfig.js
in the tests
directory (See Config for more information)fixtures
directory within the tests
directory.fixtures
directory. For examples of how to write tests see this repository's example/tests folder. If you like you can copy these tests into your own project and customize them as necessary. For more information on writing test see the Testcafe documentation site.tests/index.js
file which contains configuration for running tests. Here you can specify the tests to run and which browsers to use. See example index.js file for more information.If your tests require a user account to be present, then you will need to either configure Drupal Testcafe to use those existing user accounts or create user accounts for the default Drupal Testcafe users.
Drupal Testcafe support three functional user types (admin, editor and authenticated user). To change the configuration of these functional user types:
test/config.js
file.username
, password
and role
values to those of the Drupal user account you wish to use. Note the role
value should be the machine name of the user role in the Drupal system.drush user-create testcafe_user --password="testcafe_user" --mail="testcade_user@localhost"
drush user-create testcafe_admin --password="testcafe_admin" --mail="testcade_admin@localhost" && drush user-add-role "administrator" testcafe_admin
drush user-create testcafe_editor --password="testcafe_editor" --mail="testcafe_editor@localhost" && drush user-add-role "editor" testcafe_editor
The above instructions assume that Drupal user roles
administrator
andeditor
exist on the site. If your site uses different names for the "admin" and "editor" roles, then you should update the roles in the config.js file.In addition you would need to modify the create user drush commands above.
For example, if the maching name of the editor role is
ed
, then the modified Drush command whould be:drush user-create testcafe_editor --password="testcafe_editor" --mail="testcafe_editor@localhost" && drush user-add-role "ed" testcafe_editor
To run all tests run the following command from the {PROJECT_ROOT}
directory:
node ./tests
To make life easier you can edit your {PROJECT_ROOT}/package.json
file to include the following script entry:
{
...
"scripts": {
...
"tests": "node ./tests/index.js"
}
}
You can then run tests by using:
npm run tests
After the tests have completed you can find information on reported errors (including screenshots and videos) in the {PROJECT_ROOT}/tests/reports
directory.
Some configuration is required to be set in order for your tests to work.
Configuration is set in the following order of precedence, and can be composed with a combination:
{PROJECT_ROOT}/tests/config.js
Here is a full list of available configuration and their default values
{
baseUrl: "http://localhost:8080",
node: {
create: {
path: "/node/add",
selectors: {
title: "#edit-title-0-value",
save_button: "#edit-submit"
}
}
},
users: {
admin: {
username: "testcafe_admin",
password: "testcafe_admin",
role: "administrator"
},
editor: {
username: "testcafe_editor",
password: "testcafe_editor",
role: "editor"
},
authenticated_user: {
username: "testcafe_user",
password: "testcafe_user"
}
},
user: {
login: {
path: "/user/login",
selectors: {
username: "#edit-name",
password: "#edit-pass",
login_button: "form.user-login-form #edit-submit"
}
},
add: {
path: "/admin/people/create"
}
},
message: {
selectors: {
status: ".messages--status",
error: ".messages--error"
}
}
};
{class}
@param object t
TestCafe test controller.
Provides methods for interacting with Drupal fields created using the Field API.
Whilst the Field class can be used directly it should be noted that these methods can be accessed by other classes which extend the Field class. For example, the Node class provides useful methods for working with node related tests, whilst also having access to all Field class methods.
Usage:
const { Field } = require("testcafe-drupal");
...
test("Example test", async t => {
const field = new Field(t);
// Use field methods
});
@param {string} fileFieldId
ID property of the file field.
@param {string} file
Path to the image file to upload. Will use a default PDF image if this
argument is not provided.
Add file to a Drupal file upload field. By default it will use a placeholder PDF file.
Usage:
const { Field } = require("testcafe-drupal");
...
test("Example test", async t => {
const field = new Field(t);
await field.addFileToField("edit-field-file-0-upload");
});
@param {string} fileFieldId
ID property of the file field.
@param {object} options
An optional argument which can contain following key-value pairs:
- "alt": image alt text. Note that if alt text is provided but the image
alt text has not been enabled in Drupal, then this function will throw
an error.
- "title": image title text. Note that if title text is provided but the
image title has not been enabled in Drupal, then this funciton will
throw an error.
@param {string} image
Path to the image file to upload. Will use a default JPG image if this
argument is not provided.
Add Image to a Drupal file upload field. By default it will use a placeholder JPEG file.
Usage:
const { Field } = require("testcafe-drupal");
...
test("Example test", async t => {
const field = new Field(t);
await field.addImageToField(
"edit-field-image-0-upload",
{ alt: "my alt text", title: "my title text" }
);
});
@param {string} id
CSS id selector of the form field.
@param {string} text
Text to be added to field.
Add text for a text based field.
Works with <input[type='text']>
, <textarea>
and CKEditor
based text fields.
Usage:
const { Field } = require("testcafe-drupal");
...
test("Example test", async t => {
const field = new Field(t);
await field.addTextToField("edit-body-0-value", "hello")
});
@param {string} id
CSS id selector of the <select> element.
@param {array} text
Select element option text to find. This value should be the text that
is visible to the site visitor and is case sensitive.
Check <select>
contains one or more given options.
Usage:
const { Field } = require("testcafe-drupal");
...
test("Example test", async t => {
const field = new Field(t);
await field.checkSelectFieldHasOption(
"edit-field-country",
["Australia", "China", "Mali"]
)
});
@param {string} id
Id property of the <select> element.
@param {string} text
Select element option text. This value is case sensitve.
Choose <select>
element option
Usage:
const { Field } = require("testcafe-drupal");
...
test("Example test", async t => {
const field = new Field(t);
await field.chooseSelectFieldOption("edit-field-options", "Australia")
});
@param {string} id
Id property of the Drupal file field.
Remove a file from a Drupal file field.
Usage:
test("Example test", async t => {
const field = new Field(t);
await field.removeFileFromField(
"edit-field-file-0-upload"
);
});
@param {string} id
Id property of the Drupal file field.
Remove an image file from a Drupal image field.
Usage:
test("Example test", async t => {
const field = new Field(t);
await field.removeImageFromField(
"edit-field-image-0-upload"
);
});
Provides methods for interacting with Drupal node entities.
{class}
@param {object} t
TestCafe test controller.
@param {string} nodeType
Machine name of the node type.
@param {object} config
User's specific Drupal Testcafe configuration.
Usage:
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const nodeType = "article";
const node = new Node(t, nodeType, config);
// Use node methods
});
The Node class extends the Field class so you can access the various field methods directly via the Node class.
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const nodeType = "article";
const node = new Node(t, nodeType, config);
await node.goToNodeCreationPage();
await node.addTextToField(
"edit-body-0-value",
"Here is my test text. What do you think? Something else here as well."
);
}
Check if currently on view node page.
Usage:
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const nodeType = "article";
const node = new Node(t, nodeType, config);
await node.goToNodeCreationPage();
await node.checkOnNodePage()
});
Go to node creation page of given node type.
Usage:
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const nodeType = "article";
const node = new Node(t, nodeType, config);
await node.goToNodeCreationPage()
});
Save node. Clicks save button on node add/edit form.
Usage:
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const nodeType = "article";
const node = new Node(t, nodeType, config);
await node.goToNodeCreationPage();
...
await node.saveNode()
});
Set node title text.
@param {string} text
Node title text.
Usage:
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const nodeType = "article";
const node = new Node(t, nodeType, config);
await node.goToNodeCreationPage();
node.setTitle("This is the title")
...
});
Provides methods for interacting with Drupal generated messages.
{class}
@param {object} t
Testcafe test controller.
@param {object} config
Drupal Testcafe configuration.
Usage:
const { Message, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const message = new Message(t, config);
// Use message methods.
...
});
Check if Drupal generated status message contains given text.
@param {string} text
Text to search for within message.
Usage:
const { Message, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const title = "MY NODE TITLE";
const message = new Message(t, config);
message.statusMessageContainsText(title + " has been created");
});
Check if Drupal generated error message contains given text.
@param {string} text
Text to search for within message.
Usage:
const { Message, config } = require("testcafe-drupal");
...
test("Example test", async t => {
const message = new Message(t, config);
message.errorMessageContainsText("Oops, you can't do that");
});
Return an object containing the users' specified Drupal TestCafe configuration Order of precedence
Usage:
const { Node, config } = require("testcafe-drupal");
...
test("Example test", async t => {
// Use config when initializing an instance of the Node class.
const node = new Node(t, nodeType, config);
});
Return the target test site domain as defined in the configuration (e.g. "http://www.mysite.com").
Usage:
const { baseUrl } = require("testcafe-drupal");
...
test("Example test", async t => {
// Use the baseUrl variable in your tests, or pre-test setup.
});
Certain config values can be overridden via the use of environmental variables.
Variable | Overrides |
---|---|
process.env.TESTCAFE_BASEURL | config.baseUrl |
process.env.TESTCAFE_DRUPAL_USERS_ADMIN_USERNAME | config.users.admin.username |
process.env.TESTCAFE_DRUPAL_USERS_ADMIN_PASSWORD | config.users.admin.password |
process.env.TESTCAFE_DRUPAL_USERS_EDITOR_USERNAME | config.users.editor.username |
process.env.TESTCAFE_DRUPAL_USERS_EDITOR_PASSWORD | config.users.editor.password |
process.env.TESTCAFE_DRUPAL_USERS_AUTHUSER_USERNAME | config.users.authenticated_user.username |
process.env.TESTCAFE_DRUPAL_USERS_AUTHUSER_PASSWORD | config.users.authenticated_user.password |
Define your Testcafe Roles.
Return a user with the administrator role.
Usage:
const { Role } = require("testcafe");
const { administratorUser } = require("testcafe-drupal");
...
test("Example test", async t => {
await t.useRole(Role(...administratorUser));
// Expectations based on this role
});
Return a regular authenticated user.
Usage:
const { Role } = require("testcafe");
const { authenticatedUser } = require("testcafe-drupal");
...
test("Example test", async t => {
await t.useRole(Role(...authenticatedUser));
// Expectations based on this role
});
Return an editor user.
Usage:
const { Role } = require("testcafe");
const { editorUser } = require("testcafe-drupal");
...
test("Example test", async t => {
await t.useRole(Role(...editorUser));
// Expectations based on this role
});
Provides instructions for developers on how to setup a local environment for development work on Drupal Testcafe package. It is recommended that you use Yarn due to it's support of Workspaces, which makes life easier when developing NPM packages. The following instructions assume you are using Yarn.
Create a project directory and add create a package.json
file with the following content.
{
"private": true,
"name": "my-project-name",
"version": "1.0.0",
"workspaces": [
"workspace",
"packages/*"
]
}
Create the following directory structure in your project:
-- <project root>/
|-- package.json
|-- packages/
|-- workspace/
Clone the testcafe-drupal
project in packages/
directory.
cd packages
git clone git@github.com:ironstar-io/testcafe-drupal.git
Change into workspace/
directory and then set up new yarn project. Add the testcafe-drupal
package:
cd ../workspace
yarn init
yarn add -D testcafe-drupal testcafe testcafe-browser-provider-puppeteer @ffmpeg-installer/ffmpeg
yarn install
Copy the tests
directory from the testcafe-drupal/example
directory into the workspace
directory. If you are intending to work on the example tests, then you may wish to sybolically link the tests
directory to the workspace
directory so that any changes will be automatically applied to the tests directory in the cloned testcafe-drupal
repository.
To run tests go to workspace/tests
directory and run the appropriate command. For example:
cd workspace
node ./tests/index.js
-- <project root>/
|--- package.json
|--- packages/
| |-- testcafe-drupal
|
|--- workspace/
|--package.json
|-- tests
Built by the teams at Technocrat and Ironstar