current commit
260817.9 · debugger: wait for target startup
// Flags: --expose-internals
'use strict';

const common = require('../common');

common.skipIfInspectorDisabled();

const assert = require('assert');
const { EventEmitter } = require('events');
const {
  waitForDebugger,
} = require('internal/debugger/inspect_helpers');

function assertListenersRemoved(client) {
  assert.strictEqual(
    client.listenerCount('NodeRuntime.waitingForDebugger'),
    0,
  );
  assert.strictEqual(client.listenerCount('close'), 0);
}

async function testWaitingNotification(beforeEnableReply) {
  const client = new EventEmitter();
  const calls = [];
  client.callMethod = common.mustCall(async (method) => {
    calls.push(method);
    const emitWaiting = () => {
      client.emit('NodeRuntime.waitingForDebugger');
    };
    if (method === 'NodeRuntime.enable') {
      if (beforeEnableReply) {
        emitWaiting();
      } else {
        setImmediate(emitWaiting);
      }
    } else {
      assert.strictEqual(method, 'NodeRuntime.disable');
    }
  }, 2);

  await waitForDebugger(client);
  assert.deepStrictEqual(calls, [
    'NodeRuntime.enable',
    'NodeRuntime.disable',
  ]);
  assertListenersRemoved(client);
}

async function testCloseWhileWaiting(beforeEnableReply) {
  const client = new EventEmitter();
  client.callMethod = common.mustCall((method) => {
    assert.strictEqual(method, 'NodeRuntime.enable');
    setImmediate(() => client.emit('close'));
    return beforeEnableReply ? new Promise(() => {}) : Promise.resolve();
  });

  await assert.rejects(
    waitForDebugger(client),
    {
      code: 'ERR_DEBUGGER_ERROR',
      message: 'Debugger session ended while waiting for target startup',
    },
  );
  assertListenersRemoved(client);
}

async function testCloseWhileDisabling() {
  const client = new EventEmitter();
  client.callMethod = common.mustCall((method) => {
    if (method === 'NodeRuntime.enable') {
      client.emit('NodeRuntime.waitingForDebugger');
      return Promise.resolve();
    }
    assert.strictEqual(method, 'NodeRuntime.disable');
    setImmediate(() => client.emit('close'));
    return new Promise(() => {});
  }, 2);

  await assert.rejects(
    waitForDebugger(client),
    {
      code: 'ERR_DEBUGGER_ERROR',
      message: 'Debugger session ended while waiting for target startup',
    },
  );
  assertListenersRemoved(client);
}

async function testEnableFailure() {
  const client = new EventEmitter();
  const expected = new Error('NodeRuntime.enable failed');
  client.callMethod = common.mustCall(async (method) => {
    assert.strictEqual(method, 'NodeRuntime.enable');
    throw expected;
  });

  await assert.rejects(
    waitForDebugger(client),
    (error) => {
      assert.strictEqual(error, expected);
      return true;
    },
  );
  assertListenersRemoved(client);
}

async function testDisableFailure() {
  const client = new EventEmitter();
  const expected = new Error('NodeRuntime.disable failed');
  client.callMethod = common.mustCall(async (method) => {
    if (method === 'NodeRuntime.enable') {
      client.emit('NodeRuntime.waitingForDebugger');
      return;
    }
    assert.strictEqual(method, 'NodeRuntime.disable');
    throw expected;
  }, 2);

  await assert.rejects(
    waitForDebugger(client),
    (error) => {
      assert.strictEqual(error, expected);
      return true;
    },
  );
  assertListenersRemoved(client);
}

(async () => {
  await testWaitingNotification(true);
  await testWaitingNotification(false);
  await testCloseWhileWaiting(true);
  await testCloseWhileWaiting(false);
  await testCloseWhileDisabling();
  await testEnableFailure();
  await testDisableFailure();
})().then(common.mustCall());