facebook / memlab

A framework for finding JavaScript memory leaks and analyzing heap snapshots
https://facebook.github.io/memlab/
MIT License
4.35k stars 118 forks source link

Invalid Scenario file: Xvfb supports: false #28

Closed elarswa closed 1 year ago

elarswa commented 1 year ago

I wrote a basic scenario file that looks the same as the Getting Started Guide.

Here is my scenario.js which just clicks two buttons that should trigger mount/unmount:

function url() {
  return 'http://myAppRunningLocally';
}

async function action(page) {
  return await page.click('button[aria-label="Good"]');
}

async function back(page) {
  return await page.click('button[aria-label="Bad"]');
}

const s = { url, action, back };

module.exports = s;

Here is the entire output when run with command memlab run --scenario ./src/memlab/scenario.js -v:

Xvfb supports: false
Invalid scenario file: ./src/memlab/scenario.js
Error: Invalid scenario file: ./src/memlab/scenario.js
    at convertToError (~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/core/dist/lib/Utils.js:1670:16)
    at getError (~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/core/dist/lib/Utils.js:1662:12)
    at haltOrThrow (~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/core/dist/lib/Utils.js:1595:17)
    at Object.loadScenario (~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/core/dist/lib/Utils.js:533:15)
    at ScenarioFileOption.<anonymous> (~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/cli/dist/options/ScenarioFileOption.js:38:48)
    at Generator.next (<anonymous>)
    at ~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/cli/dist/options/ScenarioFileOption.js:17:71
    at new Promise (<anonymous>)
    at __awaiter (~/.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/cli/dist/options/ScenarioFileOption.js:13:12)
    at ScenarioFileOption.parse (/~.nvm/versions/node/v16.14.2/lib/node_modules/memlab/node_modules/@memlab/cli/dist/options/ScenarioFileOption.js:34:16)

Steps to repeat:

  1. run npm install -g memlab with npm v8.8.0
  2. create scenario file pointing at locally running app for the url function
  3. made sure app is running locally
  4. run command memlab run --scenario ./src/memlab/scenario.js -v from project directory
  5. get invalid scenario file error

OS: Mac with M1

I have also tracked down the function that is throwing in Utils.js -> checkScenarioInstance, verified I had what is expected. I copied the code into the scenario file and ran it with node just to check if I was missing something. It looked like this below the function definitions:

const s = { url, action, back };

// module.exports = s;

console.log(typeof s);
console.log(typeof url);
console.log(typeof action);
console.log(typeof back);

if (
  typeof s !== 'object' ||
  typeof s.url !== 'function' ||
  (s.action && typeof s.action !== 'function') ||
  (s.back && typeof s.back !== 'function') ||
  (s.repeat && typeof s.repeat !== 'function') ||
  (s.isPageLoaded && typeof s.isPageLoaded !== 'function') ||
  (s.leakFilter && typeof s.leakFilter !== 'function') ||
  (s.beforeLeakFilter && typeof s.beforeLeakFilter !== 'function')
) {
  throw new Error('Invalid senario'); 
}

this was run with node ./src/memlab/scenario.js on node v16.14.2. It did not throw and the output was

object
function
function
function

as expected.

The last thing is the Xvfb supports: false log. This is a dependency of memlab that should come with the installation?

If I missed a step, please let me know. Any idea why this would throw when run with memlab? Is it an installation failure?

JacksonGL commented 1 year ago

@elarswa I copy and pasted your scenario file but I couldn't reproduce the error on my local machine.

Debugging what happened on your machine should be easy since you already located the code that checks the scenario:

  1. Clone the memlab git repo
  2. Insert a few more console log statement here to figure out which conditional expression trigger the error: https://github.com/facebookincubator/memlab/blob/main/packages/core/src/lib/Utils.ts#L550
  3. Run npm run build
  4. Inside the git repo folder: node ./packages/memlab/bin/memlab run --scenario <YOUR SCENARIO FILE>

Xvfb is nice to have but it doesn't matter (enables browser run in virtual headful mode instead of headless mode).

elarswa commented 1 year ago

After repeating the steps you provided, I am finding it is failing on thescenario = require(filepath); step. However, I have verified the file path is correct. I get the same result when I switch to absolute file paths and verify with bash ls first. Even testing with the logged resolved path also shows up.

Why would this still be throwing?

JacksonGL commented 1 year ago

@elarswa please use absolute path for now, I guess you are using relative path to the current cmd directory, this is something we need to fix. Thanks for reporting this issue

JacksonGL commented 1 year ago

Hmm, it seems the relative path should work, can you double check that your relative file path is correct?

elarswa commented 1 year ago

yes, I verified relative as well

JacksonGL commented 1 year ago

Just double check, if I understand it correctly, you were running the memlab command from <DIR>, and the scenario file is located inside <DIR>/src/memlab/scenario.js. Is that correct?

elarswa commented 1 year ago

when running the globally installed instance of memlab, yes that is true. Running from the cloned repo, I input a relative path going into the project folder which is in the same directory as the cloned repo.

elarswa commented 1 year ago

running from the cloned repo: node ./packages/memlab/bin/memlab run --scenario ../memlab-demo/src/memlab/scenario.js -v

JacksonGL commented 1 year ago

Did the absolute file path fail for the following statement? scenario = require(filepath);

If so, can you print the filepath? if the filepath looks correct and does exist, then seems to me there is something wrong with the node require statement.

elarswa commented 1 year ago

Yes I have verified the absolute path. It is the same as the resolved path I'm logging on error

JacksonGL commented 1 year ago

So the absolute file path is correct, but the require(filepath) throw an error, it sounds like there is something wrong with your node installation.

Can you run a separate node version using nvm, reinstall memlab and try it again?

elarswa commented 1 year ago

Before trying your suggestion, I failed to actually log the error being thrown. My bad. This is showing up:

 Error [ERR_REQUIRE_ESM]: require() of ES Module ~/Desktop/projects/memlab-demo/src/memlab/scenario.js from ~/Desktop/projects/memlab/packages/core/dist/lib/Utils.js not supported.
scenario.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which declares all .js files in that package scope as ES modules.
Instead rename scenario.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change "type": "module" to "type": "commonjs" in ~/Desktop/projects/memlab-demo/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead)

I'll try to address this first before changing node versions.

elarswa commented 1 year ago

ok. Changing the extension to .cjs did not work, I attempted for a bit to use import() in the cloned repo but that requires more changes since it needs to be awaited.

adding "type": "commonjs" into the package.json of my demo project resolved this. Thank you for your help!

nianxiongdi commented 1 year ago

Same problem, how to solve it?

JacksonGL commented 1 year ago

@nianxiongdi

adding "type": "commonjs" into the package.json of my demo project resolved this.