keystone-nightwatch-e2e
Version:
Nightwatch end-to-end testing framework for KeystoneJS applications
637 lines (614 loc) • 26.9 kB
JavaScript
/**
* This module defines the commands an e2e test client may execute against keystone's item edit form screen.
* When using the assertElement* commands, you may specify one of the predefined element selector properties
* by prefixing it with the '@' sign or you can specify a string representing your own element selector.
* See {@link https://github.com/keystonejs/keystone/tree/master/test/e2e/adminUI/tests/group005Item|usage example},
* {@link https://github.com/keystonejs/keystone/tree/master/test/e2e/adminUI/tests/group006Fields|usage example}
*
* @module adminUIItemScreen
*/
module.exports = {
commands: [{
/**
* Sets a default model test config object so that tests do not have to pass it in with each field level command.
* Tests can still override the default model test config object when calling any field level command.
*
* @param {Object} modelTestConfig The model test config that should be used by field level commands, if the
* command does not pass it in directly.
*/
setDefaultModelTestConfig: function (modelTestConfig) {
this.defaultModelTestConfig = modelTestConfig;
return this;
},
/**
* Asserts that the specified edit item screen element UI is visible.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose UI should be visible.
*/
assertElementIsVisible: function (config) {
if (config) {
if (config.element) {
this.expect.element(config.element).to.be.visible;
} else {
throw new Error('adminUIItemScreen:must specify an element!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element UI is not visible.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose UI should not be visible.
*/
assertElementIsNotVisible: function (config) {
if (config) {
if (config.element) {
this.expect.element(config.element).to.not.be.visible;
} else {
throw new Error('adminUIItemScreen:must specify an element!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element DOM is present.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose DOM should be present.
*/
assertElementIsPresent: function (config) {
if (config) {
if (config.element) {
this.expect.element(config.element).to.be.present;
} else {
throw new Error('adminUIItemScreen:must specify an element!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element DOM is not present.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose DOM should not be present.
*/
assertElementIsNotPresent: function (config) {
if (config) {
if (config.element) {
this.expect.element(config.element).to.not.be.present;
} else {
throw new Error('adminUIItemScreen:must specify an element!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element text equals the specified value.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose text should be compared to the input text.
* @param {String} config.text The text to compare against.
*/
assertElementTextEquals: function (config) {
if (config) {
if (config.element && config.text) {
this.expect.element(config.element).text.to.equal(config.text);
} else {
throw new Error('adminUIItemScreen:must specify an element and text!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element text not equals the specified value.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose text should be compared to the input text.
* @param {String} config.text The text to compare against.
*/
assertElementTextNotEquals: function (config) {
if (config) {
if (config.element && config.text) {
this.expect.element(config.element).text.to.not.equal(config.text);
} else {
throw new Error('adminUIItemScreen:must specify an element and text!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element text contains the specified value.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose text should contain the input text.
* @param {String} config.text The text to compare against.
*/
assertElementTextContains: function (config) {
if (config) {
if (config.element && config.text) {
this.expect.element(config.element).text.to.contain(config.text);
} else {
throw new Error('adminUIItemScreen:must specify an element and text!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified edit item screen element has the specified attribute.
*
* @param {Object} config The config spec.
* @param {string} config.element The element whose UI should be visible.
* @param {string} config.attribute The attribute that should be present in the element.
* @param {string} config.value The value that the attribute should have.
*/
assertElementHasAttribute: function (config) {
if (config) {
if (config.element && config.attribute && config.value) {
this.expect.element(config.element).to.have.attribute(config.attribute).which.contains(config.value);
} else {
throw new Error('adminUIItemScreen:must specify a config element, attribute, and value!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified item field's UI is visible in the edit item screen. This command calls into the
* assertFieldUIVisible command of the field under test, which gets passed the field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to assert the UI visibility on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
* @param {Object} config.field.options Any options required by the field test object command assertFieldUIVisible.
*/
assertFieldUIVisible: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
if (ModelTestConfig) {
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'assertFieldUIVisible' in fieldTestObject.commands) {
form.section.list[field.name].commands.assertFieldUIVisible(browser, field.options);
} else {
throw new Error('adminUIItemScreen:assertFieldUIVisible command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldUIVisible: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldUIVisible: invalid field modelTestConfig!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldUIVisible: No modelTestConfig given!');
}
});
} else {
throw new Error('adminUIItemScreen:assertFieldUIVisible: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified item field's UI is not visible in the edit item screen. This command calls into the
* assertFieldUINotVisible command of the field under test, which gets passed the field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to assert the UI visibility on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
* @param {Object} config.field.options Any options required by the field test object command assertFieldUINotVisible.
*/
assertFieldUINotVisible: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
if (ModelTestConfig) {
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'assertFieldUINotVisible' in fieldTestObject.commands) {
form.section.list[field.name].commands.assertFieldUINotVisible(browser, field.options);
} else {
throw new Error('adminUIItemScreen:assertFieldUINotVisible command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldUINotVisible: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldUINotVisible: invalid field modelTestConfig!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldUINotVisible: No modelTestConfig given!');
}
});
} else {
throw new Error('adminUIItemScreen:assertFieldUINotVisible: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified item field's DOM is present in the edit item screen. This command calls into the
* assertFieldDOMPresent command of the field under test, which gets passed the field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to assert the DOM presence on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
* @param {Object} config.field.options Any options required by the field test object command assertFieldDOMPresent.
*/
assertFieldDOMPresent: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
if (ModelTestConfig) {
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'assertFieldDOMPresent' in fieldTestObject.commands) {
form.section.list[field.name].commands.assertFieldDOMPresent(browser, field.options);
} else {
throw new Error('adminUIItemScreen:assertFieldDOMPresent command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldDOMPresent: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldDOMPresent: invalid field modelTestConfig!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldDOMPresent: No modelTestConfig given!');
}
});
} else {
throw new Error('adminUIItemScreen:assertFieldDOMPresent: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts that the specified item field's DOM is not present in the edit item screen. This command calls into the
* assertFieldDOMNotPresent command of the field under test, which gets passed the field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to assert the DOM presence on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
* @param {Object} config.field.options Any options required by the field test object command assertFieldDOMNotPresent.
*/
assertFieldDOMNotPresent: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
if (ModelTestConfig) {
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'assertFieldDOMNotPresent' in fieldTestObject.commands) {
form.section.list[field.name].commands.assertFieldDOMNotPresent(browser, field.options);
} else {
throw new Error('adminUIItemScreen:assertFieldDOMNotPresent command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldDOMNotPresent: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldDOMNotPresent: invalid field modelTestConfig!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldDOMNotPresent: No modelTestConfig given!');
}
});
} else {
throw new Error('adminUIItemScreen:assertFieldDOMNotPresent: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Clicks the specified field's click area in the edit item screen. This command calls into the
* clickFieldUI command of the field under test, which gets passed the field.input and field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to click on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} field.click The clickable area to pass to the field test object command clickFieldUI.
* @param {Object} config.field.options Any options required by the field test object command clickFieldUI.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
*/
clickFieldUI: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
if (ModelTestConfig) {
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'clickFieldUI' in fieldTestObject.commands) {
form.section.list[field.name].commands.clickFieldUI(browser, field.click, field.options);
} else {
throw new Error('adminUIItemScreen:clickFieldUI command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:clickFieldUI: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:clickFieldUI: invalid field modelTestConfig!');
}
} else {
throw new Error('adminUIItemScreen:clickFieldUI: No modelTestConfig given!');
}
});
} else {
throw new Error('adminUIItemScreen:clickFieldUI: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Fills the specified field's inputs in the edit item screen. This command calls into the
* fillFieldInputs command of the field under test, which gets passed the field.input and field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to assert the UI visibility on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} field.input The input to pass to the field test object command fillFieldInputs.
* @param {Object} config.field.options Any options required by the field test object command fillFieldInputs.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
*/
fillFieldInputs: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'fillFieldInputs' in fieldTestObject.commands) {
form.section.list[field.name].commands.fillFieldInputs(browser, field.input, field.options);
browser.api.pause(1000);
} else {
throw new Error('adminUIItemScreen:fillFieldInputs command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:fillFieldInputs: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:fillFieldInputs: invalid field modelTestConfig!');
}
});
} else {
throw new Error('adminUIItemScreen:fillFieldInputs: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Asserts the field's inputs in the edit item screen are as specified. This command calls into the
* assertFieldInputs command of the field under test, which gets passed the field.input and field.options.
*
* @param {Object} config The config spec.
* @param {array} config.fields The array of fields to assert the UI visibility on.
* @param {String} config.field.name The name of the field under test.
* @param {Object} field.input The input to pass to the field test object command assertFieldInputs.
* @param {Object} config.field.options Any options required by the field test object command assertFieldInputs.
* @param {Object} config.field.modelTestConfig The model test config that should be used for the field under test.
*/
assertFieldInputs: function (config) {
var browser = this;
var form = this.section.form;
if (config) {
if (config.fields) {
config.fields.forEach(function (field) {
var ModelTestConfig = field.modelTestConfig || browser.defaultModelTestConfig;
if (ModelTestConfig) {
form.section.list = new ModelTestConfig({ formSelector: form.selector });
if (form.section.list) {
var fieldTestObject = form.section.list[field.name];
if (fieldTestObject) {
if (fieldTestObject.commands && 'assertFieldInputs' in fieldTestObject.commands) {
form.section.list[field.name].commands.assertFieldInputs(browser, field.input, field.options);
} else {
throw new Error('adminUIItemScreen:assertFieldInputs command not defined in ' + field.name + ' field test object!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldInputs: invalid field name!');
}
} else {
throw new Error('adminUIItemScreen:assertFieldInputs: invalid field modelTestConfig!');
}
} else {
throw new Error('adminUIItemScreen:fillFieldInputs: invalid field modelTestConfig!');
}
});
} else {
throw new Error('adminUIItemScreen:assertFieldInputs: Invalid fields specification!');
}
} else {
throw new Error('adminUIItemScreen:invalid config specification!');
}
return this;
},
/**
* Navigates to the first relationship in the edit item form.
*
* TODO: this should be refactor to be able to navigate to any relationship!
*/
navitageToFirstRelationship: function () {
return this
.moveToElement('@firstRelationshipItemLink', 0, 0)
.click('@firstRelationshipItemLink');
},
/**
* Navigate back to the list screen from the edit item form.
*/
back: function () {
return this
.moveToElement('@listBreadcrumb', 0, 0)
.click('@listBreadcrumb');
},
/**
* Creates a new item off the edit item form.
*/
new: function () {
return this
.moveToElement('@newItemButton', 0, 0)
.click('@newItemButton');
},
/**
* Saves the edited item form.
*/
save: function () {
return this.section.form
.moveToElement('@saveButton', 0, 0)
.click('@saveButton');
},
/**
* Resets pending changes in the edit item form.
*/
reset: function () {
return this.section.form
.moveToElement('@resetButton', 0, 0)
.click('@resetButton');
},
/**
* Deletes the item being edited.
*/
delete: function () {
return this.section.form
.moveToElement('@deleteButton', 0, 0)
.click('@deleteButton');
},
}],
sections: {
form: {
selector: '.EditForm-container',
sections: {},
elements: {
//
// FORM LEVEL ELEMENTS
//
saveButton: 'button[data-button=update]',
resetButton: 'button[data-button=reset]',
deleteButton: 'button[data-button=delete]',
},
commands: [{
//
// FORM LEVEL COMMANDS
//
}],
},
},
/**
* @property {string} listBreadcrumb The element used to ID the back to list breadcrumb.
* @property {string} searchInputIcon The element used to ID the search input icon.
* @property {string} newItemButton The element used to ID the new item button.
* @property {string} flashMessage The element used to ID the success flash message.
* @property {string} flashError The element used to ID the error flash message.
* @property {string} readOnlyNameHeader The element used to ID the read-only name header.
* @property {string} editableNameHeader The element used to ID the editable name header.
* @property {string} idLabel The element used to ID the item id label.
* @property {string} idValue The element used to ID the item id value.
* @property {string} metaHeader The element used to ID the meta data header.
* @property {string} metaCreatedAtLabel The element used to ID the meta data header created-at label.
* @property {string} metaCreatedAtValue The element used to ID the meta data header created-at value.
* @property {string} metaCreatedByLabel The element used to ID the meta data header created-by label.
* @property {string} metaCreatedByValue The element used to ID the meta data header created-by value.
* @property {string} metaUpdatedAtLabel The element used to ID the meta data header updated-at label.
* @property {string} metaUpdatedAtValue The element used to ID the meta data header updated-at value.
* @property {string} metaUpdatedByLabel The element used to ID the meta data header updated-by label.
* @property {string} metaUpdatedByValue The element used to ID the meta data header updated-by value.
* @property {string} saveButton The element used to ID the save button.
* @property {string} resetButton The element used to ID the reset button.
* @property {string} resetButtonText The element used to ID the reset button text.
* @property {string} deleteButton The element used to ID the delete button.
* @property {string} deleteButtonText The element used to ID the delete button text.
* @property {string} firstRelationshipItemLink The element used to ID the first relationship item link.
*/
elements: {
//
// PAGE LEVEL ELEMENTS
//
listBreadcrumb: 'a[data-e2e-editform-header-back="true"]',
searchInputIcon: '[data-e2e-search-icon]',
newItemButton: '.Toolbar__section button[data-e2e-item-create-button="true"]',
flashMessage: 'div[data-alert-type="success"]',
flashError: 'div[data-alert-type="danger"]',
readOnlyNameHeader: '.EditForm__name-field h2',
editableNameHeader: '.EditForm__name-field input[class*="item-name-field"',
idLabel: '.EditForm__key-or-id span[class="EditForm__key-or-id__label"]',
idValue: '.EditForm__key-or-id span[class="EditForm__key-or-id__field"]',
metaHeader: '.EditForm-container h3[class="form-heading"]',
metaCreatedAtLabel: '.EditForm-container div[for="createdAt"] label[for="createdAt"]',
metaCreatedAtValue: '.EditForm-container div[for="createdAt"] span',
metaCreatedByLabel: '.EditForm-container div[for="createdBy"] label[for="createdBy"]',
metaCreatedByValue: '.EditForm-container div[for="createdBy"] span',
metaUpdatedAtLabel: '.EditForm-container div[for="updatedAt"] label[for="updatedAt"]',
metaUpdatedAtValue: '.EditForm-container div[for="updatedAt"] span',
metaUpdatedByLabel: '.EditForm-container div[for="updatedBy"] label[for="updatedBy"]',
metaUpdatedByValue: '.EditForm-container div[for="updatedBy"] span',
saveButton: '.EditForm-container button[data-button=update]',
resetButton: '.EditForm-container button[data-button=reset]',
resetButtonText: '.EditForm-container button[data-button=reset] span',
deleteButton: '.EditForm-container button[data-button=delete]',
deleteButtonText: '.EditForm-container button[data-button=delete] span',
// TODO: refactor this so that any relationship itrem link can be used
firstRelationshipItemLink: 'div.Relationships > div > div > div > table > tbody > tr > td > a',
},
defaultModelTestConfig: null,
};