// Flags: --experimental-quic --no-warnings

// Test: SuppressedError when onerror throws.
// If session.onerror throws synchronously, a SuppressedError
//           wrapping both the onerror error and the original error is
//           thrown via process.nextTick as an uncaught exception.
// The SuppressedError's .error is the onerror failure and
//           .suppressed is the original error.

import { hasQuic, skip, mustCall } from '../common/index.mjs';
import assert from 'node:assert';

const { ok, rejects, strictEqual } = assert;

if (!hasQuic) {
  skip('QUIC is not enabled');
}

const { listen, connect } = await import('../common/quic.mjs');

const originalError = new Error('original destroy error');
const onerrorError = new Error('onerror itself threw');

const transportParams = { maxIdleTimeout: 1 };

// The SuppressedError is thrown via process.nextTick, so it appears
// as an uncaught exception.
process.on('uncaughtException', mustCall((err) => {
  ok(err instanceof SuppressedError);
  // .error is the onerror failure
  strictEqual(err.error, onerrorError);
  // .suppressed is the original error that triggered destroy
  strictEqual(err.suppressed, originalError);
}));

const serverEndpoint = await listen(mustCall(async (serverSession) => {
  await serverSession.closed;
}), { transportParams });

const clientSession = await connect(serverEndpoint.address, {
  transportParams,
});
await clientSession.opened;

clientSession.onerror = mustCall(() => {
  throw onerrorError;
});

clientSession.destroy(originalError);

// Closed rejects with the original error (not the SuppressedError).
await rejects(clientSession.closed, originalError);
await serverEndpoint.close();
