在 Jest describe 块中,使用 getElementsByClassName 时一次只通过一个测试

In Jest describe block, only one test passes at a time when using getElementsByClassName

我有这段 Jest + 测试库代码:

describe('Component', () => {
  const { container } = renderComponent(); // defined outside of describe block

  test('Renders test1', () => {
    expect(container.getElementsByClassName('test1').length).toBe(1);
  });

  test('Renders test2', () => {
    expect(container.getElementsByClassName('test2').length).toBe(1);
  });
});

这两项测试都应该通过,但只有一项通过。 另一个总是失败。
如果我 运行 使用 .only 一次只 一个 测试,它总是通过。

Jest 官方文档说:

If you have a test that often fails when it's run as part of a larger suite, but doesn't fail when you run it alone, it's a good bet that something from a different test is interfering with this one. You can often fix this by clearing some shared state with beforeEach.

但我不确定究竟是什么干扰了这里? 并行调用 getElementsByClassName 会导致这个问题吗?

不,getElementsByClassName 是 non-intrusive。如,调用它不应该对正在查询的 DOM 进行任何更改。1

您没有展示 renderComponent() 的作用,但它可能是相关的。但是,根据您的描述,每个测试调用一次而不是每个测试套件调用一次应该可以解决问题。2
这应该有效:

let container;

describe('Component', () => {
  beforeEach(() => {
    container = renderComponent().container;
  })

  it('Renders test1', () => {
    expect(container.getElementsByClassName('test1').length).toBe(1);
  });

  it('Renders test2', () => {
    expect(container.getElementsByClassName('test2').length).toBe(1);
  });
});

1 JavaScript 流畅而强大。例如,可以编写一个 getter 来改变目标,而不是仅仅读取它。但是在测试库提供的工具中使用这种 anti-pattern 的可能性很小。

2 这不应被视为 “使测试通过的 hacky 方式”。这是 正确的 测试方法。您的测试不应 re-using 与 DOM 相同,因为您不希望对 DOM 的任何更改在多个测试中传播。