UNPKG

skutter

Version:

Skutter: Opinionated BDD Browser based test framework

394 lines (393 loc) 27.4 kB
"use strict"; 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;