I am currently working on a test automation suite using Selenium, NodeJS, and Gauge framework and I am having a problem with decoupling some steps into a separate file.
I am trying to decouple the step where Selenium will redirect the user to the mentioned URL to another file called common_steps.js as Gauge will complain that the said step is duplicated if I left it in another step implementation (which makes sense).
In the below example, the step * Visit the application under test. and * Close the popup. are used in two separate specifications.
scenario_test_1.spec
# Scenario Specification 1
This file follows markdown syntax. Every heading in this file denotes a scenario.
Every bulleted point denotes a step.
## Create a New Record
tags: tag1, tag2
* Visit the application under test.
* Click the Add New button
* Close the popup.
scenario_test_2.spec
# Scenario Specification 2
This file follows markdown syntax. Every heading in this file denotes a scenario.
Every bulleted point denotes a step.
## Modify existing record
tags: tag1, tag2
* Visit the application under test.
* Click the Modify button
* Close the popup.
Now, when it's time to implement the step implementations of every step, since Visit the application under test. is already implemented once as well as Close the popup. step, Gauge will complain on the scenario_test_2.js that it is already defined (code below)
scenario_test_1.js
"use strict";
const { Builder, Browser, By, until, Key } = require("selenium-webdriver");
const assert = require("assert");
const { Options } = require("selenium-webdriver/edge");
let driver;
beforeSpec(async function () {
const edgeOptions = new Options();
const preferences = {
user_experience_metrics: {
personalization_data_consent_enabled: true,
},
};
edgeOptions.setUserPreferences(preferences);
edgeOptions.excludeSwitches(["enable-logging"]);
edgeOptions.addArguments("InPrivate");
driver = await new Builder().forBrowser(Browser.EDGE).setEdgeOptions(edgeOptions).build();
await driver.manage().setTimeouts({ implicit: parseInt(process.env.test_timeout) });
await driver.manage().window().maximize();
});
step("Visit the application under test.", async function () {
await driver.get(process.env.BASE_URL);
});
step("Click the Add New button", async function() {
await driver.findElement(By.id("addNewButton")).click();
});
step("Close the popup.", async function() {
await driver.findElement(By.id("closeButton")).click();
});
scenario_test_2.js
"use strict";
const { Builder, Browser, By, until, Key } = require("selenium-webdriver");
const assert = require("assert");
const { Options } = require("selenium-webdriver/edge");
let driver;
beforeSpec(async function () {
const edgeOptions = new Options();
const preferences = {
user_experience_metrics: {
personalization_data_consent_enabled: true,
},
};
edgeOptions.setUserPreferences(preferences);
edgeOptions.excludeSwitches(["enable-logging"]);
edgeOptions.addArguments("InPrivate");
driver = await new Builder().forBrowser(Browser.EDGE).setEdgeOptions(edgeOptions).build();
await driver.manage().setTimeouts({ implicit: parseInt(process.env.test_timeout) });
await driver.manage().window().maximize();
});
step("Visit the application under test.", async function () {
await driver.get(process.env.BASE_URL);
});
step("Click the Modify button", async function() {
await driver.findElement(By.id("modifyButton")).click();
});
step("Close the popup.", async function() {
await driver.findElement(By.id("closeButton")).click();
});
Now, the problem is that, if I decouple the Visit the application under test. and Close the popup. step, the test run will look for the variable driver which is undefined. If I decoupled the initialization of the driver from the beforeSpec() function, Gauge will spawn two browsers with both of them not doing anything because of beforeSpec() function.
I want to decouple them and pass the initialized Selenium driver in the step and have the decoupled steps use the driver instance I produced when I called the step in the specification file.
What I have done so far is to transfer the implementation of beforeSpec() to a separate function in a separate file called common_steps.js
common_functions.js
"use strict";
const { Builder, Browser } = require("selenium-webdriver");
const { Options } = require("selenium-webdriver/edge");
async function initializeDriver() {
let driver;
const edgeOptions = new Options();
const preferences = {
user_experience_metrics: {
personalization_data_consent_enabled: true,
},
};
edgeOptions.setUserPreferences(preferences);
edgeOptions.excludeSwitches(["enable-logging"]);
edgeOptions.addArguments("InPrivate");
driver = await new Builder().forBrowser(Browser.EDGE).setEdgeOptions(edgeOptions).build();
await driver.manage().setTimeouts({ implicit: parseInt(process.env.test_timeout) });
await driver.manage().window().maximize();
return driver;
}
exports.initializeDriver = initializeDriver;
common_steps.js
"use strict";
let driver = initializeDriver();
step("Visit the application under test.", async function () {
await driver.get(process.env.BASE_URL);
});
step("Close the popup.", async function() {
await driver.findElement(By.id("closeButton")).click();
});
and then I removed the duplicated steps in the scenario_test_1.js and scenario_test_2.js so when Gauge tries to run, it should just pick up from the corresponding file, but what I get is driver.findElement is not a function and upon checking, driver is null.
How do I make sure that Selenium webdriver initialized per spec is usable and available in other parts of the code?