Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Facing issue with defining steps when additional functions involved. #18

Closed
darkhorse93 opened this issue Jul 26, 2018 · 7 comments
Closed

Comments

@darkhorse93
Copy link

darkhorse93 commented Jul 26, 2018

Hi,

I'm a newbie to javascript and nodejs. We have an existing (selenium-webdriver)script which needs to be reworked to fit jest-cucumber BDD style. Created a feature file and tried to modify the scripts to jest-cucumber step def style, but the catch is an additional withWebDriver function as shown below. withWebdriver is needed/used through out the test(jest test code below), but not sure how to divide code to fit given when then, due to the var/obj declarations scope restriction.

Jest Code

describe("...", function () {
  test("Happy Path", withWebDriver(async function (webDriver) {...})
}

Jest-Cucumber:

Doesn't Work
Facing no such (browser)session error here, after the given block.

const appUrl = process.env.HOMEPAGE URL 
let appDriver = null; 
defineFeature(RndHpyPath,test=>{
	test('Happy Path Scenario Test',({given,when,then})=>{
		withWebDriver(asyncfunction(webDriver){
		appDriver=new TGDriver({webDriver,appUrl});//appdriver is used in tests below
		});
		given('Happy Path Scenario Precondition', async () {…})
		when('Happy Path Scenario Action and Condition', async(){…})
		then('Happy Path Scenario Action and Condition Validations', async() {…})
	});
});

This too doesn't work
Facing "Expected step #3 in scenario "Happy Path Scenario" to match "Happy Path Scenario"". Guess this related to feature file to step def mapping, which is disturbed by withWebDriver function.

const appUrl = process.env.HOMEPAGE URL 
let appDriver = null; 
defineFeature(RndHpyPath,test=>{
	test('Happy Path Scenario', ({given,when,then})=>{
		withWebDriver(asyncfunction(webDriver){
                appDriver=new TGDriver({webDriver,appUrl});//appdriver is used in tests below
		given('Happy Path Scenario Precondition', async () {...})
		when('Happy Path Scenario Action and Condition', async(){…})
		then('Happy Path Scenario Action and Condition Validations', async() {…})
		});
	});
});

Is there any way we can fit withWebDriver function to make it work throught out test with (given, when, then) not facing any scope restriction related errors.

Thanks.

@darkhorse93 darkhorse93 changed the title Facing issue with defining steps when additional steps involved. Facing issue with defining steps when additional functions involved. Jul 26, 2018
@darkhorse93
Copy link
Author

@bencompton can you please let us know your comments on the issue. Thanks in Advance.

@bencompton
Copy link
Owner

Hi @darkhorse93, I haven't used Selenium from Node in several months and am not immediately familiar with withWebDriver. I would suggest finding a tutorial with setting up Selenium from Jest, as jest-cucumber shouldn't be that much different. You might try setting up the web driver in a beforeEach and then set it in a variable that is used in all of the tests within a file.

@darkhorse93
Copy link
Author

darkhorse93 commented Aug 1, 2018

Thanks @bencompton for your comment, I've tried setting up a simple project, Selenium WebDriver with Jest-Cucumber, it went fine with no issues. Facing issue when I try to change the (above mentioned)existing script in our project to work with Jest-Cucmber, i.e. withWebDriver function scope issue, not able to put given, when, then under withWebDriver OR if i put withWebDriver in given, the driver created in given is not accessible in following when and then.

withWebDriver is a custom function(to build a webdriver) part of framework, which we wrote and not default with selenium.

Is there anyway that I can call the withWebDriver function and use it through out the given, when, then, unlike beforeEach where the function is called/webdriver(appdriver as in issue) created before every given, when and then's.

It would be great if you can give any other suggestions/workarounds...

@bencompton
Copy link
Owner

@darkhorse93, thanks for clarifying. So the issue seems to be that your withWebDriver function is async, and it looks like you're trying to define the step definitions (given, when, then) asynchronously after withWebDriver completes. While it's perfectly fine to return promises (or use async/await) from your given, when, and then functions, when actually defining your step functions, the process must be completely synchronous. It doesn't work if you wrap the definition of your step functions in an asynchronous callback.

Have you tried something like this?

const appUrl = process.env.HOMEPAGE URL 
let appDriver = null; 
defineFeature(RndHpyPath,test=>{
        beforeEach(async () => {
		await withWebDriver(async function(webDriver) {
		    appDriver=new TGDriver({webDriver, appUrl});
		});
        });

	test('Happy Path Scenario Test',({given,when,then})=>{
		given('Happy Path Scenario Precondition', async () {})
		when('Happy Path Scenario Action and Condition', async(){})
		then('Happy Path Scenario Action and Condition Validations', async() {})
	});
});

This assumes that your withWebDriver function also uses async/await (or returns a promise), and that it waits until the async callback passed into it completes before withWebDriver completes.

@darkhorse93
Copy link
Author

Thanks for the suggesstion @bencompton , but in the suggested beforeEach way, after every given, when, then we are killing the driver, session and creating a new driver. Again i'm aborting the E2E test flow in the middle after every given, when, then and trying to continue from the same page in a different driver and session(assuming i'm getting the getCurrentURL from driver and set it to appUrl) for the beforeEach sake.

@bencompton
Copy link
Owner

So something like this maybe?

const appUrl = process.env.HOMEPAGE URL 
let appDriver = null;

defineFeature(RndHpyPath, test => {
	const initWebDriver = () => {
		await withWebDriver(async (webDriver) => {
			appDriver = new TGDriver({webDriver, appUrl});
		});
	}

	test('Happy Path Scenario Test',({ given, when, then })=>{
		given('Happy Path Scenario Precondition', async () => {
			await initWebDriver();
			
			//Your test code goes here (appDriver will be populated now)
		});

		when('Happy Path Scenario Action and Condition', async () => {
			await initWebDriver();
			
			//Your test code goes here (appDriver will be populated now)
                });

		then('Happy Path Scenario Action and Condition Validations', async() {})
	});
});

jest-cucumber doesn't currently support hooks that fire before and after each step, so this could look nicer if something like this were supported:

const appUrl = process.env.HOMEPAGE URL 
let appDriver = null;

defineFeature(RndHpyPath, test => {
	test('Happy Path Scenario Test',({ given, when, then, beforeEachStep })=>{
                beforeEachStep(async () => {
		    await withWebDriver(async (webDriver) => {
			    appDriver = new TGDriver({webDriver, appUrl});
		    });
                });

		given('Happy Path Scenario Precondition', async () => {
			//Your test code goes here (appDriver will be populated now)
		});

		when('Happy Path Scenario Action and Condition', async () => {
			//Your test code goes here (appDriver will be populated now)
                });

		then('Happy Path Scenario Action and Condition Validations', async() {})
	});
});

@darkhorse93
Copy link
Author

darkhorse93 commented Aug 6, 2018

Thanks @bencompton, the way the tests works is, withWebDriver handles creating a driver, using it and killing it once done or if something goes wrong. Also in above mentioned existing jest scripts, withWebDriver wraps the whole testflow script.

Basic Flow is like jest calls the describe > test(withWebDriver is called) > withWebDriver creates driver > Scripts under test is executed(if any exception, withWebDriver monitoring the whole thing handles and quits webDriver) > withWebDriver quits webDriver once exectuion is done > test is completed > describe is completed

Class of withWebDriver:

class WebDriverEnvironment extends NodeEnvironment {
  constructor(config) {...}
  async setup() {
    await super.setup();
    this.global.withWebDriver = (fn) => { //**Here's the withWebDriver**
      return async () => {
        let failed = false;
        const webDriver = await (this.options.build
          ? this.options.build(new Builder())
          : new Builder()
            .usingServer(this.options.serverUrl)
            .withCapabilities(this.options.capabilities)
            .build());
        try {
          await fn(webDriver);
        } catch (e) {
          failed = true;
          throw e;
        } finally {
          const session = await webDriver.getSession();
          const sessionId = session.getId();
          await webDriver.quit(); //**quits the webdriver finally.**
          if (this.options.serverUrl && this.options.serverUrl.includes("browserstack")) {...BrowserStackCode...}	  
        }
      };
    };
  }
  async teardown() {
    await super.teardown();
  }
  runScript(script) {
    return super.runScript(script);
  }
}

Please excuse me if any of it seems dumb/way to simple concept to understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants