Blog

Embracing CodeceptJS

07 May, 2020
Xebia Background Header Wave

One of our clients who tasted success with test automation of legacy desktop application approached us with requirement to automate a web-based application. However, they have one condition that we use CodeceptJS as test automation tool.

Even though we were given a condition to automate with CodeceptJS, still we started to do a POC to check if we can automate using CodeceptJS.

To our surprise codeceptJS is a cool tool with following features

  1. Scenario Driven
  2. Easily readable code
  3. It can run test using WebDriver, Puppeteer, TestCafe, Protractor, Appium
  4. It can automate Web and Mobile applications.
  5. It has good integrations to Allure and Mochasome reports and lot of other cool stuff.

So, after learning some interesting stuff about CodeceptJS we continued with our POC.

Some of the checkpoints which we kept for ourselves are

  1. Can we control all the components across our application?
  2. Can we run DB queries?
  3. Can we perform data driven tests?
  4. Can we run tests parallelly?
  5. Can it support BDD?
  6. Can we automate api tests?
  7. Can we generate readable reports?
  8. Can we do continuous integration?
  9. Can we run a subset of tests from whole regression tests?
  10. Can we read, send emails.
  11. What if codeceptJS does not have native codeceptjs function for some actions which we intended to use?

So, for all the above question lets see how we have answered with sample code!!!

1. Can we control all the components across our application?

