WritableStream.spec.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { createReadStream } from "node:fs";
  2. import * as fs from "node:fs/promises";
  3. import * as stream from "node:stream";
  4. import { describe, it, expect, vi } from "vitest";
  5. import type { Handler, ParserOptions } from "./Parser.js";
  6. import { WritableStream } from "./WritableStream.js";
  7. import * as helper from "./__fixtures__/testHelper.js";
  8. describe("WritableStream", () => {
  9. it("should decode fragmented unicode characters", () => {
  10. const ontext = vi.fn();
  11. const stream = new WritableStream({ ontext });
  12. stream.write(Buffer.from([0xe2, 0x82]));
  13. stream.write(Buffer.from([0xac]));
  14. stream.write("");
  15. stream.end();
  16. expect(ontext).toHaveBeenCalledWith("€");
  17. });
  18. it("Basic html", () => testStream("Basic.html"));
  19. it("Attributes", () => testStream("Attributes.html"));
  20. it("SVG", () => testStream("Svg.html"));
  21. it("RSS feed", () => testStream("RSS_Example.xml", { xmlMode: true }));
  22. it("Atom feed", () => testStream("Atom_Example.xml", { xmlMode: true }));
  23. it("RDF feed", () => testStream("RDF_Example.xml", { xmlMode: true }));
  24. });
  25. function getPromiseEventCollector(): [
  26. handler: Partial<Handler>,
  27. promise: Promise<unknown>,
  28. ] {
  29. let handler: Partial<Handler> | undefined;
  30. const promise = new Promise<unknown>((resolve, reject) => {
  31. handler = helper.getEventCollector((error, events) => {
  32. if (error) {
  33. reject(error);
  34. } else {
  35. resolve(events);
  36. }
  37. });
  38. });
  39. return [handler!, promise];
  40. }
  41. // TODO[engine:node@>=16]: Use promise version of `stream.finished` instead.
  42. function finished(input: Parameters<typeof stream.finished>[0]): Promise<void> {
  43. return new Promise((resolve, reject) => {
  44. stream.finished(input, (error) => (error ? reject(error) : resolve()));
  45. });
  46. }
  47. async function testStream(
  48. file: string,
  49. options?: ParserOptions,
  50. ): Promise<void> {
  51. const filePath = new URL(`__fixtures__/Documents/${file}`, import.meta.url);
  52. const [streamHandler, eventsPromise] = getPromiseEventCollector();
  53. const fsStream = createReadStream(filePath).pipe(
  54. new WritableStream(streamHandler, options),
  55. );
  56. await finished(fsStream);
  57. const events = await eventsPromise;
  58. expect(events).toMatchSnapshot();
  59. const [singlePassHandler, singlePassPromise] = getPromiseEventCollector();
  60. const singlePassStream = new WritableStream(singlePassHandler, options).end(
  61. await fs.readFile(filePath),
  62. );
  63. await finished(singlePassStream);
  64. expect(await singlePassPromise).toStrictEqual(events);
  65. }