Шутка: ожидание против setImmediate против useFakeTimers против нового обещания (setImmediate)

Далее следует тест Jest на TypeScript. Мне интересно, зачем нужен setImmediate().

Первый пример - это тест, который работает. Затем я пробовал разные вещи, которые не работают. Я не понимаю, что происходит. Подпись для pubsub.publish:(method) PubSub.publish(triggerName: string, payload: any): Promise<void>

  test.only('subscriptions', async () => {
    const document = parse(`
      subscription {
        create 
      }
    `)

    const sub = <AsyncIterator<ExecutionResult>>await subscribe(schema, document);

    expect(sub.next).toBeDefined()

    // setInterval and process.nextTick also work here:
    setImmediate(() => pubsub.publish('CREATE_ONE', { create: "FLUM!" }))  // this works


    const { value: { errors, data } } = await sub.next()

    expect(errors).toBeUndefined()
    expect(data).toBeDefined()
    expect(data.create).toBe('FLUM!')
  }, 10000)

Вот и другие вещи, которые я пробовал, некоторые после поиска ответов на похожие вопросы. Все эти попытки терпят неудачу с исключением тайм-аута в тесте:



  test.only('subscriptions', async () => {
  // attempt #1: jest.useFakeTimers()

    const document = parse(`
      subscription {
        create 
      }
    `)

    const sub = <AsyncIterator<ExecutionResult>>await subscribe(schema, document);

    expect(sub.next).toBeDefined()

    // #1, cont: 
    // pubsub.publish('CREATE_ONE', { create: "FLUM!" })
    // or...
    // await pubsub.publish('CREATE_ONE', { create: "FLUM!" })
    // this works, though, like in previous test, but with fake timers:
    // setImmediate(() => pubsub.publish('CREATE_ONE', { create: "FLUM!" }))


    // attempt #2:
    // await pubsub.publish('CREATE_ONE', { create: "FLUM!" })

    // attempt #3:
    // pubsub.publish('CREATE_ONE', { create: "FLUM!" })
    // await new Promise(setImmediate)

    // attempt #3a (variant):
    // await new Promise((resolve) => setImmediate(resolve));

    const { value: { errors, data } } = await sub.next()

    expect(errors).toBeUndefined()
    expect(data).toBeDefined()
    expect(data.create).toBe('FLUM!')
  }, 10000)

Я понимаю, что setImmediate помещает функцию в цикл событий, которая будет выполняться сразу после любых ожидающих событий ввода-вывода. Я не уверен, зачем это нужно, потому что pubsub.publish() возвращает обещание, которое можно обработать с помощью await, но в этом случае происходит то, что следующая строка await sub.next() никогда не вызывается.

Я думаю, что в pubsub.publish() выполняется вызов setInterval, а setImmediate ожидает завершения любых ожидающих событий setInterval (мое понимание этого нечеткое). Попытки 3 и 3a - это механизмы, которые я нашел в другом месте для этого, но в данном случае они, похоже, не работают.

Вопрос: почему этот тест требует для прохождения setImmediate?

2 ответа

Решение

Итак, мое замешательство связано с тем, что делает setImmediate, а что не делает. Вот что происходит:

    // setInterval and process.nextTick also work here:
    setImmediate(() => pubsub.publish('CREATE_ONE', { create: "FLUM!" })) 
    const { value: { errors, data } } = await sub.next()

Без setImmediate() событие публикации отправляется до вызова sub.next(), поэтому оно не фиксируется. Вы могли подумать, что setImmediate(или process.nextTick) вызовет немедленное выполнение функции публикации, но нет. Вместо этого setImmediate задерживает вызов публикации на время, достаточное для выполнения sub.next().

Теперь я собираюсь прочитать немного о том, как на самом деле работают setImmediate и process.nextTick.

Этот ответ не имеет отношения к вопросу, но кто когда-либо придет сюда для модульного тестирования подписки на Apollo, вот как написать модульный тест. Этот тест помог мне протестировать подписку на Graphql.

      it('should execute the subscription using subscribe', async () => {

const query = `
  query getData (
    $id: ID!
  ) {
    data(taskId: $id) {
      // fields you want to query
    }
  }
`;

const subscription = `
  subscription {
    // fields you want to query
  }
`;

const rootValue = {};
const contextValue = getContext();
const variableValues = {
  id: someId,
};

const args = {
  schema, source: query, rootValue, contextValue, variableValues
};

const subscriptionArgs = {
  schema, document: parse(subscription)
};

// subscribing
const iterator = <AsyncIterator<ExecutionResult>> await subscribe(subscriptionArgs);
expect(iterator.next).toBeDefined();

// triggering the query to publish the event
setImmediate(() => graphql(queryArgs));

// get the next event result
const result = await iterator.next();

expect(result.value.data).toEqual(expectedResult);

});

Ссылка: https://dev.to/augustocalaca/how-to-test-graphql-subscriptions-4mldhttps://gist.github.com/AugustoCalaca/60be39bc6825d01281a110e108063af0

Другие вопросы по тегам