import { describe, expect, it } from "vitest"; import { EditorState } from "@codemirror/state"; import { ensureSyntaxTree } from "@codemirror/language"; import { bodyKind, formatMs, formatSize, prettyBody, prettyMarkup } from "./format"; import { httpLanguage } from "./language"; describe("response bodies", () => { it("detects the kind from the content type, else the content", () => { expect(bodyKind("application/json; charset=utf-8", "x")).toBe("json"); expect(bodyKind("application/problem+json", "x")).toBe("json"); expect(bodyKind("text/html", "")).toBe("html"); expect(bodyKind("application/xml", "")).toBe("xml"); expect(bodyKind(null, ' {"a":1}')).toBe("json"); expect(bodyKind(null, "{not json")).toBe("text"); expect(bodyKind(null, "")).toBe("html"); expect(bodyKind(null, "")).toBe("xml"); expect(bodyKind(null, "plain")).toBe("text"); }); it("pretty-prints JSON and leaves invalid JSON alone", () => { expect(prettyBody("json", '{"a":[1,2],"b":null}')).toBe('{\n "a": [\n 1,\n 2\n ],\n "b": null\n}'); expect(prettyBody("json", "{oops")).toBe("{oops"); }); it("re-indents XML, keeping text-only elements on one line", () => { expect(prettyMarkup('1x')).toBe( ['', "", " 1", " ", " ", " x", " ", " ", ""].join("\n"), ); }); it("re-indents HTML with void elements and raw script contents", () => { const html = "

Hi


"; expect(prettyMarkup(html, true)).toBe( [ "", " ", " ", " ", " ", " ", "

Hi

", "
", " ", "", ].join("\n"), ); }); it("formats sizes and durations", () => { expect(formatSize(512)).toBe("512 B"); expect(formatSize(2048)).toBe("2.0 KB"); expect(formatSize(null)).toBe("0 B"); expect(formatMs(12.4)).toBe("12 ms"); expect(formatMs(1500)).toBe("1.50 s"); }); }); describe("http highlighting", () => { function tokens(text: string): Array<[string, string]> { const state = EditorState.create({ doc: text, extensions: httpLanguage }); const tree = ensureSyntaxTree(state, state.doc.length, 5000)!; const out: Array<[string, string]> = []; tree.iterate({ enter: (n) => { if (n.name !== "Document" && n.from < n.to) out.push([n.name, state.sliceDoc(n.from, n.to)]); }, }); return out; } it("tags separators, methods, URLs, headers, variables and comments", () => { const t = tokens("### Users\n# @name list\nGET https://{{host}}/users\nAccept: json\n\n{\"a\": 1}\n"); const has = (name: string, text: string) => t.some(([n, s]) => n.includes(name) && s === text); expect(has("heading", "### Users")).toBe(true); expect(has("keyword", "GET")).toBe(true); expect(has("link", "https://")).toBe(true); expect(has("variableName", "{{host}}")).toBe(true); expect(has("propertyName", "Accept")).toBe(true); expect(has("string", ' json')).toBe(true); expect(has("string", '"a"')).toBe(true); expect(has("number", "1")).toBe(true); expect(has("meta", "# @name")).toBe(true); }); });