@altano/vitest-plugins 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @altano/vitest-plugins
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 989abbb: added snapshot serializers and a matcher
8
+
9
+ ### Patch Changes
10
+
11
+ - 4c2162f: remove unused dependencies
12
+
3
13
  ## 0.2.0
4
14
 
5
15
  ### Minor Changes
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ /_ eslint-disable @typescript-eslint/no-empty-object-type _/
2
+
1
3
  # vitest-plugins
2
4
 
3
5
  [![npm](https://badgen.net/npm/v/@altano/vitest-plugins)](https://www.npmjs.com/package/@altano/vitest-plugins) ![Typed with TypeScript](https://badgen.net/npm/types/@altano/vitest-plugins) ![ESM only](https://badgen.net/badge/module/esm%20only?icon=js)
@@ -79,6 +81,14 @@ FormattedVFile {
79
81
 
80
82
  Will replace any instances of `process.cwd()` with `<cwd>` in the snapshot. Useful when serializing strings that contain absolute paths, since those will be different on other machines running the tests.
81
83
 
84
+ ### URLs
85
+
86
+ Canonicalizes parts of a URL that might not be deterministic in tests. Tries to be conservative, so at the moment, this only strips the port from localhost urls, e.g. `http://localhost:1234` is converted to `http://localhost`.
87
+
88
+ ### HTML
89
+
90
+ HTML is prettier formatted. Only works on well-formed HTML that starts with `<html` or `<!doctype`. To avoid infinitely reformatting the HTML, it is preprended with `<!-- Formatted HTML -->`.
91
+
82
92
  ## Matchers
83
93
 
84
94
  Vitest's error matchers let you match against the error message, but not the rest of the Error object:
@@ -124,7 +134,7 @@ expect("/private/some/path").toBePath("/some/path");
124
134
 
125
135
  ### toBeFile
126
136
 
127
- Verify a file exists
137
+ Verify a file exists (on the filesystem)
128
138
 
129
139
  ```ts
130
140
  expect(import.meta.filename).toBeFile();
@@ -132,7 +142,7 @@ expect(import.meta.filename).toBeFile();
132
142
 
133
143
  ### toBeDirectory
134
144
 
135
- Verify a directory exists
145
+ Verify a directory exists (on the filesystem)
136
146
 
137
147
  ```ts
138
148
  expect("/").toBeDirectory();
@@ -140,8 +150,20 @@ expect("/").toBeDirectory();
140
150
 
141
151
  ### toEqualFile
142
152
 
143
- Verify that the given path matches the contents of another file
153
+ Verify that the contents of a file at a given path match the contents of a file at a another path
144
154
 
145
155
  ```ts
146
156
  expect("/some/file.txt").toEqualFile("/other/file.txt");
147
157
  ```
158
+
159
+ ### toHaveExifProperty
160
+
161
+ Similar to the `toHaveProperty` matcher, but checks exif properties on the given buffer (or any object parseable by the `exifr` library).
162
+
163
+ ### toHaveHeader (on Response objects)
164
+
165
+ Verify that Response has an expected header and optional value
166
+
167
+ ### toHaveStatus (on Response objects)
168
+
169
+ Verify that a Response has an expected status code
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@altano/vitest-plugins",
3
- "version": "0.2.0",
3
+ "version": "1.0.0",
4
4
  "description": "Custom matchers and snapshot serializers to enhance vitest",
5
5
  "homepage": "https://github.com/altano/npm-packages/tree/main/packages/vitest-plugins",
6
6
  "repository": {
@@ -26,22 +26,21 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@prettier/sync": "^0.5.2",
29
+ "exifr": "^7.1.3",
29
30
  "serialize-error": "^11.0.3",
30
31
  "vfile": "^6.0.3",
31
- "vitest": "^2.1.3"
32
+ "vitest": "^3.0.9"
32
33
  },
33
34
  "devDependencies": {
34
- "@mdx-js/mdx": "^3.1.0",
35
- "@types/node": "^20.16.5",
36
- "@vitest/coverage-v8": "^2.1.3",
37
- "@vitest/expect": "^2.1.3",
38
- "eslint": "^9.13.0",
39
- "mdast-util-mdxjs-esm": "^2.0.1",
35
+ "@types/node": "^22.13.10",
36
+ "@vitest/coverage-v8": "^3.0.9",
37
+ "@vitest/expect": "^3.0.9",
38
+ "depcheck": "^1.4.7",
39
+ "eslint": "^9.22.0",
40
40
  "prettier": "^3.3.3",
41
- "typescript": "^5.6.3",
42
- "unified": "^11.0.5",
43
- "vite": "^5.4.10",
44
- "vitest": "^2.1.3",
41
+ "typescript": "^5.8.2",
42
+ "vite": "^6.2.3",
43
+ "vitest": "^3.0.9",
45
44
  "@altano/tsconfig": "0.0.0"
46
45
  },
47
46
  "publishConfig": {
@@ -50,6 +49,7 @@
50
49
  "scripts": {
51
50
  "check:types:src": "tsc --noEmit",
52
51
  "check:types:test": "tsc --noEmit --project ./tests/tsconfig.json",
52
+ "check:unused-dependencies": "depcheck",
53
53
  "clean": "rm -rf .turbo && rm -rf .tsbuildinfo && rm -rf node_modules && rm -rf dist",
54
54
  "format": "prettier --check src",
55
55
  "format:fix": "prettier --write src",
@@ -0,0 +1,26 @@
1
+ import type { Matcher } from "../matcher.js";
2
+
3
+ const toHaveHeader: Matcher = function (
4
+ response: Response,
5
+ header: string,
6
+ value?: string | number,
7
+ ) {
8
+ const headers = response.headers;
9
+ const hasProperty = headers.has(header);
10
+ const receivedValue = headers.get(header);
11
+
12
+ const { isNot } = this;
13
+
14
+ return {
15
+ message: () =>
16
+ value === undefined
17
+ ? `Received ${isNot ? "should not have" : "does not have"} the header "${header}"`
18
+ : `Header "${header}" ${isNot ? "should not be" : "is not"} expected value`,
19
+ pass:
20
+ hasProperty && (value === undefined || this.equals(receivedValue, value)),
21
+ actual: receivedValue,
22
+ expected: value,
23
+ };
24
+ };
25
+
26
+ export default toHaveHeader;
@@ -0,0 +1,20 @@
1
+ import type { Matcher } from "../matcher.js";
2
+
3
+ const toHaveStatus: Matcher = function (
4
+ response: Response,
5
+ expectedStatus: number,
6
+ ) {
7
+ const receivedStatus = response.status;
8
+
9
+ const { isNot } = this;
10
+
11
+ return {
12
+ message: () =>
13
+ `Status ${isNot ? "should not be expected value" : "is not expected value"}`,
14
+ pass: this.equals(receivedStatus, expectedStatus),
15
+ actual: receivedStatus,
16
+ expected: expectedStatus,
17
+ };
18
+ };
19
+
20
+ export default toHaveStatus;
@@ -6,12 +6,20 @@ import toBeDirectory from "./toBeDirectory.js";
6
6
  import toEqualFile from "./toEqualFile.js";
7
7
  import toMatchError from "./toMatchError.js";
8
8
  import toThrowErrorMatching from "./toThrowErrorMatching.js";
9
+ import toHaveExifProperty from "./toHaveExifProperty.js";
10
+ import toHaveHeader from "./response/toHaveHeader.js";
11
+ import toHaveStatus from "./response/toHaveStatus.js";
9
12
 
10
13
  expect.extend({
11
- toBePath,
12
- toBeFile,
13
14
  toBeDirectory,
15
+ toBeFile,
16
+ toBePath,
14
17
  toEqualFile,
18
+ toHaveExifProperty,
15
19
  toMatchError,
16
20
  toThrowErrorMatching,
21
+
22
+ // Response matchers
23
+ toHaveHeader,
24
+ toHaveStatus,
17
25
  });
@@ -0,0 +1,32 @@
1
+ import { parse } from "exifr";
2
+ import type { Matcher } from "./matcher.js";
3
+
4
+ export type Input = Parameters<typeof parse>[0];
5
+
6
+ const toHaveExifProperty: Matcher = async function (
7
+ buffer: Input,
8
+ property: string,
9
+ value?: string | number,
10
+ ) {
11
+ const exifData = (await parse(buffer)) as unknown;
12
+ const hasProperty = Object.prototype.hasOwnProperty.call(exifData, property);
13
+
14
+ const receivedValue =
15
+ // @ts-expect-error we're checking for property existence, so obviously this
16
+ // might not be valid. don't need a TS error to tell us that.
17
+ exifData[property] as unknown;
18
+ const { isNot } = this;
19
+
20
+ return {
21
+ message: () =>
22
+ value === undefined
23
+ ? `Received ${isNot ? "should not have" : "does not have"} the property "${property}"`
24
+ : `Property "${property}" ${isNot ? "should not be expected value" : "is not expected value"}`,
25
+ pass:
26
+ hasProperty && (value === undefined || this.equals(receivedValue, value)),
27
+ actual: receivedValue,
28
+ expected: value,
29
+ };
30
+ };
31
+
32
+ export default toHaveExifProperty;
@@ -4,18 +4,57 @@ import type { Assertion, AsymmetricMatchersContaining } from "vitest";
4
4
 
5
5
  interface CustomMatchers<R = unknown> {
6
6
  /**
7
- * compare the realpath (canonical path) of expected/received
7
+ * Verify the realpath (canonical path) of expected. More lenient than a
8
+ * string check when dealing with logical paths, symlinks, etc.
8
9
  */
9
10
  toBePath(expected: string): R;
11
+ /** Verify a file exists (on the filesystem) */
10
12
  toBeFile(): R;
13
+ /** Verify a directory exists (on the filesystem) */
11
14
  toBeDirectory(): R;
15
+ /** Verify that the contents of a file at a given path match the contents of a file at a another path */
12
16
  toEqualFile(pathOfFileWithExpectedContents: string): R;
17
+ /**
18
+ * Similar to the `toHaveProperty` matcher, but checks exif properties on the
19
+ * given buffer (or any object parseable by the `exifr` library).
20
+ */
21
+ toHaveExifProperty(property: string, value?: string | number): Promise<R>;
22
+ /**
23
+ * Verify any part of an error object (e.g. the stack):
24
+ *
25
+ * @example
26
+ * expect(new Error("face")).toMatchError(
27
+ * expect.objectContaining({
28
+ * stack: expect.stringContaining("readme.spec.ts"),
29
+ * }),
30
+ * );
31
+ */
13
32
  toMatchError(expected: unknown): R;
33
+ /**
34
+ * Verify any part of a _thrown_ error object (e.g. the stack):
35
+ *
36
+ * @example
37
+ * expect(() => {
38
+ * throw new Error("face");
39
+ * }).toThrowErrorMatching(
40
+ * expect.objectContaining({
41
+ * stack: expect.stringContaining("readme.spec.ts"),
42
+ * }),
43
+ * );
44
+ */
14
45
  toThrowErrorMatching(expected: unknown): R;
15
46
  }
16
47
 
48
+ interface ResponseMatchers<R = unknown> {
49
+ /** Verify that Response has an expected header and optional value */
50
+ toHaveHeader(header: string, value?: string | number): R;
51
+ /** Verify that a Response has an expected status code */
52
+ toHaveStatus(expectedStatus: number): R;
53
+ }
54
+
17
55
  /* eslint-disable @typescript-eslint/no-empty-object-type */
18
56
  declare module "vitest" {
19
57
  interface Assertion<T> extends CustomMatchers<T> {}
58
+ interface Assertion<T> extends ResponseMatchers<T> {}
20
59
  interface AsymmetricMatchersContaining extends CustomMatchers {}
21
60
  }
@@ -0,0 +1,39 @@
1
+ import prettier from "@prettier/sync";
2
+ import prettierConfig from "./.prettierrc.json" with { type: "json" };
3
+ import type { Options } from "prettier";
4
+ import type { SnapshotSerializer } from "vitest";
5
+
6
+ const htmlPattern = /^(<html|<!doctype)/gi;
7
+
8
+ /**
9
+ * Prettier format html
10
+ */
11
+ function formatHtml(unformattedHtml: string): string {
12
+ try {
13
+ const formattedHtml = prettier
14
+ .format(unformattedHtml, {
15
+ filepath: "index.html",
16
+ ...(prettierConfig as Options),
17
+ })
18
+ .trim();
19
+ return `<!-- Formatted HTML -->
20
+ ${formattedHtml}`;
21
+ } catch (e: unknown) {
22
+ // Prettier can't parse this text as html. That's fine, pass it through
23
+ // unformatted.
24
+ return unformattedHtml;
25
+ }
26
+ }
27
+
28
+ const serializer: SnapshotSerializer = {
29
+ serialize(val: string, config, indentation, depth, refs, printer) {
30
+ const formattedHtml = formatHtml(val);
31
+ // Wrap the text to prevent infinite recursion
32
+ return printer(formattedHtml, config, indentation, depth, refs);
33
+ },
34
+ test(val) {
35
+ return typeof val === "string" && htmlPattern.test(val);
36
+ },
37
+ };
38
+
39
+ export default serializer;
@@ -3,5 +3,11 @@ import { expect } from "vitest";
3
3
  import absolutePathSerializer from "./absolutePath.js";
4
4
  expect.addSnapshotSerializer(absolutePathSerializer);
5
5
 
6
+ import urlSerializer from "./url.js";
7
+ expect.addSnapshotSerializer(urlSerializer);
8
+
6
9
  import vFileSerializer from "./vFile.js";
7
10
  expect.addSnapshotSerializer(vFileSerializer);
11
+
12
+ import htmlSerializer from "./html.js";
13
+ expect.addSnapshotSerializer(htmlSerializer);
@@ -0,0 +1,21 @@
1
+ import type { SnapshotSerializer } from "vitest";
2
+
3
+ const localhostPattern = /(https?:\/\/localhost):[0-9]+/gi;
4
+
5
+ /**
6
+ * Strip the (potentially random) port from the URL
7
+ */
8
+ function stripPort(str: string): string {
9
+ return str.replaceAll(localhostPattern, "$1");
10
+ }
11
+
12
+ const urlSerializer: SnapshotSerializer = {
13
+ serialize(val: string, config, indentation, depth, refs, printer) {
14
+ return printer(stripPort(val), config, indentation, depth, refs);
15
+ },
16
+ test(val) {
17
+ return typeof val === "string" && localhostPattern.test(val);
18
+ },
19
+ };
20
+
21
+ export default urlSerializer;
@@ -1,5 +1,5 @@
1
1
  import prettier from "@prettier/sync";
2
- import prettierConfig from "./.prettierrc.json";
2
+ import prettierConfig from "./.prettierrc.json" with { type: "json" };
3
3
  import { VFile, type Value as VFileValue } from "vfile";
4
4
  import type { Options } from "prettier";
5
5
  import type { SnapshotSerializer } from "vitest";
@@ -5,7 +5,7 @@ describe("readme", () => {
5
5
  it("should describe toMatchError", () => {
6
6
  expect(new Error("face")).toMatchError(
7
7
  expect.objectContaining({
8
- stack: expect.stringContaining("readme.spec.ts"),
8
+ stack: expect.stringContaining("readme.spec.ts") as unknown,
9
9
  }),
10
10
  );
11
11
  });
@@ -14,7 +14,7 @@ describe("readme", () => {
14
14
  throw new Error("face");
15
15
  }).toThrowErrorMatching(
16
16
  expect.objectContaining({
17
- stack: expect.stringContaining("readme.spec.ts"),
17
+ stack: expect.stringContaining("readme.spec.ts") as unknown,
18
18
  }),
19
19
  );
20
20
  });
@@ -0,0 +1,49 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import "../../../../src/matchers/setup";
3
+
4
+ describe("toHaveHeader", () => {
5
+ const r = new Response("", {
6
+ headers: {
7
+ "Content-Type": "image/png",
8
+ },
9
+ });
10
+
11
+ it("should pass when the property exists", async () => {
12
+ expect(r).toHaveHeader("Content-Type");
13
+ });
14
+ it("should pass when the property doesn't exist", async () => {
15
+ expect(r).not.toHaveHeader("face");
16
+ });
17
+ it("should pass when the property value is correct", async () => {
18
+ expect(r).toHaveHeader("Content-Type", "image/png");
19
+ });
20
+ it("should pass when the property value is incorrect", async () => {
21
+ expect(r).not.toHaveHeader("Content-Type", 15);
22
+ expect(r).not.toHaveHeader("face", 15);
23
+ });
24
+ it("should error when the property should not exist but does", async () => {
25
+ expect(() =>
26
+ expect(r).not.toHaveHeader("Content-Type"),
27
+ ).toThrowErrorMatchingInlineSnapshot(`[Error: Received should not have the header "Content-Type"]`);
28
+ });
29
+ it("should error when the property should exist but doesn't", async () => {
30
+ expect(() =>
31
+ expect(r).toHaveHeader("face"),
32
+ ).toThrowErrorMatchingInlineSnapshot(`[Error: Received does not have the header "face"]`);
33
+ });
34
+ it("should error when the value should not match but does", async () => {
35
+ expect(() =>
36
+ expect(r).not.toHaveHeader("Content-Type", "image/png"),
37
+ ).toThrowErrorMatchingInlineSnapshot(`[Error: Header "Content-Type" should not be expected value]`);
38
+ });
39
+ it("should error when the value should match but doesn't", async () => {
40
+ expect(() =>
41
+ expect(r).toHaveHeader("Content-Type", 17),
42
+ ).toThrowErrorMatchingInlineSnapshot(`[Error: Header "Content-Type" is not expected value]`);
43
+ });
44
+ it("should error when a non-buffer is passed in", async () => {
45
+ expect(() =>
46
+ expect(1234).toHaveHeader("face"),
47
+ ).toThrowErrorMatchingInlineSnapshot(`[TypeError: Cannot read properties of undefined (reading 'has')]`);
48
+ });
49
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import "../../../../src/matchers/setup";
3
+
4
+ const getResponse = (status: number): Response =>
5
+ new Response("", {
6
+ status,
7
+ });
8
+
9
+ describe("toHaveStatus", () => {
10
+ const status200 = getResponse(200);
11
+ const status404 = getResponse(404);
12
+
13
+ it("should pass when the status is correct", async () => {
14
+ expect(status200).toHaveStatus(200);
15
+ expect(status404).toHaveStatus(404);
16
+ });
17
+ it("should pass when the status is incorrect", async () => {
18
+ expect(status200).not.toHaveStatus(500);
19
+ expect(status404).not.toHaveStatus(500);
20
+ });
21
+ it("should error when the value should not match but does", async () => {
22
+ expect(() =>
23
+ expect(status200).not.toHaveStatus(200),
24
+ ).toThrowErrorMatchingInlineSnapshot(
25
+ `[Error: Status should not be expected value]`,
26
+ );
27
+ });
28
+ it("should error when the value should match but doesn't", async () => {
29
+ expect(() =>
30
+ expect(status200).toHaveStatus(500),
31
+ ).toThrowErrorMatchingInlineSnapshot(
32
+ `[Error: Status is not expected value]`,
33
+ );
34
+ });
35
+ it("should error when a non-Response is passed in", async () => {
36
+ expect(() =>
37
+ expect(1234).toHaveStatus(3),
38
+ ).toThrowErrorMatchingInlineSnapshot(
39
+ `[Error: Status is not expected value]`,
40
+ );
41
+ });
42
+ });
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import "../../../src/matchers/setup";
3
+
4
+ describe("toHaveExifProperty", () => {
5
+ const buffer = Buffer.from(
6
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2O4v3EyBwAGwgIsY3pRcwAAAABJRU5ErkJggg==",
7
+ "base64url",
8
+ );
9
+
10
+ it("should pass when the property exists", async () => {
11
+ await expect(buffer).toHaveExifProperty("ImageWidth");
12
+ });
13
+ it("should pass when the property doesn't exist", async () => {
14
+ await expect(buffer).not.toHaveExifProperty("face");
15
+ });
16
+ it("should pass when the property value is correct", async () => {
17
+ await expect(buffer).toHaveExifProperty("ImageHeight", 1);
18
+ await expect(buffer).toHaveExifProperty("ImageWidth", 1);
19
+ });
20
+ it("should pass when the property value is incorrect", async () => {
21
+ await expect(buffer).not.toHaveExifProperty("ImageWidth", 15);
22
+ await expect(buffer).not.toHaveExifProperty("face", 15);
23
+ });
24
+ it("should error when the property should not exist but does", async () => {
25
+ await expect(async () =>
26
+ expect(buffer).not.toHaveExifProperty("ImageWidth"),
27
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
28
+ `[Error: Received should not have the property "ImageWidth"]`,
29
+ );
30
+ });
31
+ it("should error when the property should exist but doesn't", async () => {
32
+ await expect(async () =>
33
+ expect(buffer).toHaveExifProperty("face"),
34
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
35
+ `[Error: Received does not have the property "face"]`,
36
+ );
37
+ });
38
+ it("should error when the value should not match but does", async () => {
39
+ await expect(async () =>
40
+ expect(buffer).not.toHaveExifProperty("ImageWidth", 1),
41
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
42
+ `[Error: Property "ImageWidth" should not be expected value]`,
43
+ );
44
+ });
45
+ it("should error when the value should match but doesn't", async () => {
46
+ await expect(async () =>
47
+ expect(buffer).toHaveExifProperty("ImageWidth", 17),
48
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
49
+ `[Error: Property "ImageWidth" is not expected value]`,
50
+ );
51
+ });
52
+ it("should error when a non-buffer is passed in", async () => {
53
+ await expect(async () =>
54
+ expect(1234).toHaveExifProperty("face"),
55
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
56
+ `[Error: Invalid input argument]`,
57
+ );
58
+ });
59
+ });
@@ -8,14 +8,14 @@ describe("matchers", () => {
8
8
  expect.objectContaining({
9
9
  message: "face",
10
10
  name: "Error",
11
- stack: expect.any(String),
11
+ stack: expect.any(String) as unknown,
12
12
  }),
13
13
  );
14
14
  });
15
15
  it("should match an error by substring", () => {
16
16
  expect(new Error("your stupid face")).toMatchError(
17
17
  expect.objectContaining({
18
- message: expect.stringContaining("stupid"),
18
+ message: expect.stringContaining("stupid") as unknown,
19
19
  }),
20
20
  );
21
21
  });
@@ -0,0 +1,58 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import htmlSerializer from "../../../src/serializers/html.js";
4
+ expect.addSnapshotSerializer(htmlSerializer);
5
+
6
+ describe("serializers", () => {
7
+ describe("html", () => {
8
+ it("should prettier format the html", () => {
9
+ expect(
10
+ `<html><head><title>your face</title></head><body>is stupid</body></html>`,
11
+ ).toMatchInlineSnapshot(`
12
+ "<!-- Formatted HTML -->
13
+ <html>
14
+ <head>
15
+ <title>your face</title>
16
+ </head>
17
+ <body>
18
+ is stupid
19
+ </body>
20
+ </html>"
21
+ `);
22
+ });
23
+ it("should ignore already formatted html", () => {
24
+ const html = `
25
+ <html>
26
+ <head>
27
+ <title>your face</title>
28
+ </head>
29
+ <body>
30
+ is stupid
31
+ </body>
32
+ </html>"
33
+ `;
34
+ expect(html).toMatchInlineSnapshot(`
35
+ "
36
+ <html>
37
+ <head>
38
+ <title>your face</title>
39
+ </head>
40
+ <body>
41
+ is stupid
42
+ </body>
43
+ </html>"
44
+ "
45
+ `);
46
+ });
47
+ it("should ignore non-html strings", () => {
48
+ expect(`I'm just some content that isn't html`).toMatchInlineSnapshot(
49
+ `"I'm just some content that isn't html"`,
50
+ );
51
+ });
52
+ it("should ignore malformed html", () => {
53
+ expect(`<html><p>oiajsdfpoiajsdf</a></q></face>`).toMatchInlineSnapshot(`
54
+ "<html><p>oiajsdfpoiajsdf</a></q></face>"
55
+ `);
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import urlSerializer from "../../../src/serializers/url.js";
4
+ expect.addSnapshotSerializer(urlSerializer);
5
+
6
+ describe("serializers", () => {
7
+ describe("url", () => {
8
+ it("should remove the port in a localhost http[s] url", () => {
9
+ expect(
10
+ `String with http://localhost:1234/path/to/face url`,
11
+ ).toMatchInlineSnapshot(`"String with http://localhost/path/to/face url"`);
12
+ });
13
+ });
14
+ });