|
| 1 | +import { fileURLToPath } from "node:url"; |
| 2 | + |
| 3 | +import { createCoverageMap } from "@vitest/istanbul-lib-coverage"; |
| 4 | +import { describe, it, expect } from "vitest"; |
| 5 | + |
| 6 | +import { create, createAsync, createContext, ReportBase } from "../src/index"; |
| 7 | +import type { PartialVisitor, ReportNode } from "../src/index"; |
| 8 | + |
| 9 | +const fixture = (name: string): string => |
| 10 | + fileURLToPath(new URL(`./fixtures/custom-reports/${name}`, import.meta.url)); |
| 11 | + |
| 12 | +describe("create", () => { |
| 13 | + it("creates built-in reports", () => { |
| 14 | + expect(create("text")).toBeInstanceOf(ReportBase); |
| 15 | + expect(create("json", { file: "out.json" })).toBeInstanceOf(ReportBase); |
| 16 | + }); |
| 17 | + |
| 18 | + it("throws for unknown reports", () => { |
| 19 | + expect(() => create("does-not-exist" as "text")).toThrowErrorMatchingInlineSnapshot( |
| 20 | + `[Error: Unknown report "does-not-exist". Use createAsync() to load custom reports.]`, |
| 21 | + ); |
| 22 | + }); |
| 23 | + |
| 24 | + it("does not resolve names via the Object prototype", () => { |
| 25 | + expect(() => create("constructor" as "text")).toThrow(/Unknown report/); |
| 26 | + }); |
| 27 | +}); |
| 28 | + |
| 29 | +describe("createAsync", () => { |
| 30 | + it("creates built-in reports", async () => { |
| 31 | + const report = await createAsync("text"); |
| 32 | + expect(report).toBeInstanceOf(ReportBase); |
| 33 | + }); |
| 34 | + |
| 35 | + it("does not resolve names via the Object prototype", async () => { |
| 36 | + await expect(createAsync("toString")).rejects.toThrow(); |
| 37 | + }); |
| 38 | + |
| 39 | + it.each([ |
| 40 | + ["CommonJS", "cjs.cjs", "CjsReport"], |
| 41 | + ["CommonJS transpiled from ESM", "cjs-transpiled.cjs", "TranspiledReport"], |
| 42 | + ["ESM", "esm.mjs", "EsmReport"], |
| 43 | + ["ESM with top-level await", "esm-tla.mjs", "EsmTlaReport"], |
| 44 | + ])("loads a custom %s report from an absolute path", async (_, file, className) => { |
| 45 | + const cfg = { file: "out.md" }; |
| 46 | + const report = (await createAsync(fixture(file), cfg)) as unknown as { opts: object }; |
| 47 | + |
| 48 | + expect(report.constructor.name).toBe(className); |
| 49 | + expect(report.opts).toBe(cfg); |
| 50 | + }); |
| 51 | + |
| 52 | + it("loads a custom report from a file:// URL", async () => { |
| 53 | + const url = new URL("./fixtures/custom-reports/esm.mjs", import.meta.url).href; |
| 54 | + const report = await createAsync(url); |
| 55 | + expect(report.constructor.name).toBe("EsmReport"); |
| 56 | + }); |
| 57 | + |
| 58 | + it.each([ |
| 59 | + ["CommonJS", "cjs.cjs", ["start cjs", "end cjs"]], |
| 60 | + ["ESM", "esm.mjs", ["start esm", "end esm"]], |
| 61 | + ])("runs a custom %s report through the report tree", async (_, file, lines) => { |
| 62 | + const report = (await createAsync(fixture(file))) as unknown as PartialVisitor<ReportNode> & { |
| 63 | + lines: string[]; |
| 64 | + }; |
| 65 | + const context = createContext({ coverageMap: createCoverageMap({}) }); |
| 66 | + |
| 67 | + context.getTree().visit(report, context); |
| 68 | + |
| 69 | + expect(report.lines).toEqual(lines); |
| 70 | + }); |
| 71 | + |
| 72 | + it("rejects modules without a report class as default export", async () => { |
| 73 | + await expect(createAsync(fixture("named-only.mjs"))).rejects.toThrow( |
| 74 | + /must export a report class as its default export/, |
| 75 | + ); |
| 76 | + }); |
| 77 | + |
| 78 | + it("rejects unresolvable reports", async () => { |
| 79 | + await expect(createAsync("@vitest/this-report-does-not-exist")).rejects.toThrow(); |
| 80 | + }); |
| 81 | +}); |
0 commit comments