Codeceptjs: [Question] How to get browser session ID?

Created on 11 Jan 2017  Â·  12Comments  Â·  Source: codeceptjs/CodeceptJS

What are you trying to achieve?

I am trying to migrate a python WebDriver test to a Codeceptjs test. When the test finishes, it posts a link to the suacelabs session like this:

def tearDown(self):
    if is_travis():
        print("Link to your job: https://saucelabs.com/jobs/%s" % self.driver.session_id)
        try:
            if sys.exc_info() == (None, None, None):
                sauce.jobs.update_job(self.driver.session_id, passed=True)
            else:
                sauce.jobs.update_job(self.driver.session_id, passed=False)
        finally:
            self.driver.quit()
    else:
self.driver.close()

Is there an equivalent to self.driver.session_id I can use to get the sessionID in codeceptjs?

Details

  • CodeceptJS version: v0.4.13
  • NodeJS Version: 6.9.2
  • WebDriverIO
question

Most helpful comment

Oh, looks like it returns a promise, not an array as I expected.

_after() {
  return this.helpers['WebDriverIO'].browser.sessions().then((sessions) => {
    // do everything you need
  });
}

All 12 comments

I think you need a custom helper

Run:

codeceptjs gh

to create SauceLabs helper

Then your helper should look like:

class SauceLab extends Helper {

  // after corresponds to teardown in your code
  _after() {
     var sessions = this.helpers['WebDriverIO'].browser.sessions(); 
     var session_id = sessions[0].id;
     // do your stuff
  }
}

Please see webdriverio session reference for session id, as I can be wrong in this part.

It is important to make your helper to be declared before WebDriverIO in codecept.json so this.browser to be available inside _after.

@DavertMik That is probably what I want, but it doesn't seem like anything in my helper is being run. I think I have it in my .conf.js file correctly:

if (process.env.SAUCE_USERNAME) {
  exports.config = {
    "tests": "./*_test.js",
    "timeout": 10000,
    "output": "./output",
    "helpers": {
      "SauceLabsSession": {
        "require": "./saucelabs_helper.js"
      },
      "WebDriverIO": {
        "url": "http://127.0.0.1:5981/apps/_design/bell/MyApp/index.html#login",
        "browser": "Firefox",
        "waitForTimeout": "10000",
        "user": process.env.SAUCE_USERNAME,
        "key": process.env.SAUCE_ACCESS_KEY,
        "host": "ondemand.saucelabs.com",
        "port": "80",
        "sauceConnect": true,
        "desiredCapabilities": {
          "browserName": "firefox",
          "version": "50",
          "platform": "Windows 10",
          "tunnel-identifier": process.env.TRAVIS_JOB_NUMBER,
          "name": "codeceptJS.login_test",
          "build": process.env.TRAVIS_BUILD_NUMBER
        }
      }
    },
    "include": {
      "I": "./steps_file.js"
    },
    "bootstrap": false,
    "mocha": {},
    "name": "tests"
  };
} else {
  exports.config = {
    "tests": "./*_test.js",
    "timeout": 10000,
    "output": "./output",
    "helpers": {
      "WebDriverIO": {
        "url": "http://127.0.0.1:5981/apps/_design/bell/MyApp/index.html#",
        "browser": "firefox",
        "waitForTimeout": "10000"
      }
    },
    "include": {
      "I": "./steps_file.js"
    },
    "bootstrap": false,
    "mocha": {},
    "name": "tests"
  }
}

And my file saucelabs_helper.js:

'use strict';
let Helper = codecept_helper;
class SauceLabsSession extends Helper {


  isevenrunning(fact) {
     console.log("Test");
     this.log("Test");
  }
  // before/after hooks
  _before() {
    // remove if not used
     console.log("Test");
     this.log("Test");
  }

   // after corresponds to teardown in your code
  _after() {
     var sessions = this.helpers['WebDriverIO'].browser.sessions(); 
     var session_id = sessions[0].id;
     // do your stuff
     console.log("Link to your job: https://saucelabs.com/jobs/%s", session_id);
     this.log("Test");

  }

  // add custom methods here
  // If you need to access other helpers
  // use: this.helpers['helperName']

}

module.exports = SauceLabsSession;

Thanks for helping :)

Please run your tests with --verbose flag. This will show you all events and helpers enabled.
If SauceLabsSession works it will be shown that SauceLabsSession._after callback is executed

It doesn't show up:
image

My guess is that env var SAUCE_USERNAME is not defined and the second config part is used.

if (process.env.SAUCE_USERNAME) {

please check it

@DavertMik Thank you for helping me. Sorry I didn't notice that trivial mistake and made you waste your time. It runs now, but the sessionID is undefined, and sessions is "{status: pending}". Any ideas?

$ codeceptjs run tests --steps --verbose
CodeceptJS v0.4.13
Using test root "/home/travis/build/ole-vi/BeLL-Apps/tests"
Login --
   [1] Starting recording promises
   Emitted | suite.before
 > SauceLabsSession._beforeSuite
   [1] Queued | hook SauceLabsSession._beforeSuite()
 > WebDriverIO._beforeSuite
   [1] Queued | hook WebDriverIO._beforeSuite()
 test successful login
   [2] Starting recording promises
   Emitted | test.before
 > SauceLabsSession._before
   [2] Queued | hook SauceLabsSession._before()
 > WebDriverIO._before
   [2] Queued | hook WebDriverIO._before()
   Emitted | test.start ([object Object])
   [2] Queued | amOnPage: /
   [2] Queued | fillField: Login, admin
   [2] Queued | fillField: Password, password
   [2] Queued | click: Sign In
   [2] Queued | waitForText: Set Configurations, 10
   [2] Queued | fire test.passed
   [2] Queued | finish test
Before
   Emitted | step.before (I am on page "/")
 • I am on page "/"
   Emitted | step.after (I am on page "/")
   Emitted | step.before (I fill field "Login", "admin")
 • I fill field "Login", "admin"
   Emitted | step.after (I fill field "Login", "admin")
   Emitted | step.before (I fill field "Password", "password")
 • I fill field "Password", "password"
   Emitted | step.after (I fill field "Password", "password")
   Emitted | step.before (I click "Sign In")
 • I click "Sign In"
   Emitted | step.after (I click "Sign In")
   Emitted | step.before (I wait for text "Set Configurations", 10)
 • I wait for text "Set Configurations", 10
   Emitted | step.after (I wait for text "Set Configurations", 10)
   Emitted | test.passed ([object Object])
 ✓ OK in 17440ms
   Emitted | test.after
 > SauceLabsSession._after
   [2] Queued | hook SauceLabsSession._after()
 > WebDriverIO._after
   [2] Queued | hook WebDriverIO._after()
After
   [3] Starting recording promises
   Emitted | suite.after
 > SauceLabsSession._afterSuite
   [3] Queued | hook SauceLabsSession._afterSuite()
 > WebDriverIO._afterSuite
   [3] Queued | hook WebDriverIO._afterSuite()
   [3] Error | TypeError: Cannot read property 'id' of undefined
   [3] Stopping recording promises
   OK  | 1 passed   // 17s
   Emitted | global.result ([object Object])

Oh, looks like it returns a promise, not an array as I expected.

_after() {
  return this.helpers['WebDriverIO'].browser.sessions().then((sessions) => {
    // do everything you need
  });
}

@DavertMik That works great locally, but when Travis runs it I get an 500 Internal Server Error.

My code:

_after() {
    console.log("After");
    return this.helpers['WebDriverIO'].browser.sessions().then((sessions) => {
      console.log(sessions);
    });
  }

Travis output

Before
   Emitted | step.before (I am on page "/")
 • I am on page "/"
   Emitted | step.after (I am on page "/")
   Emitted | step.before (I fill field "Login", "admin")
 • I fill field "Login", "admin"
   Emitted | step.after (I fill field "Login", "admin")
   Emitted | step.before (I fill field "Password", "password")
 • I fill field "Password", "password"
   Emitted | step.after (I fill field "Password", "password")
   Emitted | step.before (I click "Sign In")
 • I click "Sign In"
   Emitted | step.after (I click "Sign In")
   Emitted | step.before (I wait for text "Set Configurations", 10)
 • I wait for text "Set Configurations", 10
   Emitted | step.after (I wait for text "Set Configurations", 10)
   Emitted | test.passed ([object Object])
 ✓ OK in 16667ms
   Emitted | test.after
 > SauceLabsSession._after
   [2] Queued | hook SauceLabsSession._after()
 > WebDriverIO._after
   [2] Queued | hook WebDriverIO._after()
After
   [3] Starting recording promises
   Emitted | suite.after
 > SauceLabsSession._afterSuite
   [3] Queued | hook SauceLabsSession._afterSuite()
 > WebDriverIO._afterSuite
   [3] Queued | hook WebDriverIO._afterSuite()
  OK  | 1 passed   // 17s
   Emitted | global.result ([object Object])
   [3] Error | Error: 500 Internal Server Error
   [3] Stopping recording promises

The command "codeceptjs run tests --steps --verbose" exited with 0.

Local output

Before
   Emitted | step.before (I am on page "/")
 * I am on page "/"
   Emitted | step.after (I am on page "/")
   Emitted | step.before (I fill field "Login", "admin")
 * I fill field "Login", "admin"
   Emitted | step.after (I fill field "Login", "admin")
   Emitted | step.before (I fill field "Password", "password")
 * I fill field "Password", "password"
   Emitted | step.after (I fill field "Password", "password")
   Emitted | step.before (I click "Sign In")
 * I click "Sign In"
   Emitted | step.after (I click "Sign In")
   Emitted | step.before (I wait for text "Learner", 10)
 * I wait for text "Learner", 10
   Emitted | step.after (I wait for text "Learner", 10)
   Emitted | test.passed ([object Object])
 √ OK in 7971ms

   Emitted | test.after
 > SauceLabsSession._after
   [2] Queued | hook SauceLabsSession._after()
 > WebDriverIO._after
   [2] Queued | hook WebDriverIO._after()
After
   [3] Starting recording promises
   Emitted | suite.after
 > SauceLabsSession._afterSuite
   [3] Queued | hook SauceLabsSession._afterSuite()
 > WebDriverIO._afterSuite
   [3] Queued | hook WebDriverIO._afterSuite()

  OK  | 1 passed   // 8s
   Emitted | global.result ([object Object])
{ state: 'success',
  sessionId: null,
  hCode: 22225068,
  value:
   [ { capabilities: [Object],
       id: 'c944bd29-7379-47c8-9695-a1a8230033a0',
       hCode: 1274997,
       class: 'org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo' },
     { capabilities: [Object],
       id: '86e609b3-290a-4af6-a669-a7c7f44a204a',
       hCode: 9137327,
       class: 'org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo' },
     { capabilities: [Object],
       id: 'a66bd753-3931-4bcc-a5fe-47b56ac2dd5d',
       hCode: 32717890,
       class: 'org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo' },
     { capabilities: [Object],
       id: '3ad15b44-f4e8-4cc0-99d9-3fe1bd19e5d5',
       hCode: 17510288,
       class: 'org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo' },
     { capabilities: [Object],
       id: '20fa0295-eb58-4b3c-9586-5f41844632e1',
       hCode: 3429336,
       class: 'org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo' },
     { capabilities: [Object],
       id: '0ad21a6b-ec8f-4665-b684-0461092c1efa',
       hCode: 29337701,
       class: 'org.openqa.selenium.remote.server.handler.GetAllSessions$SessionInfo' } ],
  class: 'org.openqa.selenium.remote.Response',
  status: 0 }

On the saucelabs archive it says Your test errored. Test did not see a new command for 90 seconds. Timing out. I think node might be crashing for some reason, but I don't know how to find an error log on travis.

Ok, probably sessions() is not what we look for. 2 alternatives ( I didn't try them, so please check)

    1.
var sessionId = this.helpers['WebDriverIO'].browser.requestHandler.sessionID
console.log(sessionId);

2.

var session = this.helpers['WebDriverIO'].browser.session();
console.log(session);

@DavertMik I think sessions is fine, if you look at the local output it had plenty of information in the JSON it outputted when I did console.log(sessions), but that doesn't seem to output anything on Travis CI, which is confusing me. I can try those other things if you want though.

Yes, please try them. Probably they can work better.

@DavertMik
Okay, method 1 worked, method 2 gave me the {status: pending} thing again.

Thank you so much for your help, it really makes me happy to have this working now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Cooryd picture Cooryd  Â·  8Comments

gaurav21r picture gaurav21r  Â·  10Comments

zordius picture zordius  Â·  10Comments

jmitchell89 picture jmitchell89  Â·  15Comments

willhowlett picture willhowlett  Â·  9Comments