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

Code before:
    expectFailure: {
      label: 'Bug #124',
      match: /boom/
    }
  }, () => {
    throw new Error('boom');
  });

  test('fails with config object (label only)', {
    expectFailure: { label: 'Bug #125' }
  }, () => {
    throw new Error('boom');
  });

  test('fails with config object (match only)', {
    expectFailure: { match: /boom/ }
  }, () => {
    throw new Error('boom');
  });

  // 6. Edge Case: Empty Object (Should throw ERR_INVALID_ARG_VALUE during creation)
  try {
    test('invalid empty object', { expectFailure: {} }, () => {});
  } catch (e) {
    console.log(`CAUGHT_INVALID_ARG: ${e.code}`);
  }

  // 7. Primitives and Truthiness
  test('fails with boolean true', { expectFailure: true }, () => {
    throw new Error('any error');
  });

  // 8. Unexpected Pass (Enhanced)
  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.
    });

Review comment (bug):
I think we should cover more edge cases as below. Desired behavior is open for discussion.

```suggestion

// 7. Edge Case: Wrong way to have both error match and reason.
//    Should result in test failure because thrown error doesn't
//    have matching label field
test('', {
  expectFailure: {
    code: 'ERR_TEST';
    label: 'Bug #124',
  }
}, () => {
  const err = new Error('boom');
  err.code = 'ERR_TEST';
  throw err;
});

```

Code after:
    expectFailure: {
      label: 'Bug #124',
      match: /boom/
    }
  }, () => {
    throw new Error('boom');
  });

  test('fails with config object (label only)', {
    expectFailure: { label: 'Bug #125' }
  }, () => {
    throw new Error('boom');
  });

  test('fails with config object (match only)', {
    expectFailure: { match: /boom/ }
  }, () => {
    throw new Error('boom');
  });

  // 6. Edge Case: Empty Object (Should throw ERR_INVALID_ARG_VALUE during creation)
  test('invalid empty object throws', () => {
    // eslint-disable-next-line no-restricted-syntax
    assert.throws(() => test('invalid empty object', { expectFailure: {} }, () => {}));
  });

  // 7. Primitives and Truthiness
  test('fails with boolean true', { expectFailure: true }, () => {
    throw new Error('any error');
  });

  // 8. Unexpected Pass (Enhanced)
  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.
    });
  });