🙌

jest it.concurrent / test.concurrent の挙動

2023/07/06に公開

https://jestjs.io/ja/docs/api#testconcurrentname-fn-timeout

test.concurrent is considered experimental - see here for details on missing features and other issues.
test.concurrentは実験的なものとみなされています。不足している機能やその他の問題の詳細については、こちらをご覧ください。

とあるので、どういう挙動なのかを確認した。
jest バージョン 29.5.0 で確認した。

テスト対象コード

import { setTimeout } from "timers/promises";

export const calc = (a: number) => async (b: number, c: number) => {
  await setTimeout(1000);
  return a * (b + c);
};

concurrentを使わない場合

describe("concurrentを使わない場合", function () {
  it("test 1", async function () {
    const result = await calc(2)(4, 2);
    expect(result).toBe(12);
  });

  it("test 2", async function () {
    const result = await calc(2)(5, 2);
    expect(result).toBe(14);
  });
});
 PASS  ./index.test.ts
  concurrentを使わない場合
    ✓ test 1 (1003 ms)
    ✓ test 2 (1002 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.257 s

concurrentを使う場合

describe("concurrentを使う場合", function () {
  it.concurrent("test 1", async function () {
    const result = await calc(2)(4, 2);
    expect(result).toBe(12);
  });

  it.concurrent("test 2", async function () {
    const result = await calc(2)(5, 2);
    expect(result).toBe(14);
  });
});
 PASS  ./index.test.ts
  concurrentを使う場合
    ✓ test 1 (1003 ms)
    ✓ test 2

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.238 s, estimated 2 s

早い。

beforeAll を使う場合

concurrentを使わない場合

describe("beforeAllを使い、concurrentを使わない場合", function () {
  let calc2;
  beforeAll(() => {
    calc2 = calc(2);
  });

  it("test 1", async function () {
    const result = await calc2(4, 2);
    expect(result).toBe(12);
  });

  it("test 2", async function () {
    const result = await calc2(5, 2);
    expect(result).toBe(14);
  });
});
 PASS  ./index.test.ts
  beforeAllを使い、concurrentを使わない場合
    ✓ test 1 (1002 ms)
    ✓ test 2 (1001 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        2.251 s, estimated 3 s
Ran all test suites.

concurrentを使う場合

describe("beforeAllを使い、concurrentを使う場合", function () {
  let calc2;

  beforeAll(() => {
    console.log("beforeAll");
    calc2 = calc(2);
  });

  it.concurrent("test 1", async function () {
    console.log("test 1");
    const result = await calc2(4, 2);
    expect(result).toBe(12);
  });

  it.concurrent("test 2", async function () {
    console.log("test 2");
    const result = await calc2(5, 2);
    expect(result).toBe(14);
  });
});
 FAIL  ./index.test.ts
  beforeAllを使い、concurrentを使う場合
    ✕ test 1
    ✕ test 2

  ● beforeAllを使い、concurrentを使う場合 › test 1

    TypeError: calc2 is not a function

      52 |   it.concurrent("test 1", async function () {
      53 |     console.log("test 1");
    > 54 |     const result = await calc2(4, 2);
         |                          ^
      55 |     expect(result).toBe(12);
      56 |   });
      57 |

失敗。

console.logの出力を見ると、beforeAllでの出力が最後に実行されている。

  console.log
    test 1

      at log (index.test.ts:53:13)

  console.log
    test 2

      at log (index.test.ts:59:13)

  console.log
    beforeAll

      at Object.log (index.test.ts:48:13)

回避策

https://github.com/jestjs/jest/issues/7997#issuecomment-1455052585 に、

I found some workaround to execute beforeAll before test.concurrent. Seems like problem is not with test.concurrent logic but with describe. If we move beforeAll out from describe, everything works as expected:
test.concurrentの前にbeforeAllを実行する回避策を見つけました。問題はtest.concurrentのロジックではなく、describeにあるようだ。beforeAllをdescribeから外せば、すべてが期待通りに動く:

とある。

let calc2;

beforeAll(() => {
  console.log("beforeAll");
  calc2 = calc(2);
});

it.concurrent("test 1", async function () {
  console.log("test 1");
  const result = await calc2(4, 2);
  expect(result).toBe(12);
});

it.concurrent("test 2", async function () {
  console.log("test 2");
  const result = await calc2(5, 2);
  expect(result).toBe(14);
});
 PASS  ./index.test.ts
  ✓ test 1 (1004 ms)
  ✓ test 2

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.084 s
Ran all test suites.

確かに回避できた。

Discussion