Git Product home page Git Product logo

servicenow-selenium-test-runner's Introduction

ServiceNow Selenium Test Runner

This is a maven project to run browser tests for ServiceNow. It supports running tests in SauceLabs, or natively on your machine. If you want to run browsers other than Firefox on your machine, you will need to download the appropriate drivers and either add them to the classpath or update the pom.xml file with the location. You will also need the Java 8 sdk installed, because some of the helper methods use its Date API.

Operate your tests in the command line by entering the following command in the base directory of your project:


mvn clean test -Dpassword="yourpassword" -Denvironment="yourenvironment"

An example class and test are included. The test uses the PageObject and PageFactory pattern.

I've created an update set, which is also in this repo, that contains Script Includes, Scheduled Jobs and a table to generate the appropriate locators in Java, Javascript, C#, Ruby and Python. Install the update set and run the job. (By default it runs some time in the afternoon.) To change what language you want the classes to be, change one of the system properties that came with the update set. The same thing applies to whether you prefer camel case variables or ones with underscores.

If you would rather avoid installing an update set, use the following script (with appropriate arguments) in background scripts:


function getTableVariables(tableName){
	var gr = new GlideRecord('sys_dictionary');
	gr.addEncodedQuery('nameIN' + tableName + ',task^element!=sys_id');
	gr.query();
	while (gr.next()){
		if (gr.internal_type.getDisplayValue() == "Reference"){
			gs.log("@FindBy(id=\"sys_display." + tableName + "." + gr.element + "\")\npublic WebElement " + gr.element + ";");
		} else if (gr.internal_type == "boolean"){
			gs.log("@FindBy(id=\"ni." + tableName + "." + gr.element + "\")\npublic WebElement " + gr.element + ";");
		} else{
			gs.log("@FindBy(id=\"" + tableName + "." + gr.element + "\")\npublic WebElement " + gr.element + ";");
		}
			gs.log("@FindBy(id=\"status." + tableName + "." + gr.element + "\")\npublic WebElement " + gr.element + "Span;\n");
	}
}

Copy the output into a text editor, and replace the "*** Script: " with "". Now you have java variables for the input fields and status spans for each element. Reference fields have to have sys_display appended to the id. ServiceNow generates a tablename.element input, however, it is not editable on the screen. Sometimes, using reference fields can cause an error, so be cautious when writing statements to send text to those elements.

If you are creating a page object for page that extends something other than task (cmdb_ci, for instance), adjust the script accordingly. We exclude the sys_id, because that should be manually generated with the following @FindBy code:


@FindBy(id = "sys_uniqueValue")
public WebElement sysId;

ServiceCatalog items are a bit different. I have my Service Catalog Item classes extend the Requested Item (Sc_Req_Item) class, since once ordered the page object needs those fields. Modify and use the following script to get the variables:


function getServiceCatalogVariables(){
	var gr = new GlideRecord('item_option_new');
	gr.addEncodedQuery('typeNOT IN19,20');
	//add a query for the catalog item or variable set here
	gr.query();
	while (gr.next()){
	if (gr.type.getDisplayValue() == "Reference"){
		gs.log("@FindBy(id=\"sys_display.IO:" + gr.sys_id + "\")\npublic WebElement " + gr.name + ";\n");
	} else if (gr.type.getDisplayValue() == "CheckBox"){
		gs.log("@FindBy(id=\"ni.IO:" + gr.sys_id + "\")\npublic WebElement " + gr.name + ";\n");
	} else if (gr.type.getDisplayValue() == "Multiple Choice" || gr.type.getDisplayValue() == "Lookup Multiple Choice"){
		gs.log("@FindAll({@FindBy(name=\"IO:" + gr.sys_id + "\")})\npublic List<WebElement> " + gr.name + ";\n");
	} else {
		gs.log("@FindBy(id=\"IO:" + gr.sys_id + "\")\npublic WebElement " + gr.name + ";\n");
	}
		gs.log("@FindBy(id=\"status.IO:" + gr.sys_id + "\")\npublic WebElement " + gr.name + "Span;\n");
}
}

Now you can use Selenium to easily interact with elements.

The following script will take any UI Policies and turn them into assertions. It will even look through the conditional scripts (if any) to get the g_form statements and make them assertions.


function uiPoliciesForTable(tableName){
	var policy = new GlideRecord('sys_ui_policy');
	policy.addQuery('table', tableName);
	policy.addActiveQuery();
	policy.query();
	while(policy.next()){
		var actions = new GlideRecord('sys_ui_policy_action');
		actions.addQuery('ui_policy', policy.sys_id);
		actions.query();
		gs.log("/**Assertions for UI Policy: " + policy.short_description );
		gs.log(" * When: " + policy.conditions);
		gs.log(" */");
		gs.log("public void assertFor" + policy.short_description.replace(/\s/g, "") + "() {");
		while (actions.next()){
			if (actions.disabled == "true"){
				gs.log("assertTrue(\"" + actions.field + " should be read-only\", isReadOnly(" + actions.field + "Span));");
			} else if (actions.disabled == "false"){
				gs.log("assertTrue(\"" + actions.field + " should not be read-only\", !isReadOnly(" + actions.field + "Span));");
			}
			if (actions.mandatory == "true"){
				gs.log("assertTrue(\"" + actions.field + " should be mandatory\", isMandatory(" + actions.field + "Span));");
			} else if (actions.mandatory == "false"){
				gs.log("assertTrue(\"" + actions.field + " should be mandatory\", !isMandatory(" + actions.field + "Span));");
			}
			if (actions.visible == "true"){
				gs.log("assertTrue(\"" + actions.field + " should be displayed\", " + actions.field + ".isDisplayed());");
			} else if (actions.visible == "false"){
				gs.log("assertTrue(\"" + actions.field + " should not be displayed\", !" + actions.field + ".isDisplayed());");
			}
		}
		if (policy.run_scripts == true){
			gs.log("//ON TRUE SCRIPTS");
			parseConditionalScript(policy.script_true);
			gs.log("//ON FALSE SCRIPTS");
			parseConditionalScript(policy.script_false);
		}
		gs.log("\n}\n");
	}

	function parseConditionalScript(script){
		var regexMandatory = /g_form\.setMandatory\((.*),(.*)\)/g
		var match = regexMandatory.exec(script);
		while (match != null){
			if (match.toString().indexOf('true') > -1){
				if (match.toString().indexOf('ReadOnly') > -1 || match.toString().indexOf('Disabled') > -1){
					gs.log("assertTrue(\"" + match[1].replace(/'/g, "") + " should be read-only\", isReadOnly(" + match[1].replace(/'/g, "") + "Span));");
				} else if (match.toString().indexOf('Mandatory') > -1){
					gs.log("assertTrue(\"" + match[1].replace(/'/g, "") + " should be mandatory\", isMandatory(" + match[1].replace(/'/g, "") + "Span));");
				} else if (match.toString().indexOf('Visible') > -1){
					gs.log("assertTrue(\"" + match[1].replace(/'/g, "") + " should be visible\", " + match[1].replace(/'/g, "") + ".isDisplayed());");
				}			
			} else {
				if (match.toString().indexOf('ReadOnly') > -1 || match.toString().indexOf('Disabled') > -1){
					gs.log("assertTrue(\"" + match[1].replace(/'/g, "") + " should not be read-only\", !isReadOnly(" + match[1].replace(/'/g, "") + "Span));");
				} else if (match.toString().indexOf('Mandatory') > -1){
					gs.log("assertTrue(\"" + match[1].replace(/'/g, "") + " should not be mandatory\", !isMandatory(" + match[1].replace(/'/g, "") + "Span));");
				} else if (match.toString().indexOf('Visible') > -1){
					gs.log("assertTrue(\"" + match[1].replace(/'/g, "") + " should be visible\", !" + match[1].replace(/'/g, "") + ".isDisplayed());");
				}
			}
			match = regexMandatory.exec(script);		
		}
	}
}

The following script will take Client Scripts and look for any g_form statements that alter fields


function createClientScriptAssertions(tableName){
	var gr = new GlideRecord('sys_script_client');
	gr.addQuery('table', tableName);
	gr.addActiveQuery();
	gr.query();
	while (gr.next()){
		gs.log("/**Assertions for UI Policy: " + gr.name );
		gs.log(" * ");
		gs.log(" */");
		gs.log("public void assertFor" + gr.name.replace(/\s/g, "") + "() {");
		parseConditionalScript(gr.script);
		gs.log("}\n");
	}
	
	function parseConditionalScript(script){
	var regexMandatory = /g_form\.(setMandatory|setReadOnly|setVisible|setDisabled|showFieldMsg|showErrorBox)\((.*),(.*)\)/g
	var match = regexMandatory.exec(script);
	while (match != null){
		if (match.toString().indexOf('true') > -1){
			if (match.toString().indexOf('ReadOnly') > -1 || match.toString().indexOf('Disabled') > -1){
				gs.log("assertTrue(\"" + match[2].replace(/'/g, "") + " should be read-only\", isReadOnly(" + match[2].replace(/'/g, "") + "Span));");
			} else if (match.toString().indexOf('Mandatory') > -1){
				gs.log("assertTrue(\"" + match[2].replace(/'/g, "") + " should be mandatory\", isMandatory(" + match[2].replace(/'/g, "") + "Span));");
			} else if (match.toString().indexOf('Visible') > -1){
				gs.log("assertTrue(\"" + match[2].replace(/'/g, "") + " should be visible\", " + match[2].replace(/'/g, "") + ".isDisplayed());");
			}			
		} else if (match.toString().indexOf('false') > -1) {
			if (match.toString().indexOf('ReadOnly') > -1 || match.toString().indexOf('Disabled') > -1){
				gs.log("assertTrue(\"" + match[2].replace(/'/g, "") + " should not be read-only\", !isReadOnly(" + match[2].replace(/'/g, "") + "Span));");
			} else if (match.toString().indexOf('Mandatory') > -1){
				gs.log("assertTrue(\"" + match[2].replace(/'/g, "") + " should not be mandatory\", !isMandatory(" + match[2].replace(/'/g, "") + "Span));");
			} else if (match.toString().indexOf('Visible') > -1){
				gs.log("assertTrue(\"" + match[2].replace(/'/g, "") + " should be visible\", !" + match[2].replace(/'/g, "") + ".isDisplayed());");
			}
		} else if (match.toString().indexOf('showFieldMsg') > -1 || match.toString().indexOf('showErrorBox') > -1){
			gs.log("assertEquals(\"" + match[2] + "\", driver.fineElement(By.cssSelector(\"div.outputmsg_info\")).getText());");
		}
		match = regexMandatory.exec(script);
	}
}
}

servicenow-selenium-test-runner's People

Contributors

jmbauguess avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.