sitespeedio / sitespeed.io

sitespeed.io is an open-source tool for comprehensive web performance analysis, enabling you to test, monitor, and optimize your website’s speed using real browsers in various environments.
https://www.sitespeed.io/
MIT License
4.72k stars 601 forks source link

When trying to run a function that is imported from a class from a separate file, a browser session cannot be succesfully initiated #3662

Closed monika-pietrosian closed 2 years ago

monika-pietrosian commented 2 years ago

Have you read the documentation?

URL

www.google.com

What are you trying to accomplish

When trying to run a function that is imported from a separate file, there is an error while using the methods that are imitating the browser, like context.selenium.driver.get('https://www.google.com') orcommands.navigate('https://www.google.com');. Other commands, like context.log.info or commands.wait.byTime get recognized and don't cause error. In both of the cases, session doesn't get initiated.

Since this option is mentioned in the documentation I assume it should be possible: https://www.sitespeed.io/documentation/sitespeed.io/scripting/#reuse-scripts

Exact how you run (the exact parameters): docker run --rm -v "$(pwd):/sitespeed.io" sitespeedio/sitespeed.io:24.7.0 exampleScript.js --multi -n 1 Which version you are using: 24.7.0 OS (if you use Docker, report the base OS): Windows 10 Pro 21H1 Browser version (if you don't run Docker): N/A - use docker

It works as expected better when the function is not inside a class, I included scripts to reproduce that case as well. It might be also my mistake in this case please change it from a bug into a question and guide me a bit if the time allows :).

first file - exampleScript.js

const UserClass = require('./exporttrial')

module.exports = async function (context, commands) {
    // commands.navigate('https://www.google.com'); // - this sitespeedio command works from here if you unncomment it
    // context.selenium.driver.get('https://www.google.com'); // - this sitespeedio command works from here if you unncomment it
    const User = new UserClass(context, commands); // - to be uncommented with the line above
    context.log.info('navigated to https://www.google.com')
    User.loginWithPerformanceAccount();
}

second file - exporttrial.js

class User {
    context;
    comments;

    constructor(context,commands) {
      this.context = context;
      this.commands = commands;
    }

    async loginWithPerformanceAccount() {
        await this.context.log.info('test1');
        await this.commands.wait.byTime(1000)
        await this.context.log.info('test2');
        // await this.commands.navigate('https://www.google.com'); // doesn't work - sitespeedio commands
        await this.context.log.info('test3');
        await this.context.selenium.driver.get('https://www.google.com'); // doesn't work - selenium
        await this.context.log.info('test4');
    }

  }

Now for the variant without classes - command stays the same

first file without class - exampleScript.js:

const loginWithPerformanceAccount = require('./exporttrial2')

module.exports = async function (context, commands) {
    loginWithPerformanceAccount(context, commands);
}

second file without class - exporttrial.js:

  async function loginWithPerformanceAccount(context, commands) {
    context.log.info('test1');
    commands.wait.byTime(1000)
    context.log.info('test2');
    commands.navigate('https://www.google.com'); // doesn't work - sitespeedio commands
    context.log.info('test3');
    context.selenium.driver.get('https://www.google.com'); // doesn't work - selenium
    context.log.info('test4');
}
module.exports = loginWithPerformanceAccount;

What browser did you use?

Chrome, Firefox, Edge

How to reproduce

docker run --rm -v "$(pwd):/sitespeed.io" sitespeedio/sitespeed.io:24.7.0 exampleScript.js --multi -n 1

Relevant log output

// log while using sitespeed commands
/usr/src/app/node_modules/ws/lib/websocket.js:903
    const err = new Error(
                ^

Error: WebSocket is not open: readyState 3 (CLOSED)
    at sendAfterClose (/usr/src/app/node_modules/ws/lib/websocket.js:903:17)
    at WebSocket.send (/usr/src/app/node_modules/ws/lib/websocket.js:405:7)
    at Chrome._enqueueCommand (/usr/src/app/node_modules/chrome-remote-interface/lib/chrome.js:286:18)
    at /usr/src/app/node_modules/chrome-remote-interface/lib/chrome.js:88:22
    at new Promise (<anonymous>)
    at Chrome.send (/usr/src/app/node_modules/chrome-remote-interface/lib/chrome.js:87:20)
    at Object.handler [as addScriptToEvaluateOnNewDocument] (/usr/src/app/node_modules/chrome-remote-interface/lib/api.js:33:23)
    at ChromeDevtoolsProtocol.setupLongTask (/usr/src/app/node_modules/browsertime/lib/chrome/chromeDevtoolsProtocol.js:121:32)
    at Chromium.beforeStartIteration (/usr/src/app/node_modules/browsertime/lib/chrome/webdriver/chromium.js:124:26)
    at Measure._navigate (/usr/src/app/node_modules/browsertime/lib/core/engine/command/measure.js:146:33)
    at async User.loginWithPerformanceAccount (/sitespeed.io/exporttrial.js:41:9)

// log while using selenium
/usr/src/app/node_modules/selenium-webdriver/lib/webdriver.js:766
        new error.NoSuchSessionError(
        ^

NoSuchSessionError: This driver instance does not have a valid session ID (did you call WebDriver.quit()?) and may no longer be used.
    at /usr/src/app/node_modules/selenium-webdriver/lib/webdriver.js:766:9
    at Object.thenFinally [as finally] (/usr/src/app/node_modules/selenium-webdriver/lib/promise.js:110:12)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Iteration.run (/usr/src/app/node_modules/browsertime/lib/core/engine/iteration.js:247:7)
    at async Engine.runByScript (/usr/src/app/node_modules/browsertime/lib/core/engine/index.js:266:20)
    at async Object.analyzeUrl (/usr/src/app/lib/plugins/browsertime/analyzer.js:145:21)
    at async Object.processMessage (/usr/src/app/lib/plugins/browsertime/index.js:150:26) {
  remoteStacktrace: ''
}
soulgalore commented 2 years ago

Hi @monika-pietrosian thanks for taking the time to write a so detailed bug description that helps a lot!

In your first script change: User.loginWithPerformanceAccount(); to return User.loginWithPerformanceAccount(); (return a promise that will be a success when the navigation finish) or if you will run some other commands after that use await User.loginWithPerformanceAccount();.

What happens without that is that that function runs and sitespeed.io do not understand to wait on it to finish before continuing so it closes the connection to the browser.

The await is only needed when the function returns a promise and we want to wait on to finish before we move on with the next thing.

Hope that helps!

monika-pietrosian commented 2 years ago

Ouuu yes, it helped a lot :). I wouldn't call it a bug anymore then, but if someone else would struggle with it maybe they can find it here in the closed issues :). Thank you!

soulgalore commented 2 years ago

I'm gonna update the documentation so we have a section explaining when to use awaity/return etc.