We recommend using the SDK integration over the API because it simplifies integration, reduces required code, and includes features for faster, more reliable development.
โ
In this article, we are going to the discuss the script created to automate the execution of test case and to update the status on the basis of results , for related test case in TestCollab using API.
What is to be done?
We are automating the process of verification of the login feature offered by TestCollab.
How it will be done?
Assumptions
It is being assumed that
The reader has been through the TestCollab API guide accessible at http://developers.testcollab.com
The reader has basic knowledge of using API endpoints (TestCollab or any other REST API)
The key test steps
The application should not allow login through invalid credentials and should show a proper message to user
If correct credentials are provided on login page, user should be allowed access to the application by showing him/her the tasks page (this is the page shown by default after login)
Pre-requisites
A testcase created in TestCollab that needs to be automated
One or more test plans that are created to test the functionality with concerned testcase assigned to a user
Values expected
Id of the project that has the testcase to be automated
Id of the concerned testcase
A valid API token of the TestCollab user who has been assigned the testcase
The code
login is the function that does the main job of testing.
While login does the main task of verification, other sections of code take care of
Fetching the correct testplantestcases that are created for testcase whose id is provided
Looping through testplantestcases, it fetches the testplanregressions (test plan RUNs)
Then for each RUN list of concerned executedtestcases records are fetched
With all required information from the application the login function is then invoked
If the status returned by login is same as the status already set for executedtestcase record then the executedtestcase status is set to unexecuted
The executedtestcase record is then updated to have status as per the results of automation
The snippet below uses javascript. Selenium and XHR libraries are mainly required.
Here, Google Chrome is used to run the automated script, you can use other browser; that may require some changes in part of code that is used to find UI element and perform actions on it.
const { Builder, By, Key, until } = require('selenium-webdriver')
const assert = require('assert');
const { elementIsVisible } = require('selenium-webdriver/lib/until');
const { WebDriver } = require('selenium-webdriver');
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const console = require('console');
async function login() {
let driver = await new Builder().forBrowser("chrome").build();
try {
const TIMEOUT = 10000
await driver.manage().setTimeouts({ implicit: TIMEOUT, pageLoad: TIMEOUT, script: TIMEOUT })
await driver.get("https://testcollab.io/login")
await driver.manage().window().setRect({ width: 750, height: 750 })
await driver.findElement(By.id("normal_login_userName")).click()
await driver.findElement(By.id("normal_login_userName")).sendKeys("vishal+st2022ent@gigapromoters.com")
await driver.findElement(By.id("normal_login_password")).sendKeys("abcd1234")
await driver.findElement(By.css(".btn-success")).click()
await driver.wait(until.elementIsVisible(driver.findElement(By.css(".ant-notification-notice-message"))), 10000);
await driver.findElement(By.css(".ant-notification-notice-message")).click()
assert(await driver.findElement(By.css(".ant-notification-notice-message")).getText() == "Identifier or password invalid.")
await driver.findElement(By.css(".anticon-close > svg")).click()
await driver.findElement(By.id("normal_login_password")).click()
await driver.findElement(By.id("normal_login_password")).clear()
await driver.findElement(By.id("normal_login_password")).sendKeys("abcd12345")
await driver.findElement(By.css(".btn-success")).click()
await driver.executeScript("window.scrollTo(0,0)")
await driver.findElement(By.css(".page-title")).click()
await assert(await driver.findElement(By.css(".page-title")).getText() == "My Tasks")
await driver.findElement(By.css(".white_wrapper")).click()
await driver.findElement(By.css(".UserAvatar--inner")).click()
await driver.findElement(By.partialLinkText("Logout")).click()
driver.close()
return 1;
}
catch (e) {
console.log(e)
driver.close()
return 2;
}
}
let project_id = 8;
let testcase_id = 1;
let api_token = 'sOm3D4mM4491';
let xhr = new XMLHttpRequest();
let url = new URL('https://api.testcollab.io/users/me');
url.searchParams.set('token', api_token);
let xhrBody = null;
let assignee_id = null;
try {
xhr.open("GET", url);
xhr.timeout = 10000;
xhr.responseType = 'json';
xhr.send(xhrBody);
xhr.onload = function () {
if (xhr.status != 200) {
console.log(`xhr Error ${xhr.status}: ${xhr.statusText}`);
} else {
const obj = JSON.parse(xhr.responseText);
assignee_id = obj["id"];
let xhr2 = new XMLHttpRequest();
url = new URL('https://api.testcollab.io/testplantestcases');
url.searchParams.set('token', api_token);
url.searchParams.set('project', project_id);
url.searchParams.set('test_case', testcase_id);
url.searchParams.set('_sort', 'ID:DESC');
xhrBody2 = null;
try {
xhr2.open("GET", url);
xhr2.timeout = 10000;
xhr2.responseType = 'json';
xhr2.send(xhrBody2);
xhr2.onload = function () {
if (xhr2.status != 200) {
console.log(`xhr2 Error ${xhr2.status}: ${xhr2.statusText}`);
} else {
const obj = JSON.parse(xhr2.responseText);
obj.forEach(testplantestcase => {
if (testplantestcase["testplan"]["id"] !== undefined) {
let testplantestcase_id = testplantestcase["id"];
let testplan_id = testplantestcase["testplan"]["id"];
let xhr3 = new XMLHttpRequest();
url = new URL('https://api.testcollab.io/testplanregressions');
url.searchParams.set('token', api_token);
url.searchParams.set('project', project_id);
url.searchParams.set('testplan', testplan_id);
url.searchParams.set('_limit', 1);
url.searchParams.set('_sort', 'ID:DESC');
xhrBody3 = null;
try {
xhr3.open("GET", url);
xhr3.timeout = 10000;
xhr3.responseType = 'json';
xhr3.send(xhrBody3);
xhr3.onload = function () {
if (xhr3.status != 200) {
console.log(`xhr3 Error ${xhr3.status}: ${xhr3.statusText}`);
} else {
const obj = JSON.parse(xhr3.responseText);
obj.forEach(testplanregressions => {
if (testplanregressions["id"] !== undefined) {
let regression_id = testplanregressions["id"];
let xhr4 = new XMLHttpRequest();
url = new URL('https://api.testcollab.io/executedtestcases');
url.searchParams.set('token', api_token);
url.searchParams.set('project', project_id);
url.searchParams.set('regression', regression_id);
url.searchParams.set('assigned_to', assignee_id);
url.searchParams.set('test_plan_test_case', testplantestcase_id);
url.searchParams.set('_sort', 'ID:DESC');
xhrBody4 = null;
try {
xhr4.open("GET", url);
xhr4.timeout = 10000;
xhr4.responseType = 'json';
xhr4.send(xhrBody4);
xhr4.onload = async function () {
if (xhr4.status != 200) {
console.log(`xhr4 Error ${xhr4.status}: ${xhr4.statusText}`);
} else {
const obj = JSON.parse(xhr4.responseText);
obj.forEach(executedtestcase => {
if (executedtestcase["id"] !== undefined) {
login().then((testcase_status) => {
let executabletestcase_id = executedtestcase["id"];
let testplanconfig_id = ((executedtestcase["test_plan_config"] !== undefined && executedtestcase["test_plan_config"] !== null) ? executedtestcase["test_plan_config"]["id"] : null);
let prev_status = executedtestcase["status"];
if (prev_status == testcase_status) {
//if previous executed test case status is same as current status then in order to write new execution log we need to mark it as unexecuted
let xhr6 = new XMLHttpRequest();
url = new URL('https://api.testcollab.io/executedtestcases/' + executabletestcase_id);
url.searchParams.set('token', api_token);
let xhrBody5 = {
"project": project_id,
"status": 0,
"_comment1": "Resetting the status to unexecuted before adding new execution log",
"test_plan_config": testplanconfig_id
};
try {
xhr6.open("PUT", url);
xhr6.timeout = 10000;
xhr6.responseType = 'json';
xhr6.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr6.send(JSON.stringify(xhrBody5));
xhr6.onload = function () {
if (xhr6.status != 200) {
console.log(`xhr6 Error ${xhr6.status}: ${xhr6.statusText}`);
} else {
const obj = JSON.parse(xhr6.responseText);
console.log("Resetting testcase status");
let xhr5 = new XMLHttpRequest();
url = new URL('https://api.testcollab.io/executedtestcases/' + executabletestcase_id);
url.searchParams.set('token', api_token);
let xhrBody5 = {
"project": project_id,
"status": testcase_status,
"_comment1": "Optional",
"test_plan_config": testplanconfig_id
};
try {
xhr5.open("PUT", url);
xhr5.timeout = 10000;
xhr5.responseType = 'json';
xhr5.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr5.send(JSON.stringify(xhrBody5));
xhr5.onload = function () {
if (xhr5.status != 200) {
console.log(`xhr5 Error ${xhr5.status}: ${xhr5.statusText}`);
} else {
const obj = JSON.parse(xhr5.responseText);
console.log("Done");
}
};
xhr5.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr5.onerror = function () {
console.log("xhr5 Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
}
};
xhr6.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr6.onerror = function () {
console.log("xhr6 Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
} else {
let xhr5 = new XMLHttpRequest();
url = new URL('https://api.testcollab.io/executedtestcases/' + executabletestcase_id);
url.searchParams.set('token', api_token);
let xhrBody5 = {
"project": project_id,
"status": testcase_status,
"_comment1": "Optional",
"test_plan_config": testplanconfig_id
};
try {
xhr5.open("PUT", url);
xhr5.timeout = 10000;
xhr5.responseType = 'json';
xhr5.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr5.send(JSON.stringify(xhrBody5));
xhr5.onload = function () {
if (xhr5.status != 200) {
console.log(`xhr5 Error ${xhr5.status}: ${xhr5.statusText}`);
} else {
const obj = JSON.parse(xhr5.responseText);
console.log("Done");
}
};
xhr5.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr5.onerror = function () {
console.log("xhr5 Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
}
});
}
})
}
};
xhr4.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr4.onerror = function () {
console.log("xhr4 Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
}
})
}
};
xhr3.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr3.onerror = function () {
console.log("xhr3 Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
}
})
}
};
xhr2.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr2.onerror = function () {
console.log("xhr2 Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
}
};
xhr.onprogress = function (event) {
if (event.lengthComputable) {
console.log(`Received ${event.loaded} of ${event.total} bytes`);
} else {
console.log(`Received ${event.loaded} bytes`);
}
};
xhr.onerror = function () {
console.log("xhr Request failed");
};
}
catch (e) {
console.log("Caught " + e);
}
Next step
Step wise results are not being set, this can be done by setting JSON for individual step of test case having step index , step , expected result , status, comment, mentions and attachments etc.
Please send your queries, concerns and feedback to support@testcollab.com