@altano/vitest-plugins 0.0.2
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/.eslintrc.cjs +19 -0
- package/.turbo/turbo-lint.log +5 -0
- package/CHANGELOG.md +7 -0
- package/README.md +115 -0
- package/package.json +64 -0
- package/src/matchers/matcher.ts +5 -0
- package/src/matchers/setup.ts +9 -0
- package/src/matchers/toMatchError.ts +18 -0
- package/src/matchers/toThrowErrorMatching.ts +26 -0
- package/src/matchers/types.d.ts +13 -0
- package/src/serializers/absolutePath.ts +30 -0
- package/src/serializers/setup.ts +7 -0
- package/src/serializers/vFile.ts +45 -0
- package/tests/tsconfig.json +9 -0
- package/tests/unit/matchers/readme.spec.ts +21 -0
- package/tests/unit/matchers/toMatchError.spec.ts +45 -0
- package/tests/unit/matchers/toThrowErrorMatching.spec.ts +31 -0
- package/tests/unit/serializers/absolutePath.spec.ts +16 -0
- package/tests/unit/serializers/vFile.spec.ts +80 -0
- package/tsconfig.json +4 -0
- package/vitest.config.ts +24 -0
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
extends: ["altano"],
|
|
3
|
+
overrides: [
|
|
4
|
+
{
|
|
5
|
+
files: ["src/**/!(*.d).{ts,tsx}", "*.config.ts"],
|
|
6
|
+
parserOptions: {
|
|
7
|
+
project: ["./tsconfig.json"],
|
|
8
|
+
tsconfigRootDir: __dirname,
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
files: ["tests/**/*.ts", "tests/**/*.tsx"],
|
|
13
|
+
parserOptions: {
|
|
14
|
+
project: ["./tsconfig.json"],
|
|
15
|
+
tsconfigRootDir: `${__dirname}/tests/`,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
|
|
2
|
+
> @altano/vitest-plugins@0.0.2 lint /home/runner/work/npm-packages/npm-packages/packages/vitest-plugins
|
|
3
|
+
> eslint package.json src/**/*.ts*
|
|
4
|
+
|
|
5
|
+
Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# vitest-plugins
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@altano/vitest-plugins)  
|
|
4
|
+
|
|
5
|
+
Custom matchers and snapshot serializers to enhance vitest.
|
|
6
|
+
|
|
7
|
+
# Installation
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install -D @altano/vitest-plugins
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## To install the custom matchers
|
|
14
|
+
|
|
15
|
+
Modify vite.config.ts / vitest.config.ts:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export default defineConfig({
|
|
19
|
+
test: {
|
|
20
|
+
setupFiles: [
|
|
21
|
+
"@altano/vitest-plugins/matchers",
|
|
22
|
+
// ...
|
|
23
|
+
],
|
|
24
|
+
// ...
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Add matcher types to your tsconfig.json (if using TypeScript):
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"compilerOptions": {
|
|
34
|
+
"types": ["@altano/vitest-plugins/matchers"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## To install the snapshot serializers
|
|
40
|
+
|
|
41
|
+
Modify vite.config.ts / vitest.config.ts:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
export default defineConfig({
|
|
45
|
+
test: {
|
|
46
|
+
setupFiles: [
|
|
47
|
+
"@altano/vitest-plugins/serializers",
|
|
48
|
+
// ...
|
|
49
|
+
],
|
|
50
|
+
// ...
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
NOTE: You can pick and choose what to install: the matchers and serializers don't depend on each other.
|
|
56
|
+
|
|
57
|
+
# Details
|
|
58
|
+
|
|
59
|
+
## Snapshot Serializers
|
|
60
|
+
|
|
61
|
+
### VFile
|
|
62
|
+
|
|
63
|
+
Will format the contents of a [vfile](https://unifiedjs.com/explore/package/vfile/) using Prettier (auto-detecting the type from the vfile's filename), e.g.
|
|
64
|
+
|
|
65
|
+
```snap
|
|
66
|
+
FormattedVFile {
|
|
67
|
+
"cwd": "<cwd>",
|
|
68
|
+
"data": {},
|
|
69
|
+
"history": [
|
|
70
|
+
"tests/unit/__fixtures__/basic/input.js",
|
|
71
|
+
],
|
|
72
|
+
"map": undefined,
|
|
73
|
+
"messages": [],
|
|
74
|
+
"value": "function face() { }"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Absolute Paths
|
|
79
|
+
|
|
80
|
+
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
|
+
|
|
82
|
+
## Matchers
|
|
83
|
+
|
|
84
|
+
Vitest's error matchers let you match against the error message, but not the rest of the Error object:
|
|
85
|
+
|
|
86
|
+
- `toThrow(error?)` - error is thrown ([docs](https://jestjs.io/docs/expect#tothrowerror))
|
|
87
|
+
- `toThrowErrorMatching[Inline]Snapshot` - an error _exactly_ matches a snapshot ([docs](https://jestjs.io/docs/expect#tothrowerrormatchingsnapshothint))
|
|
88
|
+
|
|
89
|
+
If you want to assert anything more complicated (e.g. an error contains some substring in the stack) then you'll need these custom matchers:
|
|
90
|
+
|
|
91
|
+
### toMatchError
|
|
92
|
+
|
|
93
|
+
Assert on any part of an error object (e.g. the stack):
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
expect(new Error("face")).toMatchError(
|
|
97
|
+
expect.objectContaining({
|
|
98
|
+
stack: expect.stringContaining("readme.spec.ts"),
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### toThrowErrorMatching
|
|
104
|
+
|
|
105
|
+
Assert on any part of a _thrown_ error object (e.g. the stack):
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
expect(() => {
|
|
109
|
+
throw new Error("face");
|
|
110
|
+
}).toThrowErrorMatching(
|
|
111
|
+
expect.objectContaining({
|
|
112
|
+
stack: expect.stringContaining("readme.spec.ts"),
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@altano/vitest-plugins",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Custom matchers and snapshot serializers to enhance vitest",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
"./matchers": {
|
|
9
|
+
"default": "./src/matchers/setup.ts",
|
|
10
|
+
"types": "./src/matchers/types.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./matchers/*": "./src/matchers/*.ts",
|
|
13
|
+
"./serializers": "./src/serializers/setup.ts",
|
|
14
|
+
"./serializers/*": "./src/serializers/*.ts"
|
|
15
|
+
},
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Alan Norbauer",
|
|
18
|
+
"email": "altano@gmail.com",
|
|
19
|
+
"url": "https://alan.norbauer.com"
|
|
20
|
+
},
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/altano/npm-packages",
|
|
25
|
+
"directory": "packages/vitest-plugins"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/altano/npm-packages/tree/main/packages/vitest-plugins",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@mdx-js/mdx": "^2.3.0",
|
|
30
|
+
"@prettier/sync": "^0.5.1",
|
|
31
|
+
"@types/node": "^20.11.25",
|
|
32
|
+
"@vitest/coverage-v8": "^1.4.0",
|
|
33
|
+
"@vitest/expect": "^1.4.0",
|
|
34
|
+
"@vitest/ui": "^1.4.0",
|
|
35
|
+
"eslint": "^8.57.0",
|
|
36
|
+
"mdast-util-mdxjs-esm": "^2.0.1",
|
|
37
|
+
"prettier": "^3.2.5",
|
|
38
|
+
"typescript": "^5.4.2",
|
|
39
|
+
"unified": "^10.1.2",
|
|
40
|
+
"vfile": "^5.3.7",
|
|
41
|
+
"vitest": "^1.4.0",
|
|
42
|
+
"@altano/tsconfig": "0.0.0",
|
|
43
|
+
"eslint-config-altano": "0.0.0"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"serialize-error": "^11.0.3"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"clean": "rm -rf .turbo && rm -rf .tsbuildinfo && rm -rf node_modules && rm -rf dist",
|
|
53
|
+
"format": "prettier --check src",
|
|
54
|
+
"format:fix": "prettier --write src",
|
|
55
|
+
"lint": "eslint package.json src/**/*.ts*",
|
|
56
|
+
"lint:fix": "TIMING=1 pnpm lint --fix",
|
|
57
|
+
"lint:timing": "TIMING=1 pnpm lint",
|
|
58
|
+
"test:typecheck": "tsc --project ./tests/tsconfig.json --noEmit",
|
|
59
|
+
"test:unit": "vitest --run",
|
|
60
|
+
"test:unit:watch": "vitest",
|
|
61
|
+
"typecheck:src": "tsc --noEmit",
|
|
62
|
+
"typecheck:test": "tsc --noEmit --project ./tests/tsconfig.json"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { serializeError } from "serialize-error";
|
|
2
|
+
import type { Matcher } from "./matcher";
|
|
3
|
+
|
|
4
|
+
const toMatchError: Matcher = function (received: Error, expected: unknown) {
|
|
5
|
+
// If we don't serialize the error before passing it to vitest, vitest will
|
|
6
|
+
// output just the error message (e.g. `"[Error: face]"`). If we let people
|
|
7
|
+
// match against the other Error fields (e.g. `stack`) we should display those
|
|
8
|
+
// instead of simplifying them out of the output.
|
|
9
|
+
const serializedError = serializeError(received);
|
|
10
|
+
return {
|
|
11
|
+
message: () => `Expected errors to match`,
|
|
12
|
+
pass: this.equals(received, expected, this.customTesters),
|
|
13
|
+
actual: serializedError,
|
|
14
|
+
expected: expected,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default toMatchError;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import toMatchError from "./toMatchError";
|
|
2
|
+
import type { Matcher } from "./matcher";
|
|
3
|
+
|
|
4
|
+
const toThrowErrorMatching: Matcher = function (
|
|
5
|
+
received: () => never,
|
|
6
|
+
expected: unknown,
|
|
7
|
+
) {
|
|
8
|
+
let error: unknown = null;
|
|
9
|
+
try {
|
|
10
|
+
received();
|
|
11
|
+
} catch (e: unknown) {
|
|
12
|
+
error = e;
|
|
13
|
+
}
|
|
14
|
+
if (error instanceof Error) {
|
|
15
|
+
return toMatchError.call(this, error, expected);
|
|
16
|
+
} else {
|
|
17
|
+
return {
|
|
18
|
+
message: () => `Did not throw an Error`,
|
|
19
|
+
pass: false,
|
|
20
|
+
actual: error,
|
|
21
|
+
expected: `[Error]`,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default toThrowErrorMatching;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Have to import these to get declaration merging.
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
3
|
+
import type { Assertion, AsymmetricMatchersContaining } from "vitest";
|
|
4
|
+
|
|
5
|
+
interface CustomMatchers<R = unknown> {
|
|
6
|
+
toMatchError(expected: unknown): R;
|
|
7
|
+
toThrowErrorMatching(expected: unknown): R;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
declare module "vitest" {
|
|
11
|
+
interface Assertion<T> extends CustomMatchers<T> {}
|
|
12
|
+
interface AsymmetricMatchersContaining extends CustomMatchers {}
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import type { SnapshotSerializer } from "vitest";
|
|
3
|
+
|
|
4
|
+
function getCWD(): string {
|
|
5
|
+
return process.cwd();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Strip absolute paths from the output to make tests portable
|
|
10
|
+
*/
|
|
11
|
+
function stripAbsolutePaths(str: string): string {
|
|
12
|
+
return str.replaceAll(getCWD(), "<cwd>");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const serializer: SnapshotSerializer = {
|
|
16
|
+
serialize(val: string, config, indentation, depth, refs, printer) {
|
|
17
|
+
return printer(stripAbsolutePaths(val), config, indentation, depth, refs);
|
|
18
|
+
},
|
|
19
|
+
test(val) {
|
|
20
|
+
return (
|
|
21
|
+
typeof val === "string" &&
|
|
22
|
+
// This is potentially really expensive, given large strings, but I can't
|
|
23
|
+
// find a better way to do this. Without this check, the string will keep
|
|
24
|
+
// getting reprocessed by this serializer over and over.
|
|
25
|
+
val.includes(getCWD())
|
|
26
|
+
);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default serializer;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import prettier from "@prettier/sync";
|
|
2
|
+
import prettierConfig from "../../../../.prettierrc.json";
|
|
3
|
+
import { VFile, type Value as VFileValue } from "vfile";
|
|
4
|
+
import type { Options } from "prettier";
|
|
5
|
+
import type { SnapshotSerializer } from "vitest";
|
|
6
|
+
|
|
7
|
+
class FormattedVFile extends VFile {
|
|
8
|
+
constructor(vfile: VFile, formattedContents: VFileValue) {
|
|
9
|
+
super(vfile);
|
|
10
|
+
this.value = formattedContents;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const vFileSerializer: SnapshotSerializer = {
|
|
15
|
+
serialize(vfile: VFile, config, indentation, depth, refs, printer) {
|
|
16
|
+
const unformattedContents = vfile.toString();
|
|
17
|
+
let vFileToPrint: VFile;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const formattedContents = prettier
|
|
21
|
+
.format(unformattedContents, {
|
|
22
|
+
filepath: vfile.path,
|
|
23
|
+
...(prettierConfig as Options),
|
|
24
|
+
})
|
|
25
|
+
.trim();
|
|
26
|
+
vFileToPrint = new FormattedVFile(vfile, formattedContents);
|
|
27
|
+
} catch (e: unknown) {
|
|
28
|
+
if (e instanceof Error && e.name === "UndefinedParserError") {
|
|
29
|
+
// Prettier doesn't have a parser for this vfile. That's fine, pass it
|
|
30
|
+
// through unformatted.
|
|
31
|
+
vFileToPrint = new FormattedVFile(vfile, vfile.value);
|
|
32
|
+
} else {
|
|
33
|
+
// Rethrow any other errors
|
|
34
|
+
throw e;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return printer(vFileToPrint, config, indentation, depth, refs);
|
|
39
|
+
},
|
|
40
|
+
test(val: unknown) {
|
|
41
|
+
return val instanceof VFile && !(val instanceof FormattedVFile);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default vFileSerializer;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import "../../../src/matchers/setup";
|
|
3
|
+
|
|
4
|
+
describe("readme", () => {
|
|
5
|
+
it("should describe toMatchError", () => {
|
|
6
|
+
expect(new Error("face")).toMatchError(
|
|
7
|
+
expect.objectContaining({
|
|
8
|
+
stack: expect.stringContaining("readme.spec.ts"),
|
|
9
|
+
}),
|
|
10
|
+
);
|
|
11
|
+
});
|
|
12
|
+
it("should describe toThrowErrorMatching", () => {
|
|
13
|
+
expect(() => {
|
|
14
|
+
throw new Error("face");
|
|
15
|
+
}).toThrowErrorMatching(
|
|
16
|
+
expect.objectContaining({
|
|
17
|
+
stack: expect.stringContaining("readme.spec.ts"),
|
|
18
|
+
}),
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import "../../../src/matchers/setup";
|
|
3
|
+
|
|
4
|
+
describe("matchers", () => {
|
|
5
|
+
describe("toMatchError", () => {
|
|
6
|
+
it("should match an error exactly", () => {
|
|
7
|
+
expect(new Error("face")).toMatchError(
|
|
8
|
+
expect.objectContaining({
|
|
9
|
+
message: "face",
|
|
10
|
+
name: "Error",
|
|
11
|
+
stack: expect.any(String),
|
|
12
|
+
}),
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
it("should match an error by substring", () => {
|
|
16
|
+
expect(new Error("your stupid face")).toMatchError(
|
|
17
|
+
expect.objectContaining({
|
|
18
|
+
message: expect.stringContaining("stupid"),
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
it("should NOT match an invalid string", () => {
|
|
23
|
+
expect(new Error("face")).not.toMatchError(
|
|
24
|
+
expect.objectContaining({
|
|
25
|
+
message: "hat",
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
it("should throw an error when there is no match", () => {
|
|
30
|
+
expect(() => {
|
|
31
|
+
expect(new Error("face")).toMatchError(
|
|
32
|
+
expect.objectContaining({
|
|
33
|
+
message: "hat",
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
}).toThrowErrorMatchingInlineSnapshot(
|
|
37
|
+
`[Error: Expected errors to match]`,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
it.todo("should display the other Error fields in the error", () => {
|
|
41
|
+
// I don't know how to capture vitest's full error output to verify it
|
|
42
|
+
// contains what we expect.
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import "../../../src/matchers/setup";
|
|
3
|
+
|
|
4
|
+
describe("matchers", () => {
|
|
5
|
+
describe("toThrowErrorMatching", () => {
|
|
6
|
+
it("should match an error exactly", () => {
|
|
7
|
+
expect(() => {
|
|
8
|
+
throw new Error("face");
|
|
9
|
+
}).toThrow("fac");
|
|
10
|
+
});
|
|
11
|
+
it("should NOT match an just the message", () => {
|
|
12
|
+
expect(() => {
|
|
13
|
+
throw new Error("face");
|
|
14
|
+
}).not.toThrowErrorMatching("face");
|
|
15
|
+
});
|
|
16
|
+
it("should NOT match an invalid message", () => {
|
|
17
|
+
expect(() => {
|
|
18
|
+
throw new Error("face");
|
|
19
|
+
}).not.toThrowErrorMatching(
|
|
20
|
+
expect.objectContaining({
|
|
21
|
+
message: "hat",
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
it("should throw an error when an error wasn't thrown", () => {
|
|
26
|
+
expect(() => {
|
|
27
|
+
expect(() => 1).toThrowErrorMatching("face");
|
|
28
|
+
}).toThrowErrorMatchingInlineSnapshot(`[Error: Did not throw an Error]`);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import absolutePathSerializer from "../../../src/serializers/absolutePath";
|
|
4
|
+
expect.addSnapshotSerializer(absolutePathSerializer);
|
|
5
|
+
|
|
6
|
+
describe("serializers", () => {
|
|
7
|
+
describe("absolutePath", () => {
|
|
8
|
+
it("should remove absolute file paths in a string", () => {
|
|
9
|
+
expect(
|
|
10
|
+
`String with an absolute path: ${import.meta.dirname}`,
|
|
11
|
+
).toMatchInlineSnapshot(
|
|
12
|
+
`"String with an absolute path: <cwd>/tests/unit/serializers"`,
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { VFile } from "vfile";
|
|
3
|
+
|
|
4
|
+
// We're not testing the absolute path serializer, but the test isn't
|
|
5
|
+
// reproducible without it. So just add both.
|
|
6
|
+
import "../../../src/serializers/setup";
|
|
7
|
+
|
|
8
|
+
describe("serializers", () => {
|
|
9
|
+
describe("vFile", () => {
|
|
10
|
+
it("should produce a snapshot for a plain text VFile (not Prettier supported)", () => {
|
|
11
|
+
const file = new VFile({
|
|
12
|
+
path: "~/example.txt",
|
|
13
|
+
value: "Alpha *braavo* charlie.",
|
|
14
|
+
});
|
|
15
|
+
expect(file).toMatchInlineSnapshot(`
|
|
16
|
+
FormattedVFile {
|
|
17
|
+
"cwd": "<cwd>",
|
|
18
|
+
"data": {},
|
|
19
|
+
"history": [
|
|
20
|
+
"~/example.txt",
|
|
21
|
+
],
|
|
22
|
+
"messages": [],
|
|
23
|
+
"value": "Alpha *braavo* charlie.",
|
|
24
|
+
}
|
|
25
|
+
`);
|
|
26
|
+
});
|
|
27
|
+
it("should produce a formatted snapshot for a Prettier-compatible file", () => {
|
|
28
|
+
const file = new VFile({
|
|
29
|
+
path: "~/example.js",
|
|
30
|
+
value: `function face( ) {console.log("hi" ); }`,
|
|
31
|
+
});
|
|
32
|
+
expect(file).toMatchInlineSnapshot(`
|
|
33
|
+
FormattedVFile {
|
|
34
|
+
"cwd": "<cwd>",
|
|
35
|
+
"data": {},
|
|
36
|
+
"history": [
|
|
37
|
+
"~/example.js",
|
|
38
|
+
],
|
|
39
|
+
"messages": [],
|
|
40
|
+
"value": "function face() {
|
|
41
|
+
console.log("hi");
|
|
42
|
+
}",
|
|
43
|
+
}
|
|
44
|
+
`);
|
|
45
|
+
});
|
|
46
|
+
it("should throw if given a file that Prettier supports but can't format", () => {
|
|
47
|
+
const file = new VFile({
|
|
48
|
+
path: "~/example.js",
|
|
49
|
+
value: `function ( ) {1 }`,
|
|
50
|
+
});
|
|
51
|
+
file.cwd = "/root/path"; // make snapshot reproducible
|
|
52
|
+
expect(() => {
|
|
53
|
+
expect(file).toMatchInlineSnapshot(`"function ( ) {1 }"`);
|
|
54
|
+
}).toThrowErrorMatchingInlineSnapshot(`
|
|
55
|
+
[PrettyFormatPluginError: Unexpected token (1:10)
|
|
56
|
+
> 1 | function ( ) {1 }
|
|
57
|
+
| ^]
|
|
58
|
+
`);
|
|
59
|
+
});
|
|
60
|
+
it("should remove absolute file paths in a vFile", () => {
|
|
61
|
+
const file = new VFile({
|
|
62
|
+
path: "~/example.json",
|
|
63
|
+
value: `{ "key": "${import.meta.dirname}" }`,
|
|
64
|
+
});
|
|
65
|
+
expect(file).toMatchInlineSnapshot(`
|
|
66
|
+
FormattedVFile {
|
|
67
|
+
"cwd": "<cwd>",
|
|
68
|
+
"data": {},
|
|
69
|
+
"history": [
|
|
70
|
+
"~/example.json",
|
|
71
|
+
],
|
|
72
|
+
"messages": [],
|
|
73
|
+
"value": "{
|
|
74
|
+
"key": "<cwd>/tests/unit/serializers"
|
|
75
|
+
}",
|
|
76
|
+
}
|
|
77
|
+
`);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
package/tsconfig.json
ADDED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineProject } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineProject({
|
|
4
|
+
test: {
|
|
5
|
+
dir: "tests/unit",
|
|
6
|
+
coverage: {
|
|
7
|
+
enabled: true,
|
|
8
|
+
|
|
9
|
+
exclude: [
|
|
10
|
+
"tests/e2e",
|
|
11
|
+
"playwright.config.ts",
|
|
12
|
+
".eslintrc.cjs",
|
|
13
|
+
"tests/unit/**/*.benchmark.tsx",
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
provider: "v8",
|
|
17
|
+
all: true,
|
|
18
|
+
clean: true,
|
|
19
|
+
skipFull: true,
|
|
20
|
+
thresholds: { "100": true },
|
|
21
|
+
reportsDirectory: ".coverage",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|