Skip to content

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

@Tobio89

Description

@Tobio89

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'),
    });
  });
});

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions