Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(0 , chrome_remote_interface_1.default) is not a function error when running CDP() through Cypress #559

Open
Tobio89 opened this issue May 16, 2024 · 1 comment

Comments

@Tobio89
Copy link

Tobio89 commented May 16, 2024

Environment

Component Version
Node.js v.20.11.1
Client (Chrome/Chromium/...) Chrome v.125
OS running Node.js MacOS Sonoma 14.4.1
OS running the client Also MacOS
chrome-remote-interface 0.33.0

Is the client running in a container? YES

Description

Trying to use CDP to grab heap snapshots with Cypress.
Cypress fails to run the CDP init function:
image

Example

cypress.config.ts

export default defineConfig({
  e2e: {
    ...nxE2EPreset(__dirname, {
      bundler: 'vite',
    }),
    baseUrl: 'http://localhost:3000',
    setupNodeEvents(on, config) {
      const { setRdpPortWhenBrowserLaunch, initCDPClient, takeHeapSnapshot } = cdpPlugin();

      on('before:browser:launch', (_, launchOptionsOrArgs) => {
        setRdpPortWhenBrowserLaunch(launchOptionsOrArgs);
      });

      on('task', {
        takeHeapSnapshot: async (opts) => {
          console.log('task: snapshot');
          console.log('init check');
          await initCDPClient();
          console.log('snapshot');
          await takeHeapSnapshot(opts);

          return null;
        },
      });

      return config;
    },
  },
});

cdpPlugin

import CDP from 'chrome-remote-interface';
import fs from 'fs';

export interface TakeHeapSnapshotType {
  filePath: string;
  beforeTakeCallback?: () => void;
  afterTakeCallback?: () => void;
}

let port = 0;
let client: CDP.Client | null = null;

const setRdpPortWhenBrowserLaunch = (launchOptionsOrArgs: Cypress.BrowserLaunchOptions) => {
  const args = Array.isArray(launchOptionsOrArgs) ? launchOptionsOrArgs : launchOptionsOrArgs.args;

  const ensureRdpPort = (args: string[] | (Cypress.BrowserLaunchOptions & any[])) => {
    const existing = args.find((arg) => arg.slice(0, 23) === '--remote-debugging-port');

    if (existing) {
      return Number(existing.split('=')[1]);
    }

    const port = 40000 + Math.round(Math.random() * 25000);

    args.push(`--remote-debugging-port=${port}`);

    return port;
  };

  port = ensureRdpPort(args);

  console.log('Ensure remote debugging port %d', port);
};

const initCDPClient = async () => {
  if (!port) {
    throw new Error('Please set the remote debugging port first!');
  }

  if (!client) {
    console.log('generating client, port:', port);
    client = await CDP({
      port,
    });
    console.log('client', client);
  }
};

const takeHeapSnapshot = async (opts: TakeHeapSnapshotType) => {
  console.log('start take snapshot');

  if (!client) {
    console.warn('client not init');
    throw new Error('Please init the cdp client first!');
  }

  const { filePath, beforeTakeCallback = null, afterTakeCallback = null } = opts;

  if (beforeTakeCallback) {
    beforeTakeCallback();
  }

  const writeStream = fs.createWriteStream(filePath, { encoding: 'utf-8' });
  const dataHandler = (data: { chunk: string }) => {
    writeStream.write(data.chunk);
  };

  const progressHander = (data: { done: number; total: number; finished: boolean }) => {
    const percent = ((100 * data.done) / data.total) | 0;
    console.log(`heap snapshot ${percent}% complete`);
  };

  client.on('HeapProfiler.addHeapSnapshotChunk', dataHandler);
  client.on('HeapProfiler.reportHeapSnapshotProgress', progressHander as SafeAny);

  await client.send('HeapProfiler.takeHeapSnapshot', {
    reportProgress: true,
    captureNumericValue: true,
  });

  writeStream.end();

  if (afterTakeCallback) {
    afterTakeCallback();
  }
};

export const cdpPlugin = () => {
  return {
    setRdpPortWhenBrowserLaunch,
    initCDPClient,
    takeHeapSnapshot,
  };
};

Cypress test

describe('MemLab Test', () => {
  it('should take a snapshot', () => {
    cy.task('takeHeapSnapshot', {
      filePath: path.join(__dirname, './snapshots/s1.heapsnapshot'),
    });
  });
});
@cyrus-and
Copy link
Owner

I know nothing about Cypress, but I think it should be:

import {CDP} from 'chrome-remote-interface';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants