node.js - Η χρήση ενός asyncIterator μέσα σε ένα unit test ποτέ δεν επιστρέφει τιμές


Έχω ένα αναγνώσιμο stream από το chatGPT στο οποίο προσπαθώ να κάνω assertion χρησιμοποιώντας ένα asyncIterator και στη συνέχεια να διαβάσω αυτές τις τιμές και να κάνω assertion πάνω τους. Το τεστ jest τρέχει κανονικά αλλά υπάρχει ένα σφάλμα στη λογική μου που εμποδίζει την επίλυσή του μετά από κάθε επανάληψη.

Τι μου λείπει;

Ευχαριστώ Τζίμι

var util = require("util");

describe("stream", () => {
  it("should work", async () => {
    let i = -1;
    const completionStream: ChatCompletionStreamParams = {
      toReadableStream: () => {
        const mockReadable = {
          async *[Symbol.asyncIterator]() {
            const encoder = new util.TextEncoder("utf-8");
            yield encoder.encode(
              JSON.stringify({
                id: "1",
                object: "text",
                created: 1629159835,
                model: "gpt4",
                choices: [
                  {
                    index: 0,
                    delta: { content: "Hello" },
                    finish_reason: null,
                  },
                ],
              })
            ).buffer;
            yield encoder.encode(
              JSON.stringify({
                id: "1",
                object: "text",
                created: 1629159835,
                model: "gpt4",
                choices: [
                  {
                    index: 0,
                    delta: { content: "there" },
                    finish_reason: null,
                  },
                ],
              })
            ).buffer;
            yield null;
          },
          getReader: () => {
            return {
              read: async () => {
                const result = await mockReadable[
                  Symbol.asyncIterator
                ]().next();
                i++;
                if (i >= 2) {
                  return Promise.resolve({ done: true, value: null });
                }
                return Promise.resolve({ done: false, value: result?.value });
              },
            };
          },
        };
        return mockReadable;
      },
    };

    const readable = completionStream.toReadableStream().getReader();

    while (true) {
      const { done, value } = await readable.read();
      expect(done).toBe(false); // assert here
    }
  });
});

Απάντηση #1

Έκανες ένα λάθος στο getReader στο μέρος mockReadable[Symbol.asyncIterator](). Καλείται κάθε φορά που καλείς readable.read(), το οποίο δημιουργεί έναν νέο ασύγχρονο επαναλήπτη από το μηδέν, και έτσι συνεχίζει να επιστρέφει το "Hello" και ποτέ δεν φτάνει στο "there".

Πρέπει να αποθηκεύσεις τον επαναληπτικό και να τον ξαναχρησιμοποιήσεις.

getReader: () => {
  const iterator = mockReadable[Symbol.asyncIterator]();
  return {
    read: async () => {
      const result = await iterator.next();
      return result;
    }

    // in fact you can just re-expose `iterator.next` as `read` like
    // read: iterator.next.bind(iterator),
  };
}

Απάντηση #2

θα λειτουργήσει αρχείο:

it("should work", async () => {
  let i = -1;
  const completionStream: ChatCompletionStreamParams = {
    toReadableStream: () => {
      const mockReadable = {
        async *[Symbol.asyncIterator]() {
          const encoder = new util.TextEncoder("utf-8");
          yield encoder.encode(
            JSON.stringify({
              id: "1",
              object: "text",
              created: 1629159835,
              model: "gpt4",
              choices: [
                {
                  index: 0,
                  delta: { content: "Hello" },
                  finish_reason: null,
                },
              ],
            })
          ).buffer;
          yield encoder.encode(
            JSON.stringify({
              id: "1",
              object: "text",
              created: 1629159835,
              model: "gpt4",
              choices: [
                {
                  index: 0,
                  delta: { content: "there" },
                  finish_reason: null,
                },
              ],
            })
          ).buffer;
          yield null;
        },
        getReader: () => {
          return {
            read: async () => {
              const result = await mockReadable[
                Symbol.asyncIterator
              ]().next();
              i++;
              if (i >= 2) {
                return Promise.resolve({ done: true, value: null });
              }
              return Promise.resolve({ done: false, value: result?.value });
            },
          };
        },
      };
      return mockReadable;
    },
  };

  const readable = completionStream.toReadableStream().getReader();

  while (true) {
    const { done, value } = await readable.read();
    expect(done).toBe(false); // assert here

    if (done) {
      break; // exit the loop when done is true
    }
  }
});