skutter
Version:
Skutter: Opinionated BDD Browser based test framework
394 lines (393 loc) • 27.4 kB
JavaScript
;
const iskutter_library_1 = require("../framework/iskutter-library");
const skutter_library_1 = require("../framework/skutter-library");
const iskutter_dictionary_1 = require("../framework/iskutter-dictionary");
const qualifier_validator_1 = require("./qualifier-validator");
const html_actions_1 = require("../actions/html-actions");
const definition_finder_1 = require("../framework/page-structure/definition-finder");
const verbosity_level_aware_logger_1 = require("../framework/services/verbosity-level-aware-logger");
class HtmlSteps {
constructor() {
let dictionary = new iskutter_dictionary_1.SkutterDictionary()
.define("quotedWordOrWords", /"([^"]+)"/)
.define("nonQuotedWord", /([^\s"]+)/)
.define("qualifier", qualifier_validator_1.QualifierValidator.qualifierRegex)
.define("qualifierPlural", qualifier_validator_1.QualifierValidator.qualifierPluralRegex)
.define("qualifierNumerical", qualifier_validator_1.QualifierValidator.qualifierNumericalRegex)
.define("visibilityQualifier", qualifier_validator_1.QualifierValidator.qualifierVisibilityRegex)
.define("editableQualifier", /(is not editable|is editable|is not readonly|is readonly)/)
.define("disabledQualifier", /(is not disabled|is disabled|is not enabled|is enabled)/);
this.lib = new skutter_library_1.SkutterLibrary(dictionary);
}
createLibrary() {
let lib = this.lib;
lib.when(new iskutter_library_1.WhenDefinition([
"I (?:click|click on) the $nonQuotedWord (?:button|checkbox|radiobutton|image|element)",
"I (?:click|click on) the $quotedWordOrWords (?:button|checkbox|radiobutton|image|element)"]), function (selectorIdentifier, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorIdentifier);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.click(htmlElement))
.then(() => { next(); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.when(new iskutter_library_1.WhenDefinition([
"I type $quotedWordOrWords into the $nonQuotedWord textbox",
"I type $quotedWordOrWords into the $quotedWordOrWords textbox"]), function (text, selectorIdentifier, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorIdentifier);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => { return html_actions_1.HtmlActions.typeText(htmlElement, text); })
.then(() => { next(); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.when(new iskutter_library_1.WhenDefinition([
"I type (enter|tab|backspace|delete|left arrow|right arrow|up arrow|down arrow|escape) into the $quotedWordOrWords",
"I type (enter|tab|backspace|delete|left arrow|right arrow|up arrow|down arrow|escape) into the $nonQuotedWord"]), function (key, selectorIdentifier, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorIdentifier);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.pressKey(htmlElement, key))
.then(() => { next(); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.when(new iskutter_library_1.WhenDefinition([
"I (check|uncheck) the $quotedWordOrWords checkbox",
"I (check|uncheck) the $nonQuotedWord checkbox"]), function (checkuncheck, checkboxName, next) {
let checked = checkuncheck === "check";
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, checkboxName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => {
html_actions_1.HtmlActions.isCheckboxChecked(htmlElement)
.then((isChecked) => {
if (checked && isChecked) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.info("Checkbox is already checked. Performing no action.");
next();
}
else if (!checked && !isChecked) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.info("Checkbox is already unchecked. Performing no action.");
next();
}
else {
html_actions_1.HtmlActions.click(htmlElement)
.then(() => { next(); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
}
}, error => { next(error); });
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.when(new iskutter_library_1.WhenDefinition([
"I select the $quotedWordOrWords option in the $quotedWordOrWords dropdown",
"I select the $quotedWordOrWords option in the $nonQuotedWord dropdown"]), function (optionToSelect, dropdownSelector, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, dropdownSelector);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.selectOption(htmlElement, optionToSelect))
.then(() => { next(); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.when(new iskutter_library_1.WhenDefinition([
"I select the blank option in the $quotedWordOrWords dropdown",
"I select the blank option in the $nonQuotedWord dropdown"]), function (dropdownSelector, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, dropdownSelector);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.selectOption(htmlElement, "", true))
.then(() => { next(); }, error => {
next(error || new Error("Promise resolution failed with no error details."));
});
});
lib.when(new iskutter_library_1.WhenDefinition([
"I clear the $quotedWordOrWords (?:field|textbox)",
"I clear the $nonQuotedWord (?:field|textbox)"]), function (fieldName, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, fieldName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.clear())
.then(() => { next(); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords text (is|is not) empty",
"the $nonQuotedWord text (is|is not) empty"]), function (selectorName, isIsNot, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getText())
.then((actualText) => {
actualText = actualText || "";
let error = null;
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.test(`[HtmlSteps] Testing: Element Text ${isIsNot} empty`);
switch (isIsNot) {
case "is":
if (actualText !== "") {
error = `Expected text to be empty string. But it was "${actualText}".`;
}
break;
case "is not":
if (actualText === "") {
error = "Expected text not to be empty string.";
}
break;
}
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords text $qualifier $quotedWordOrWords",
"the $nonQuotedWord text $qualifier $quotedWordOrWords"]), function (selectorName, qualifier, expectedText, next) {
if (expectedText === "") {
throw new Error('[HtmlSteps] Blank expected text provided. Instead use the "text is empty" or "text is not empty" variant to test for emptiness".');
}
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getText())
.then((selectedOptionText) => { next(qualifier_validator_1.QualifierValidator.qualifierValidate(qualifier, selectedOptionText, expectedText)); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords text (is not|is) unicode $quotedWordOrWords",
"the $nonQuotedWord text (is not|is) unicode $quotedWordOrWords"]), function (selectorIdentifier, qualifier, expectedValue, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorIdentifier);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getText())
.then((actualValue) => {
let expectedNumericValue = parseInt(expectedValue, 16);
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.info(`Expected: ${expectedValue} unicode integer ${expectedNumericValue}`);
let actualInt = actualValue.charCodeAt(0);
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.info(`Actual: ${actualValue} unicode integer ${actualInt}`);
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.test(`Testing: ${actualInt} is ${expectedNumericValue}`);
let error = qualifier_validator_1.QualifierValidator.qualifierNumericalValidate(actualInt, qualifier, expectedNumericValue);
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords value $qualifier $quotedWordOrWords",
"the $nonQuotedWord value $qualifier $quotedWordOrWords"]), function (selectorName, qualifier, expectedText, next) {
if (expectedText === "") {
throw new Error('[HtmlSteps] Blank expected value provided. Instead use the "value is empty" or "value is not empty" variant to test for emptiness".');
}
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getAttribute("value"))
.then((actualText) => { next(qualifier_validator_1.QualifierValidator.qualifierValidate(qualifier, actualText, expectedText)); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords value (is not|is) empty",
"the $nonQuotedWord value (is not|is) empty"]), function (selectorName, isIsNot, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getAttribute("value"))
.then((actualText) => {
actualText = actualText || "";
let error = null;
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.test(`[HtmlSteps] Testing: Element value ${isIsNot} empty`);
switch (isIsNot) {
case "is":
if (actualText !== "") {
error = `Expected value to be empty. But it was "${actualText}".`;
}
break;
case "is not":
if (actualText === "") {
error = "Expected value not to be empty.";
}
break;
}
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords (?:textbox|checkbox|dropdown|button|radiobutton) $disabledQualifier",
"the $nonQuotedWord (?:textbox|checkbox|dropdown|button|radiobutton) $disabledQualifier"]), function (selectorName, disabledQualifier, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getAttribute("disabled"))
.then((actualdisabled) => {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.test(`[HtmlSteps] Testing: Element ${disabledQualifier}.`);
let error = null;
switch (disabledQualifier) {
case "is disabled":
case "is not enabled":
if (actualdisabled !== "true") {
error = "Expected element to be disabled.";
}
break;
case "is not disabled":
case "is enabled":
if (actualdisabled !== null) {
error = "Expected element not to be disabled.";
}
break;
}
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords (does not have|has) a css class of $quotedWordOrWords",
"the $nonQuotedWord (does not have|has) a css class of $quotedWordOrWords"]), function (selectorName, qualifier, cssClass, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getAttribute("class"))
.then((actualCssClass) => {
let error = null;
switch (qualifier) {
case "has":
if (actualCssClass.indexOf(cssClass) === -1) {
error = `Expected "${actualCssClass}" to contain "${cssClass}".`;
}
break;
case "does not have":
if (actualCssClass.indexOf(cssClass) !== -1) {
error = `Expected "${actualCssClass}" not to contain "${cssClass}".`;
}
break;
}
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords attribute $quotedWordOrWords value $qualifier $quotedWordOrWords",
"the $nonQuotedWord attribute $quotedWordOrWords value $qualifier $quotedWordOrWords"]), function (selectorName, attributeName, qualifier, expectedValue, next) {
if (attributeName === "name") {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.info('WARNING: Getting the attribute "name" is not supported/broken in webdriver.');
}
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getAttribute(attributeName))
.then((actualAttributeValue) => { next(qualifier_validator_1.QualifierValidator.qualifierValidate(qualifier, actualAttributeValue, expectedValue)); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords (?:textbox|checkbox|dropdown|button|radiobutton) $editableQualifier",
"the $nonQuotedWord (?:textbox|checkbox|dropdown|button|radiobutton) $editableQualifier"]), function (selectorName, editableQualifier, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => htmlElement.getAttribute("readonly"))
.then((actualReadonly) => {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.test(`[HtmlSteps] Testing: Element ${editableQualifier}`);
let error = null;
switch (editableQualifier) {
case "is readonly":
case "is not editable":
if (!actualReadonly) {
error = `Expected element to not be editable.`;
}
break;
case "is not readonly":
case "is editable":
if (actualReadonly !== null) {
error = `Expected element to be editable.`;
}
break;
default:
throw new Error(`[HtmlSteps] qualifier value of "${editableQualifier}" is not supported.`);
}
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords (?:checkbox|radiobutton) (is not checked|is not unchecked|is checked|is unchecked)",
"the $nonQuotedWord (?:checkbox|radiobutton) (is not checked|is not unchecked|is checked|is unchecked)"]), function (selectorName, checkedQualifier, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.isCheckboxChecked(htmlElement))
.then((actualChecked) => {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.test(`[HtmlSteps] Testing: Element ${checkedQualifier}`);
let error = null;
switch (checkedQualifier) {
case "is not checked":
case "is unchecked":
if (actualChecked) {
error = `Expected checkbox element to be unchecked.`;
}
break;
case "is checked":
case "is not unchecked":
if (!actualChecked) {
error = `Expected checkbox element to be checked.`;
}
break;
}
if (error) {
verbosity_level_aware_logger_1.VerbosityLevelAwareConsoleLog.failure(error);
}
next(error);
}, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords dropdown has $qualifierNumerical $NUM (?:option|options)",
"the $nonQuotedWord dropdown has $qualifierNumerical $NUM (?:option|options)"]), function (dropdownSelector, qualifier, quantity, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, dropdownSelector);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.getDropDownOptionLabels(htmlElement))
.then((optionLabels) => { next(qualifier_validator_1.QualifierValidator.qualifierNumericalValidate(optionLabels.length, qualifier, quantity)); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords dropdown option $qualifier $quotedWordOrWords",
"the $nonQuotedWord dropdown option $qualifier $quotedWordOrWords"]), function (dropdownSelector, qualifier, expectedValue, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, dropdownSelector);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.getDropDownSelectedValue(htmlElement))
.then((actualText) => { next(qualifier_validator_1.QualifierValidator.qualifierValidate(qualifier, actualText, expectedValue)); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords dropdown option is blank",
"the $nonQuotedWord dropdown option is blank"]), function (dropdownSelector, next) {
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, dropdownSelector);
return html_actions_1.HtmlActions.getElement(this.context, htmlSelectorDefinition.selector, true)
.then((htmlElement) => html_actions_1.HtmlActions.getDropDownSelectedValue(htmlElement))
.then((selectedOptionText) => { next(qualifier_validator_1.QualifierValidator.qualifierValidate("is", selectedOptionText, "")); }, error => { next(error || new Error("Promise resolution failed with no error details.")); });
});
lib.then(new iskutter_library_1.ThenDefinition([
"the $quotedWordOrWords $visibilityQualifier",
"the $nonQuotedWord $visibilityQualifier"]), function (selectorName, visibilityQualifier, next) {
let expectedToBePresent = visibilityQualifier === "is visible" || visibilityQualifier === "is not hidden";
let htmlSelectorDefinition = definition_finder_1.DefinitionFinder.getDefinition(this.context, selectorName);
let contextCopy = this.context;
html_actions_1.HtmlActions.getElement(contextCopy, htmlSelectorDefinition.selector, expectedToBePresent)
.then((htmlElement) => {
if (htmlElement === null && !expectedToBePresent) {
next();
return;
}
contextCopy.browser.isElementPresent(htmlSelectorDefinition.selector).then((isPresentActual) => {
if (expectedToBePresent && !isPresentActual) {
next("Element is not present to check visibility.");
return;
}
htmlElement.isDisplayed().then((isDisplayedActual) => {
let error = qualifier_validator_1.QualifierValidator.visibilityQualifierValidate(visibilityQualifier, isDisplayedActual);
next(error);
}, (error) => {
if (!expectedToBePresent) {
next();
}
else {
next("Element is not present to check visibility.");
}
});
}, (error) => {
if (!expectedToBePresent) {
next();
}
else {
next("Element is not present to check visibility.");
}
});
}, function elementNotPresent() {
if (!expectedToBePresent) {
next();
}
else {
next("Element is not present to check visibility.");
}
});
});
return lib;
}
}
exports.default = HtmlSteps;