Repository: nodejs/node
File: test/parallel/test-runner-xfail.js (JavaScript)

Code before:
  // 8. Unexpected Pass (Enhanced)
  test('unexpected pass (reason string)', { expectFailure: 'should fail' }, () => {
    // Pass
  });

  test('unexpected pass (matcher)', { expectFailure: /boom/ }, () => {
    // Pass
  });

  // 9. Suite level expectFailure
  test('suite level expectFailure', { expectFailure: true }, async (t) => {
    await t.test('subtest should pass if it throws', () => {
      throw new Error('fail');
    });

    await t.test('subtest should fail if it does not throw', () => {
      // This should fail the test because the suite expects failure,
      // and this subtest inherited that expectation but didn't throw.
    });
  });

  test('suite level expectFailure with matcher', { expectFailure: /suite error/ }, async (t) => {
    await t.test('subtest match suite expectation', () => {
      throw new Error('suite error');
    });
  });

} else {
  const child = spawn(process.execPath, ['--test-reporter', 'tap', __filename], {
    env: { ...process.env, CHILD_PROCESS: 'true' },
    stdio: 'pipe',
  });

  let stdout = '';
  child.stdout.setEncoding('utf8');
  child.stdout.on('data', (chunk) => { stdout += chunk; });

  child.on('close', common.mustCall((code) => {
    // We expect exit code 1 because 'unexpected pass' and 'wrong error' should fail the test run
    assert.strictEqual(code, 1);

    assert.match(stdout, /ok \d+ - fail with message string # EXPECTED FAILURE reason string/);
    assert.match(stdout, /ok \d+ - fail with label object # EXPECTED FAILURE reason object/);
    assert.match(stdout, /ok \d+ - fail with match regex # EXPECTED FAILURE/);
    assert.match(stdout, /ok \d+ - fail with match object # EXPECTED FAILURE/);
    assert.match(stdout, /ok \d+ - fail with match class # EXPECTED FAILURE/);
    assert.match(stdout, /not ok \d+ - fail with match error \(wrong error\) # EXPECTED FAILURE/);
    assert.match(stdout, /not ok \d+ - unexpected pass # EXPECTED FAILURE/);
    assert.match(stdout, /ok \d+ - fail with empty string # EXPECTED FAILURE/);

    // New tests verification

Review comment (bug):
These are good test additions, but they test `test`-level expectFailure applying to *subtests*, not `suite`-level, e.g.:

```js
suite('suite level...', {expectFailure: ...
  await test(...
    throw...

```

So recharacterize the former and add some of the latter and we should be good. almost there! great work.


Code after:
  test('unexpected pass (reason string)', { expectFailure: 'should fail' }, () => {
    // Pass
  });

  test('unexpected pass (matcher)', { expectFailure: /boom/ }, () => {
    // Pass
  });

  // 9. Test level expectFailure with subtests
  test('test level expectFailure with subtests', { expectFailure: true }, async (t) => {
    await t.test('subtest should pass if it throws', () => {
      throw new Error('fail');
    });

    await t.test('subtest should fail if it does not throw', () => {
      // This should fail the test because the suite expects failure,
      // and this subtest inherited that expectation but didn't throw.
    });
  });

  test('test level expectFailure with subtests and matcher', { expectFailure: /suite error/ }, async (t) => {
    await t.test('subtest match suite expectation', () => {
      throw new Error('suite error');
    });
  });

  // 10. Suite level expectFailure
  suite('suite level expectFailure', { expectFailure: true }, () => {
    test('suite subtest should pass if it throws', () => {
      throw new Error('fail');
    });

    test('suite subtest should fail if it does not throw', () => {
      // This should fail the test because the suite expects failure,
      // and this subtest inherited that expectation but didn't throw.
    });
  });

  suite('suite level expectFailure with matcher', { expectFailure: /suite error/ }, () => {
    test('suite subtest match suite expectation', () => {
      throw new Error('suite error');
    });
  });

  test('correct config with label and match object', {
    expectFailure: {
      label: 'Bug #124',
      match: { code: 'ERR_TEST' }
    }
  }, () => {
    const err = new Error('boom');