Skip to content

Commit

Permalink
Introduced pre-define variables
Browse files Browse the repository at this point in the history
  • Loading branch information
ariesb committed Jul 19, 2019
1 parent 7e1822d commit 8ad9ad0
Show file tree
Hide file tree
Showing 23 changed files with 504 additions and 80 deletions.
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All you need to know is Gherkin and you can start working and creating automated

## What's New
* Ability to test response JSON Data against JSON Schema (https://json-schema.org/). See example.
* Allow pre-define variable set that can be loaded use within features
* Ability to test response execution time
* New Console Log Outputs

Expand Down Expand Up @@ -385,6 +386,46 @@ Feature: My Schema Check Feature > Login to the system
```

## Pre-define Variable Set
Iin most case we do not want to hard code values in our test and we want to control the value based on certain environment to run it. You can specify pre-defined variable set using a JSON file.

**Pre-defined Staging Environment Variables**
```features/data/uat.variables.json```
```json
{
"host": "www.uat.autokinjs.com",
"username": "autokin"
}
```

For example above is our variable set, and we have 2 key-value that we can use within our test. Using the above anticipated variables, the following can be our test:
```gherkin
Feature: My Feature
As Autokin tester
I want to verify that all API are working as they should
Scenario: Login to the system
Given that a secure endpoint is up at {host}
Given I set Content-Type header to application/json
Given I set the JSON body to
"""
{
"username": "{username}",
"password": "p3dr0"
}
"""
When I POST /login
Then response status code should be 200
Then I keep the value of body path "$.sessionId" as "userSessionToken"
```

In the above example, we can use the variable by using curly braces to enclose our variable name, such as ``{host}``. In the example above, we used the variable as our source for the ``host``, and we also used another variable in the ``username`` as part of the body.

**Specifying pre-define variable in runtime**
```bash
./node_modules/.bin/autokin -e -v ./features/data/uat.variables.json
```



See more [examples](docs/examples).
Expand Down
1 change: 1 addition & 0 deletions bin/autokin
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ program
.option('-t, --tags [tags]', 'Use with --exec to specify which tags to run, example:"@autokin"')
.option('-j, --junit', 'Output result as JUnit format')
.option('-f, --formatter [cucumber-formatter]', 'Use with --exec to specify custom formatter')
.option('-v, --variables [file-path]', 'Use with --exec to specify variable set from json file')
.parse(process.argv);

let _getTags = () => program.tags ? program.tags : undefined;
Expand Down
3 changes: 2 additions & 1 deletion bin/autokin-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
const path = require('path');
const fs = require('fs');

module.exports.default = function ({tags, formatter, junit}) {
module.exports.default = function ({tags, formatter, junit, variables}) {
let formatterPath = path.resolve(__dirname, '../lib/formatter/autokin-formatter');

if (!fs.existsSync('reports')) {
Expand All @@ -18,6 +18,7 @@ module.exports.default = function ({tags, formatter, junit}) {
if (junit) cliOptions = cliOptions.concat([`--format=node_modules/cucumber-junit-formatter:reports/junit.xml`]);
if (formatter) cliOptions = cliOptions.concat([`--format=${formatter}`]);
if (tags) cliOptions = cliOptions.concat(['--tags', `${tags}`]);
if (variables) process.env.AUTOKIN_VARS = variables;

let cli = new (require('cucumber').Cli)({ argv: cliOptions, cwd: process.cwd(), stdout: process.stdout });
new Promise(function (resolve, reject) {
Expand Down
49 changes: 49 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,52 @@
* Autokin
*/
module.exports = require('./lib/autokin');

let vars = {
host: 'demo.habbitzz.com',
default_email: 'phoenixbotengine@gmail.com'
}

function sanitizeJson(obj) {
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
console.log(p, typeof (obj[p]));
if (typeof (obj[p]) == "object") {
obj[p] = sanitizeJson(obj[p]);
} else if (typeof (obj[p]) == "string") {
obj[p] = sanitize(obj[p]);
}

}
}

return obj;
}

function sanitize(pickle) {
return interpolateValues(pickle, vars);
}

function interpolateValues(pickle, variables) {
return pickle.replace(new RegExp("\{([^\{]+)\}", "g"), (match, varName) => {
return variables.hasOwnProperty(varName) ? variables[varName] : '{' + varName + '}';
});
};



console.log(sanitizeJson({
"username": "{default_email}",
"password": "n2V45sQgur21",
"language": "en",
"data": {
a: 1, b: "{host}"
},
"hello": [
"Data String",
{
"more": "object",
"name" : "{missing_var}/{host}"
}
]
}))
40 changes: 20 additions & 20 deletions lib/autokin-rest-steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

const { Before, Given, When, Then } = require("cucumber");
const { expect } = require("chai");
const { RestBuilder, Utils } = require("./autokin");
const { RestBuilder, Utils, Store } = require("./autokin");

const Builder = new RestBuilder();

Expand Down Expand Up @@ -42,7 +42,7 @@ Given("I set {word} header from {string}", function(
keepVariable,
callback
) {
Builder.header(name, Builder.resolve(keepVariable));
Builder.header(name, Store.resolve(keepVariable));
callback();
});

Expand All @@ -68,7 +68,7 @@ Given("I set query parameter {word} from {string}", function(
keepVariable,
callback
) {
Builder.query(name, Builder.resolve(keepVariable));
Builder.query(name, Store.resolve(keepVariable));
callback();
});

Expand All @@ -94,7 +94,7 @@ Given("I set cookie {string} from {string}", function(
keepVariable,
callback
) {
Builder.cookie(name.concat("=").concat(Builder.resolve(keepVariable)));
Builder.cookie(name.concat("=").concat(Store.resolve(keepVariable)));
callback();
});

Expand All @@ -115,7 +115,7 @@ Given(/^I set the bearer token to (.*)$/, function(token, callback) {
Given("I set the bearer token with {string}", function(keepVariable, callback) {
Builder.header(
"Authorization",
"Bearer ".concat(Builder.resolve(keepVariable))
"Bearer ".concat(Store.resolve(keepVariable))
);
callback();
});
Expand Down Expand Up @@ -190,27 +190,27 @@ Then("response status code should not be {int}", function(httpStatusCode) {
});

Then("response header {string} should exist", function(name, callback) {
if (Builder.Response().hasHeader(name)) {
if (Builder.Response().hasHeader(Store.sanitize(name))) {
callback();
} else {
callback("Expected header (" + name + ") is missing.");
callback("Expected header (" + Store.sanitize(name) + ") is missing.");
}
});

Then("response header {string} should not exist", function(name, callback) {
if (!Builder.Response().hasHeader(name)) {
if (!Builder.Response().hasHeader(Store.sanitize(name))) {
callback();
} else {
callback("Expected header (" + name + ") exists.");
callback("Expected header (" + Store.sanitize(name) + ") exists.");
}
});

Then("response header {string} should be {string}", function(name, value) {
expect(Builder.Response().headerValue(name)).to.eq(value);
expect(Builder.Response().headerValue(Store.sanitize(name))).to.eq(Store.sanitize(value));
});

Then("response header {string} should not be {string}", function(name, value) {
expect(Builder.Response().headerValue(name)).to.not.eq(value);
expect(Builder.Response().headerValue(Store.sanitize(name))).to.not.eq(Store.sanitize(value));
});

Then("response body should be valid json", function() {
Expand Down Expand Up @@ -247,10 +247,10 @@ Then("I expect that path {string} from body has value of {string}", function(
path,
value
) {
expect(value).to.eql(
expect(Store.sanitize(value)).to.eql(
Builder.Response()
.Body()
.pathValue(path)
.pathValue(Store.sanitize(path))
);
});

Expand All @@ -261,19 +261,19 @@ Then("I expect that path {string} from body has value of {int}", function(
expect(value).to.eql(
Builder.Response()
.Body()
.pathValue(path)
.pathValue(Store.sanitize(path))
);
});

Then("response body should have path {string}", function(path, callback) {
if (
Builder.Response()
.Body()
.hasPath(path)
.hasPath(Store.sanitize(path))
) {
callback();
} else {
callback("Expected JSON Path (" + path + ") is missing.");
callback("Expected JSON Path (" + Store.sanitize(path) + ") is missing.");
}
});

Expand Down Expand Up @@ -320,7 +320,7 @@ Then("I keep the value of body path {string} as {string}", function(
key,
Builder.Response()
.Body()
.pathValue(path)
.pathValue(Store.sanitize(path))
);
callback();
});
Expand All @@ -330,15 +330,15 @@ Then("I keep the value of header {string} as {string}", function(
key,
callback
) {
Builder.keep(key, Builder.Response().headerValue(name));
Builder.keep(key, Builder.Response().headerValue(Store.sanitize(name)));
callback();
});

Then("I expect that the stored value in {string} is {string}", function(
key,
value
) {
expect(value).to.eql(Builder.resolve(key));
expect(value).to.eql(Store.resolve(Store.sanitize(key)));
});

Then("I expect response data schema complies to {string}", function(
Expand All @@ -349,7 +349,7 @@ Then("I expect response data schema complies to {string}", function(
Builder.Response()
.Body()
.asJSON(),
schemaPath
Store.sanitize(schemaPath)
);
if (schemaErrors.length > 0) {
callback(
Expand Down
41 changes: 26 additions & 15 deletions lib/autokin-restbuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const request = require('request');
const Utils = require('./utilities');
const jp = require('jsonpath');
const diff = require('deep-diff');
const path = require('path');
const colors = require('colors');
const Store = require('./autokin-store');

class Response {
constructor(response) {
Expand Down Expand Up @@ -67,10 +70,19 @@ class Body {

class RestBuilder {
constructor() {
this.storage = {};
this.reqbody = {};
this.cookiejar = request.jar();
this.resp = new Response();

if (process.env.AUTOKIN_VARS) {
try {
const autokinVars = require(path.resolve(process.cwd(), process.env.AUTOKIN_VARS));
Store.merge(autokinVars);
}
catch(error) {
process.stdout.write(colors.red(`Autokin Variables not loaded. Please check file path provided. (${colors.white(process.env.AUTOKIN_VARS)})\n\n`));
}
}
}

reset() {
Expand All @@ -79,46 +91,45 @@ class RestBuilder {
this.resp = null;
}

resolve(variable) {
let data = this.storage[variable];
return data;
}

host(domain, https = true) {
this.reqbody.https = https;
this.reqbody.domain = domain;
this.reqbody.domain = Store.sanitize(domain);
return this;
}

header(name, value) {
this.reqbody.headers = !this.reqbody.headers ? {} : this.reqbody.headers;
this.reqbody.headers[name] = value;
this.reqbody.headers[Store.sanitize(name)] = Store.sanitize(value);
return this;
}

query(name, value) {
this.reqbody.qs = !this.reqbody.qs ? {} : this.reqbody.qs;
this.reqbody.qs[name] = value;
this.reqbody.qs[Store.sanitize(name)] = Store.sanitize(value);
return this;
}

body(body) {
this.reqbody.body = body;
const newBody = Store.sanitizeJson(JSON.parse(body));
this.reqbody.body = JSON.stringify(newBody);
return this;
}

cookie(cookie) {
this.cookiejar.setCookie(request.cookie(cookie), this.reqbody.domain);
this.cookiejar.setCookie(request.cookie(Store.sanitize(cookie)), this.reqbody.domain);
return this;
}

basicAuthentication(username, password) {
username = Store.sanitize(username);
password = Store.sanitize(password);

const auth = Buffer.from(username.concat(':').concat(password)).toString('base64');
return this.header('Authorization', 'Basic ' + auth);
}

keep(key, value) {
this.storage[key] = value;
Store.set(key, value);
return this;
}

Expand All @@ -136,7 +147,7 @@ class RestBuilder {
time: true
};

if(this.reqbody.body) {
if (this.reqbody.body) {
buildProcessArgs['body'] = this.reqbody.body;
}

Expand All @@ -145,7 +156,7 @@ class RestBuilder {

process(uri, callback, method = 'GET') {
let self = this;
request(this.build(uri, method), function (error, response) {
request(this.build(Store.sanitize(uri), method), function (error, response) {
if (error) {
return callback(error);
}
Expand All @@ -154,7 +165,7 @@ class RestBuilder {
callback(null, response);
});
}
}
}

module.exports.RestBuilder = RestBuilder;
module.exports.Response = Response;
Expand Down
Loading

0 comments on commit 8ad9ad0

Please sign in to comment.