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?
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:

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)
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.
Most helpful comment
Oh, looks like it returns a promise, not an array as I expected.