playwright icon indicating copy to clipboard operation
playwright copied to clipboard

[BUG] _interopRequireWildcard not defined in browser when using "import()" in page.evaluate()

Open Ademsk1 opened this issue 1 year ago • 3 comments

System info

  • Playwright Version: [v1.34.0]
  • Operating System: [macOS 13.2]
  • Browser: [All]
  • Other info: Trying to import a url module in page.evaluate raises the following error: Error: page.evaluate: ReferenceError: _interopRequireWildcard is not defined despite me only using the following:
page.evaluate(()=> {
const {getAuth} = import('some-url-link-to-module')
}

I found this strange, as I don't use _interopRequireWildcard at all. When in the debugging browser session, I plugged my commands in manually, and had no issues at all. On further inspection within the evaluate function, it seems as though the command import(...) gets converted into:

await Promise.resolve().then(() => _interopRequireWildcard(require('some-url-link-to-module')));

within the pageFunction variable in page.evaluate. I decided to quickly try and change it back to its regular import(...) and it worked! However, even if _interopRequireWildcard was defined in the browser, require wouldn't be, and so if this could be altered so that import() doesn't get modified, this would work.

Steps

  • Run a test with page.evaluate(...) where within it we use the import() method to import a url module

Expected Module should be imported and usable

Actual Error occurs due to some action causing import() to be rewritten as a promise that uses _interopRequireWildcard

Ademsk1 avatar May 24 '23 08:05 Ademsk1

seems like they transpile that code that is supposed to be evaluated in the browser

Smrtnyk avatar May 24 '23 12:05 Smrtnyk

seems like they transpile that code that is supposed to be evaluated in the browser

Yeah, which is a bit strange right? Surely a TS dev would know to write Javascript within the page.evaluate?

Ademsk1 avatar May 24 '23 14:05 Ademsk1

I've been able to get around the issue by running

page.addScriptTag({url: 'http://X.com/Y', type: 'module'})
...
page.addScriptTag({content: 'import {Z} from http://X.com/Y', type: 'module'})

to enable me to use Z from the imported module. Despite this, I still think that the the import() method should work in page.evaluate.

Ademsk1 avatar May 24 '23 14:05 Ademsk1

It's caused by the @babel/plugin-proposal-dynamic-import plugin which we use.

Wrote a test for it.
test('should support dynamic import inside page', async ({ runInlineTest, server }) => {
  server.setRoute('/helper.js', (req, res) => {
    res.setHeader('Content-Type', 'application/javascript');
    res.end(`export const foo = 'from helper';`);
  });
  server.setRoute('/empty.html', (req, res) => {
    res.setHeader('Content-Type', 'text/html');
    res.end(`<script type="module">
      import { foo } from './helper.js';
      window.foo = foo;
    </script>`);
  });
  const result = await runInlineTest({
    'playwright.config.ts': `
    import { PlaywrightTestConfig } from '@playwright/test';

    const config: PlaywrightTestConfig = {
      use: {
        headless: false,
      },
    };
    module.exports = config;
  `,
    'a.test.ts': `
      const {test, expect} = require('@playwright/test');

      test('pass', async ({ page }) => {
        await page.goto('${server.EMPTY_PAGE}');
        expect(await page.evaluate(async () => {
          const foo = await import('./helper.js');
          throw new Error(foo);
          return foo;
        )).toBe('from helper');
      });
    `,
  });
  expect(result.passed).toBe(1);
  expect(result.exitCode).toBe(0);
});

I don't think we can easily solve it, since we want the plugin to be enabled in node but not in the "evaluate functions" which get stringified to the browser. As a workaround I recommend for now to pass it as a string, then it does not get transpiled with Babel:

 expect(await page.evaluate(`
  (async () => {
    const { foo } = await import ('./helper.js');
    return foo;
  })()
`)).toBe('from helper');

mxschmitt avatar May 30 '23 11:05 mxschmitt

Why was this issue closed?

Thank you for your contribution to our project. This issue has been closed due to its limited upvotes and recent activity, and insufficient feedback for us to effectively act upon. Our priority is to focus on bugs that reflect higher user engagement and have actionable feedback, to ensure our bug database stays manageable.

Should you feel this closure was in error, please create a new issue and reference this one. We're open to revisiting it given increased support or additional clarity. Your understanding and cooperation are greatly appreciated.

pavelfeldman avatar Apr 22 '24 17:04 pavelfeldman