Control TypeReading data from controlWriting/Modifying data into controlRead properties of the fieldAutomatable (Yes/No)
CheckBoxI.seeCheckboxIsChecked();I.checkOption(); I.grabValueFrom() Yes
I.dontSeeCheckboxIsChecked();I.click()
Radio Button I.seeCheckboxIsChecked();I.checkOption();  I.grabValueFrom() Yes
I.dontSeeCheckboxIsChecked();I.click()
Dropdown I.grabAttributeFrom() I.selectOption(locator,value); I.grabAttributeFrom() Yes
I.waitForText()I.waitForText()
Search button I.grabAttributeFrom() I.fillField()  I.grabAttributeFrom() yes
I.clearField()
Button I.grabTextFrom() N/A yes
I.grabAttributeFrom()I.grabAttributeFrom()
I.executeScript(function() {I.executeScript(function() {
// javascript code to read/write/execute// javascript code to read/write/execute
});});
Date Picker I.grabValueFrom() I.fillField()  I.grabAttributeFrom()Yes
I.clearField()
input fieldI.fillField()I.grabAttributeFrom() Yes
I.grabAttributeFrom()I.clearField()I.executeScript(function() {
I.executeScript(function() {// javascript code to read/write/execute
// javascript code to read/write/execute});
});
TableI.grabTextFrom()Normally not done but added in a dialog. I.grabAttributeFrom() Yes
file(upload/download) N/A I.attachFile() //for upload N/A Yes
I.click() //for download
link buttonI.grabTextFrom(element locator); I.click(element locator)I.grabAttributeFrom(locator,attribute); Yes
form (to fill extra fields) I.grabAttributeFrom() I.fillField()I.grabAttributeFrom() Yes
I.clearField()
I.click()
Alert popup N/AacceptPopup() N/A Yes
cancelPopup()
Tooltip(Mouse hover)  I.grabAttributeFrom() I.grabAttributeFrom() Yes

From the above, we can conclude at least we could automate most of the components which are used across application.

2. Can we run DB queries?

To make a connection:         

const database: SQLDatabase = initSqlServer();

export = database;

function initSqlServer(): SQLDatabase {

const sqlServer = require(‘./SqlServer’);

sqlServer.init({

server: TestConfig.database.server || ‘localhost’,

port: TestConfig.database.port || 1433,

database: TestConfig.database.database || ‘Test’,

user: TestConfig.database.user || ‘sa’,

password: TestConfig.database.password,

});

For Oracle connection use oracle.init and require(‘./oracle’)

 Execute the supplied (INSERT, UPDATE or DELETE) statement:

execute(statement: string): Promise<number> {

return new Promise((resolve, reject) => {

mssql

.connect(this.config)

.then((connection: any) => {

connection

.request()

.query(statement)

.then((result: number) => {

mssql.close();

resolve(result);

})

.catch((err: any) => {

mssql.close();

reject(err);

});

})

.catch((err: any) => {

reject(err);

});

});

}

Similar functions will be written for Executes the supplied query, Execute the supplied query that should result in a single value, Gets the meta data for the columns of the supplied table.

Example:

await database.execute(UPDATE test SET url='${prefix}${postfix}');

3. Can we perform data driven tests?

Yes, we have created data sets in JSON and we read the dataset in our code to work on data driven tests.

import { Pageobject } from ‘./pageobjects;

const data = JSON.parse(fs.readFileSync(actualFilePath).toString());

const PO = new Pageobject(); /* Page Object */

Data(data.users).Scenario(‘Test authenticator @regression, (I: CodeceptJS.I, current: any) => {

I.amOnPage(‘current.url’)

I.fillField(PO.Username, current.name);

I.fillField(PO.Password, secret(current.password));   /* Click on login button */

I.click(PO.submit);

}

4. Can we run tests parallelly?

Yes, we can always run them in chunks. We also can run them on multiple browsers

multiple: {

parallel: {

// Splits tests into 2 chunks

chunks: 2

}

}

5. Can it support BDD?

Yes, with help of Gherkin integration

Given(/I have product with $(d+) price/, (product) => {

I.amOnPage(‘/products’);

I.selectoption(productcode, product);

I.click(‘Add to cart’);

});

When(‘I go to checkout process’, () => {

I.click(‘Checkout’);

});

Then(‘I should see that total number of products is {int}’, (Value) => {

I.see(Value, ‘.cart’);

});

Then(‘my order amount is ${int}’, (total) => {

I.see(‘Total: ‘ + Total);

});

6. Can we automate api tests?

This is our favorite part, where it proves that we can automate api testing. According to codeceptJS developer it is meant for automation of rest api’s.  However, we were able to do automation of SOAP calls using third party npm packages integrated to our framework.

Scenario(‘@api_001 test POC’, async (I) => {

let res = await I.sendPostRequest(data.baseUrl, body)

let expectedResponse = expectedData.api001

I.assertEqual(await I.grabValueByXmlTagName(res, “Test1”), expectedResponse.melding);

I.assertEqual(await I.grabValueByXmlTagName(res, “Test2”), expectedResponse.succes);

})

7. Can we generate readable reports?

Codeceptjs have integration to allure reporting, and other reporting options like Mochawesome, cli, xml reports etc…

Sample Mochawesome Report:

Sample Allure Report

8. Can we do continuous integration?

Codeceptjs gives us flexibility to integrate with git, Jenkins, TeamCity and Code Fresh

Below is sample screenshot for Jenkins Integration.

9. Can we run a subset of tests from whole regression tests?

Yes, with the help of tags in the tests we can run module wise, whole regression suite, or smoke tests or combination of tests

Ex: –grep ‘(?=.@regression)(?=.@smoke3)’

10. Can we read, send emails?

We can read and send emails from mails slurp, however mail slurp account is paid account for some of the features. However, we used help of mailhog to intercept email communication from our application.

import { MailhogClient, Email } from ‘mailhog-awesome’;

import { MailHog } from “../../../common/util/MailHog”;

const mailClient = new MailhogClient({});

async getEmailContext() {

let emailText: string

return await new Promise<string>((resolve, reject) => {

// wait for 60 second for executing below method from the start of executing the call method.

setTimeout(async function () {

let email = await mailClient.getLastEmail();

if (email != undefined) {

let lastEmail = (email.html)       emailText = lastEmail.replace(/<[^>]+>|r|n|s/ig, ”)

} else throw “Url not found”;

resolve(emailText)

}, 60000);

});

}

11. What if codeceptJS does not have native codeceptjs function for some actions which we intended to use?

We always refer npm packages, native protractor functions and javascript during these situations, for example in the above example we have mailhog help to read emails

So, is it all cake walk with codeceptjs?

Absolutely not, as sometimes the functions of codeceptjs will not work as we intended them to. For example, smartwait option did not work for us, the way it was intended to, so we must prepare a whole new wrapper with protractor native commands. Synchronization of Javascript with codeceptjs.

Did we work before on codeceptjs?

In simple words, no. However, we at CoMakeIT hire people who can work on any tool, and any scripting language. We make it done. This is one of the secrets for our success.

Balaji Tunuguntla
Project Lead in coMakeIT
Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts