I need some help to parameterize my test suites.
I want to create a Json file Suites.json and define suites in this file
module.exports = {
Suites:
Smoke: 'File1.spec.js','File2.spec.js',
Main: 'File1.spec.js','File2.spec.js','File3.spec.js'
}
Now i want to use this Json file in protractor.conf.js
I imported JSON file:
var SuiteFile = require('../Suites.json')
Now if i want to us in my actual Conf file, i am not sure how to use it.
Should i just say:
suites: SuitesFile
Can someone please confirm?
Yes, it is definitely possible to do something like this.
Please refer my blog post for more info
Step 1: Create a js file with suites
module.exports = {
suitesCollection: {
smoke: ['File1.spec.js','File2.spec.js',],
sanity: ['File1.spec.js','File2.spec.js','File3.spec.js'],
demo: ['demo.js']
}
}
Step 2: Import the js file and point the exports.config.suites to use the info from this file
var suitesFile = require('./suites.js');
exports.config = {
suites: suitesFile.suitesCollection,
UPDATE: In case there is a need to use Json feed for suites, please refer below
Step 1: Create a JSON file with Key-Value pairs of suites
{
"smoke": "demo.js,demo2.js",
"sanity": "demo2.js,demo.js,demo3.js",
"demo": "demo.js"
}
Step 2: Import the JSON and edit the config file accordingly. In case you want the suite names also generated, create a custom function to iterate the JSON and build suites
var suitesJson = require('./suites.json');
exports.config = {
suites: {
smoke: suitesJson.smoke.split(","),
sanity: suitesJson.sanity.split(","),
demo: suitesJson.demo.split(",")
},
OR In case you need to completely construct Suites object out of JSON (when you dont even know suite names)
Protractor Config File
var suitesJson = require('./suites.json');
var suitesAll = {}
for(var myKey in suitesJson) {
suitesAll[myKey] = suitesJson[myKey].split(",");
}
exports.config = {
suites: suitesAll,
Related
In the code presented below, I am trying to interact with a database through the use of a js function within the karate framework. The query used to get some data works as expected, likewise auxiliary information is accessible. The same function within the js file can be ran through groovy just fine but seems to explode when ran within karate.
JS Function to be ran in karate through a callSingle():
function() { let dbUser = Java.type('dev.dao.dbUser') return dbUser.getId(karate.properties['username'])
dbUser:
class dbUser {
static Integer getId(String email) {
db.sql.firstRow("select user_id from table.db_user where email = ?", [email]).userId
}
}
Karate-config.js
function fn() {
let config = {
project: karate.properties['vs.project'],
environment: karate.properties['vs.environment'],
baseUrl: karate.properties['vs.baseUrl'],
timeZoneId: karate.properties['vs.timeZoneId'],
env: karate.properties['vs.env'],
proxy: {
...
]
},
demoUserId: 1,
userId: karate.callSingle('classpath:proj/dev/js/dao/getDbUserId.js'),
createDBuid: karate.read('classpath:proj/dev/js/createDBuid.js'),
DBuid: karate.callonce('classpath:proj/dev/js/createDBuid.js')
}
}
Error returned calling the getDbUserId.js:
PolyglotError
<<<<
org.graalvm.polyglot.PolyglotException
com.intuit.karate.core.ScenarioBridge.callSingle(ScenarioBridge.java:243)
com.intuit.karate.core.ScenarioBridge.callSingle(ScenarioBridge.java:187)
.fn(Unnamed:18)
I have test data based on environments. Need to use respecitive environment test data for webservice testing in karate framework.
So I have config file which load variable based on environment. I have edited my feature file as runtime variable to get the path accordingly something like below. It looks I am missing something or might not using right way.
I have kept testdata based on environment in my folders as like below
TestData
|->DEV
|-> applicationFeature_scenorio1_Req.json
|->SIT
|-> applicationFeature_scenorio1_Req.json
|->UAT
|-> applicationFeature_scenorio1_Req.json
|->PROD
|-> applicationFeature_scenorio1_Req.json
Please help me on this how to pick data based on environment.
Config file
dev: {
baseUrl: 'https://applicationsit.company.com',
TestData : 'TestData/DEV'
},
sit: {
baseUrl: 'https://applicationsit.company.com',
TestData : 'TestData/SIT'
},
uat: {
baseUrl: 'https://applicationuat2.company.com',
TestData : 'TestData/UAT'
},
prod: {
baseUrl: 'https://applicationnewprod.company.com',
TestData : 'TestData/PROD'
}
Feature file
Background:
* def testdata = TestData
#smoke #prod
Scenario: This is success scenario
Given url baseUrl
Given path '/cryptoService'
And request read('#(testdata)/applicationFeature_scenorio1_Req.json')
When method POST
Then status 200
* def encryptedPayload = response
Error found in karate
And request read('#(testdata)/applicationFeature_scenorio1_Req.json')
js failed:
>>>>
01: read('#(testdata)/applicationFeature_scenorio1_Req.json')
<<<<
org.graalvm.polyglot.PolyglotException: java.io.FileNotFoundException: /tmp/workspace/application-prod-test/Continous_Testing/KarateConfigDir/#(testdata)/applicationFeature_scenorio1_Req.json (No such file or directory)
- com.intuit.karate.resource.FileResource.getStream(FileResource.java:98)
- com.intuit.karate.core.ScenarioFileReader.readFileAsStream(ScenarioFileReader.java:99)
- com.intuit.karate.core.ScenarioFileReader.readFileAsString(ScenarioFileReader.java:95)
- com.intuit.karate.core.ScenarioFileReader.readFile(ScenarioFileReader.java:53)
- com.intuit.karate.core.ScenarioEngine.lambda$new$0(ScenarioEngine.java:124)
- <js>.:program(Unnamed:1)
The '#(var)' system works only for JSON: https://github.com/karatelabs/karate#rules-for-embedded-expressions
Karate syntax is mostly JS and variables just work normally. With that in mind please make this change:
And request read(testdata + '/applicationFeature_scenorio1_Req.json')
I was trying to find a way to launch all features in Karate testing through maven using an external variable to set up the browser (with a local webdriver or using a Selenium grid).
So something like:
mvn test -Dbrowser=chrome (or firefox, safari, etc)
or using a Selenium grid:
mvn test -Dbrowser=chrome (or firefox, safari, etc) -Dgrid="grid url"
With Cucumber and Java this was quite simple using a singleton for setting up a global webdriver that was then used in all tests. In this way I could run the tests with different local or remote webdrivers.
In Karate I tried different solution, the last was to:
define the Karate config file a variable "browser"
use the variable "browser" in a single feature "X" in which I set up only the Karate driver
from all the other features with callonce to re-call the feature "X" for using that driver
but it didn't work and to be honest it doesn't seem to me to be the right approach.
Probably being able to set the Karate driver from a Javascript function inside the features is the right way but I was not able to find a solution of that.
Another problem I found with karate is differentiating the behavior using a local or a remote webdriver as in the features files they're set in different ways.
So does anyone had my same needs and how can I solve it?
With the suggestions of Peter Thomas I used this karate-config.js
function fn() {
// browser settings, if not set it takes chrome
var browser = karate.properties['browser'] || 'chrome';
karate.log('the browser set is: ' + browser + ', default: "chrome"');
// grid flag, if not set it takes false. The grid url is in this format http://localhost:4444/wd/hub
var grid_url = karate.properties['grid_url'] || false;
karate.log('the grid url set is: ' + grid_url + ', default: false');
// configurations.
var config = {
host: 'http://httpstat.us/'
};
if (browser == 'chrome') {
if (!grid_url) {
karate.configure('driver', { type: 'chromedriver', executable: 'chromedriver' });
karate.log("Selected Chrome");
} else {
karate.configure('driver', { type: 'chromedriver', start: false, webDriverUrl: grid_url });
karate.log("Selected Chrome in grid");
}
} else if (browser == 'firefox') {
if (!grid_url) {
karate.configure('driver', { type: 'geckodriver', executable: 'geckodriver' });
karate.log("Selected Firefox");
} else {
karate.configure('driver', { type: 'geckodriver', start: false, webDriverUrl: grid_url });
karate.log("Selected Firefox in grid");
}
}
return config;
}
In this way I was able to call the the test suite specifying the browser to use directly from the command line (to be used in a Jenkins pipeline):
mvn clean test -Dbrowser=firefox -Dgrid_url=http://localhost:4444/wd/hub
Here are a couple of principles. Karate is responsible for starting the driver (the equivalent of the Selenium WebDriver). All you need to do is set up the configure driver as described here: https://github.com/intuit/karate/tree/master/karate-core#configure-driver
Finally, depending on your environment, just switch the driver config. This can easily be done in karate-config.js actually (globally) instead of in each feature file:
function fn() {
var config = {
baseUrl: 'https://qa.mycompany.com'
};
if (karate.env == 'chrome') {
karate.configure('driver', { type: 'chromedriver', start: false, webDriverUrl: 'http://somehost:9515/wd/hub' });
}
return config;
}
And on the command-line:
mvn test -Dkarate.env=chrome
I suggest you get familiar with Karate's configuration: https://github.com/intuit/karate#configuration - it actually ends up being simpler than typical Java / Maven projects.
Another way is to set variables in the karate-config.js and then use them in feature files.
* configure driver = { type: '#(myVariableFromConfig)' }
Keep these principles in mind:
Any driver instances created by a "top level" feature will be available to "called" features
You can even call a "common" feature, create the driver there, and it will be set in the "calling" feature
Any driver created will be closed when the "top level" feature ends
You don't need any other patterns.
EDIT: there's some more details in the documentation: https://github.com/intuit/karate/tree/develop/karate-core#code-reuse
And for parallel execution or trying to re-use a single browser for all tests, refer: https://stackoverflow.com/a/60387907/143475
I am using the following syntax in karate feature file and it works but I want to add this globally in karate config file so that I don't have to add in all of my feature file individually
* configure proxy = { uri: 'http://xx.xx.xxx.xx:8080', username: 'myuserid', password: 'xxxxxx' }
I need to know how we can add above globally in karate-config.js file
Thanks
The karate documentation is quite comprehensive.
If you have any questions, it's pretty likely to find the answer there or in a related demo .feature file.
From the documentation:
And if you need to set some of these 'globally' you can easily do so using the karate object in karate-config.js - for e.g. karate.configure('ssl', true).
So, I would try to put the following snippet in karate-config.js:
function() {
var config = {
BASE_URL: 'base url one,
BASE_URL2: 'base url two'
};
karate.configure('proxy', { uri: 'http://xx.xx.xxx.xx:8080', username: 'myuserid', password: 'xxxxxx' });
return config;
}
Needless to say, that you can use karate.env property to configure your proxy on the base of your environment.
I need to write multiple tests (e.g. login test, use application once logged in tests, logout test, etc.) and need them all to be in separate files. The issue I run into is after each test, at the beginning of the next test being run, a new browser session start and it is no longer logged in due to the new session, so all my tests will fail except the login test.
So, is there a way to use the same browser session to run all of my tests sequentially without having to duplicate my login code? Sorry if this is a repost but I have searched and researched and not found any answers.
OR, is there a way to chain the test files somehow? Like having one file that you run that just calls all the other test files?
Using this function to chain together files:
extend = function(target) {
var sources = [].slice.call(arguments, 1);
sources.forEach(function (source) {
for (var prop in source) {
target[prop] = source[prop];
}
});
return target;
}
and adding files to this master file like this:
require("./testName.js");
module.exports = extend(module.exports,testName);
and having the test file look like this:
testName = {
"Test" : function(browser) {
browser
// Your test code
}
};
allowed me to have one file that could link all the tests to, and keep the same browser session the entire time. It runs the tests in the order you require them in the master file and if you do not call browser.end() until the last test is finished it will use one browser window for all tests.
Reuse of session is not good idea as you may run tests in different oreder, but
You could place login code into before function or even extract it into custom commands.
Example:
https://github.com/dimetron/backbone_app/blob/master/nightwatch/custom-commands/login.js
1 - In nightwatch config add
"custom_commands_path" : "nightwatch/custom-commands",
2 - Create custom-commands/login.js
exports.command = function(username, password, callback) {
var self = this;
this
.frame(null)
.waitForElementPresent('input[name=username]', 10000)
.setValue('input[name=username]', username)
.waitForElementPresent('input[name=password]', 10000)
.setValue('input[name=password]', password)
.click('#submit');
if( typeof callback === "function"){
callback.call(self);
}
return this; // allows the command to be chained.
};
3 - Test code - Before using .login(user, apssword)
module.exports = {
before: function(browser) {
console.log("Setting up...");
browser
.windowSize('current', 1024, 768)
.url("app:8000/")
.waitForElementVisible("body", 1000)
.login('user', 'password')
},
after : function(browser) {
browser.end()
console.log("Closing down...");
},
beforeEach: function(browser) {
browser
.pause(2000)
.useCss()
},
"Test 1": function(browser) {
browser
.assert.containsText("#div1", "some tex")
.pause(5000);
},
"Test 2": function(browser) {
browser
.assert.containsText("#div2", "some text")
.pause(5000);
}
}