-
Notifications
You must be signed in to change notification settings - Fork 44
browser.on('disconnect')
hangs when browser is abstracted from JS API #913
Description
Brief summary
After the work done in #910, now the browser lifecycle is handled by our Go implementation based on the VU context and transparently to the end user. That means that the flow of events is as follows:
- Iteration starts and VU context is initialized
- Some interaction is done with the
browser
API which produces the browser initialization (e.g.:browser.newPage()
) - The browser is initialized and stored in the registry
- Iteration ends and VU context is canceled
- browser is closed in response of VU context being done
The problem happens if the test script makes us of browser.on
method. Currently this method only supports the disconnect
event. When calling browser.on('disconnect')
, our implementation will return a promise that will be resolved once the browser is disconnected. Previously this disconnection happened at the end of the test, as browser.close()
was being called explicitly by the end user in the JS code. But now, because the browser.close()
is handled by the Go implementation, away from the scope of the JS test, the promise waits indefinetly due to a deadlock:
- The promise waits for the browser to be closed/disconnected
- The browser waits for the iteration (so the JS code) to finish
We should consider if this functionality brings value given the current implementation. If so, consider implementation options that will allow this functionality at the same time that the restrictions on browser process and browser contexts are fulfilled.
xk6-browser version
OS
Ubuntu 20.04.5 LTS
Chrome version
113.0.5672.126 (Official Build) (64-bit)
Docker version and image (if applicable)
No response
Steps to reproduce the problem
Build a custom k6 binary based on the work done in PR #910 . E.g.:
xk6 build --with github.com/grafana/xk6-browser@b08de58
Run the following test:
import { check } from 'k6';
import { browser } from 'k6/x/browser';
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: {
browser: {
type: 'chromium',
},
},
},
},
thresholds: {
checks: ["rate==1.0"]
}
}
export default function() {
check(browser, {
'should be connected after launch': browser.isConnected(),
});
const handlerCalled = Symbol();
let p = browser.on('disconnected')
// The promise resolve/success handler
.then((val) => {
check(browser, {
'should be disconnected on event': !browser.isConnected(),
});
return handlerCalled;
// The promise reject/failure handler
}, (val) => {
console.error(`promise rejected: ${val}`);
});
p.then((val) => {
check(val, {
'the browser.on success handler should be called': val === handlerCalled,
});
});
check(browser, {
'should be connected before ending iteration': browser.isConnected(),
});
}
Expected behaviour
Considering the previous implementation, a browser.close()
method would be call at the end of the JS test code explicitly, which would make the browser disconnect and resolve the browser.on
promise resolve, making the promise handling function being called and passing the checks.
Actual behaviour
The test hangs.