@ 261105.4 · fetching
current
import { describe, it } from 'node:test';
import assert from 'node:assert';

import {
  formatMetadataResult,
  METADATA_EXIT_CODES,
  METADATA_READINESS
} from '../../components/metadata.js';
import {
  writeMetadataJsonResult
} from '../../components/git/metadata.js';
import {
  PR_CHECK_REASON_CODES
} from '../../lib/pr_checker.js';

describe('metadata command helpers', () => {
  it('formats ready metadata JSON output with unique reason codes', () => {
    const reason = {
      code: PR_CHECK_REASON_CODES.WAIT_TIME,
      message: 'This PR needs to wait 24 more hours to land'
    };
    const result = formatMetadataResult({
      status: true,
      data: {
        owner: 'nodejs',
        repo: 'node',
        prid: 12345,
        pr: {
          url: 'https://github.com/nodejs/node/pull/12345',
          labels: {
            nodes: [
              { name: 'commit-queue' },
              { name: 'fast-track' }
            ]
          }
        }
      },
      metadata: 'PR-URL: https://github.com/nodejs/node/pull/12345\n',
      checker: {
        reasons: [reason, reason]
      }
    });

    assert.deepStrictEqual(result, {
      ready: true,
      readiness: METADATA_READINESS.READY,
      exitCode: METADATA_EXIT_CODES.READY,
      pullRequest: {
        owner: 'nodejs',
        repo: 'node',
        number: 12345,
        url: 'https://github.com/nodejs/node/pull/12345',
        labels: ['commit-queue', 'fast-track']
      },
      metadata: 'PR-URL: https://github.com/nodejs/node/pull/12345\n',
      reasonCodes: [PR_CHECK_REASON_CODES.WAIT_TIME],
      reasons: [reason, reason]
    });
  });

  it('classifies metadata JSON output with deferrable reasons', () => {
    const result = formatMetadataResult({
      status: false,
      data: {
        owner: 'nodejs',
        repo: 'node',
        prid: 12345,
        pr: {
          url: 'https://github.com/nodejs/node/pull/12345',
          labels: { nodes: [] }
        }
      },
      metadata: 'PR-URL: https://github.com/nodejs/node/pull/12345\n',
      checker: {
        reasons: [
          {
            code: PR_CHECK_REASON_CODES.WAIT_TIME,
            message: 'This PR needs to wait 24 more hours to land'
          }
        ]
      }
    });

    assert.strictEqual(result.readiness, METADATA_READINESS.DEFERRABLE);
    assert.strictEqual(result.exitCode, METADATA_EXIT_CODES.DEFERRABLE);
    assert.deepStrictEqual(result.pullRequest.labels, []);
  });

  it('classifies missing approvals as failed', () => {
    const result = formatMetadataResult({
      status: false,
      data: {
        owner: 'nodejs',
        repo: 'node',
        prid: 12345,
        pr: {
          url: 'https://github.com/nodejs/node/pull/12345',
          labels: { nodes: [] }
        }
      },
      metadata: 'PR-URL: https://github.com/nodejs/node/pull/12345\n',
      checker: {
        reasons: [
          {
            code: PR_CHECK_REASON_CODES.MISSING_APPROVAL,
            message: 'Approvals: 0'
          }
        ]
      }
    });

    assert.strictEqual(result.readiness, METADATA_READINESS.FAILED);
    assert.strictEqual(result.exitCode, METADATA_EXIT_CODES.FAILED);
  });

  it('classifies mixed metadata JSON output as failed', () => {
    const result = formatMetadataResult({
      status: false,
      data: {
        owner: 'nodejs',
        repo: 'node',
        prid: 12345,
        pr: {
          url: 'https://github.com/nodejs/node/pull/12345',
          labels: { nodes: [] }
        }
      },
      metadata: 'PR-URL: https://github.com/nodejs/node/pull/12345\n',
      checker: {
        reasons: [
          {
            code: PR_CHECK_REASON_CODES.WAIT_TIME,
            message: 'This PR needs to wait 24 more hours to land'
          },
          {
            code: PR_CHECK_REASON_CODES.CONFLICT,
            message: 'This PR has conflicts that must be resolved'
          }
        ]
      }
    });

    assert.strictEqual(result.readiness, METADATA_READINESS.FAILED);
    assert.strictEqual(result.exitCode, METADATA_EXIT_CODES.FAILED);
  });

  it('writes metadata JSON output before setting the exit code', async(t) => {
    const originalWrite = process.stdout.write;
    const originalExitCode = process.exitCode;
    const written = [];

    t.after(() => {
      process.stdout.write = originalWrite;
      process.exitCode = originalExitCode;
    });

    process.stdout.write = (chunk, encoding, callback) => {
      written.push(chunk.toString());
      const cb = typeof encoding === 'function' ? encoding : callback;
      cb?.();
      return true;
    };

    const json = {
      ready: false,
      readiness: METADATA_READINESS.DEFERRABLE,
      exitCode: METADATA_EXIT_CODES.DEFERRABLE
    };

    await writeMetadataJsonResult(Promise.resolve({ json }));

    assert.deepStrictEqual(JSON.parse(written.join('')), json);
    assert.strictEqual(process.exitCode, METADATA_EXIT_CODES.DEFERRABLE);
  });
});