jokarl
jokarl

Reputation: 2245

Jest with custom function that sets some pre condition and execution order

I am trying to extend Jest to easier get API integration tests to play along between different APIs.

I have followed this tutorial and I have it working somewhat. Here's my setup:

jest.setup.api.ts

test.apiOne = async (
    name: string,
    fn?: jest.ProvidesCallback,
    timeout?: number
  ) => {
    console.log(`Running test "${name}" against API 1`)
    pactum.request.setBaseUrl(`${process.env.API_TEST_HOST}/one`)
    test(name, fn, timeout)
}

test.apiTwo = async (
    name: string,
    fn?: jest.ProvidesCallback,
    timeout?: number
  ) => {
    console.log(`Running test "${name}" against API 2`)
    pactum.request.setBaseUrl(`${process.env.API_TEST_HOST}/two`)
    test(name, fn, timeout)
}

And I use it like this:

test.apiOne("1", async () => {
    console.log("1");
})

test.apiTwo("2", async () => {
    console.log("2");
})

test.apiOne("3", async () => {
    console.log("3");
})

test.apiOne("4", async () => {
    console.log("4");
})

When I run these tests, this is the output

console.log jest.setup.api.ts:26
    Running test "1" against API 1
console.log jest.setup.api.ts:38
    Running test "2" against API 2
console.log jest.setup.api.ts:26
    Running test "3" against API 1
console.log jest.setup.api.ts:38
    Running test "4" against API 2
console.log mytest.ts:511
    1

console.log jest.setup.api.ts:26
    Running test "1" against API 1
console.log jest.setup.api.ts:38
    Running test "2" against API 2
console.log jest.setup.api.ts:26
    Running test "3" against API 1
console.log jest.setup.api.ts:38
    Running test "4" against API 2
console.log mytest.ts:511
    2

console.log jest.setup.api.ts:26
    Running test "1" against API 1
console.log jest.setup.api.ts:38
    Running test "2" against API 2
console.log jest.setup.api.ts:26
    Running test "3" against API 1
console.log jest.setup.api.ts:38
    Running test "4" against API 2
console.log mytest.ts:511
    3

console.log jest.setup.api.ts:26
    Running test "1" against API 1
console.log jest.setup.api.ts:38
    Running test "2" against API 2
console.log jest.setup.api.ts:26
    Running test "3" against API 1
console.log jest.setup.api.ts:38
    Running test "4" against API 2
console.log mytest.ts:511
    4

So for all tests it is always the conditions for the last test within the describe that gets set. So test 1 should run against API path /one but actually gets run against /two.

Is there any way to achieve what I am trying do with Jest?

Upvotes: 1

Views: 463

Answers (1)

Estus Flask
Estus Flask

Reputation: 222979

The article is wrong on some points.

Modifying third-party API for your own needs isn't a good practice. If there's a need for custom test helpers, there's no need to modify test. They can be importable or global and be used the same way as test.apiOne but with less potential problems. It's a mistake to make these functions async. Tests should be known at the time when test run starts, so async results in a promise that isn't used. The article uses await yet types a function to return void.

test.apiOne cannot contain asynchronous operations, they will be discarded when they occur after test(...) and they will result in missing test when they occur before. test(...) result isn't returned, this means that a promise it returns won't be handled correctly by Jest.

console.log(`Running test "${name}" against API 1`) mistakenly suggests that it's called when a test runs, but it's actually called when it's declared.

pactum.request.setBaseUrl should be called inside a test it's supposed to affect. Considering that tests are asynchronous and use promises and not done callback, a helper is:

global.testApiOne = (name, fn, timeout) => {
  test(
    name, 
    async () => {
      console.log(`Running test "${name}" against API 1`)
      pactum.request.setBaseUrl(`${process.env.API_TEST_HOST}/one`)
      await fn();
    },
    timeout
  )
}

Upvotes: 1

Related Questions