@flint.fyi/rule-tester 0.14.0 → 0.14.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.
@@ -0,0 +1,201 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { resolveReportedSuggestions } from "./resolveReportedSuggestions.js";
4
+
5
+ const mockReport = {
6
+ message: { primary: "", secondary: [], suggestions: [] },
7
+ range: {
8
+ begin: { column: 0, line: 1, raw: 0 },
9
+ end: { column: 3, line: 1, raw: 3 },
10
+ },
11
+ };
12
+
13
+ const mockTestCaseNormalized = {
14
+ code: "xyz",
15
+ fileName: "file.ts",
16
+ snapshot: "",
17
+ };
18
+
19
+ describe("resolveReportedSuggestions", () => {
20
+ it("returns undefined when reports is empty", () => {
21
+ const result = resolveReportedSuggestions([], mockTestCaseNormalized);
22
+
23
+ expect(result).toEqual(undefined);
24
+ });
25
+
26
+ it("returns undefined when given one report with no suggestions", () => {
27
+ const report = {
28
+ ...mockReport,
29
+ suggestions: [],
30
+ };
31
+
32
+ const result = resolveReportedSuggestions([report], mockTestCaseNormalized);
33
+
34
+ expect(result).toEqual(undefined);
35
+ });
36
+
37
+ it("returns id and updated text when given a single file suggestion", () => {
38
+ const suggestion = {
39
+ id: "suggestion",
40
+ range: { begin: 0, end: 3 },
41
+ text: "abc",
42
+ };
43
+ const report = {
44
+ ...mockReport,
45
+ suggestions: [suggestion],
46
+ };
47
+
48
+ const result = resolveReportedSuggestions([report], mockTestCaseNormalized);
49
+
50
+ expect(result).toEqual([
51
+ {
52
+ id: suggestion.id,
53
+ updated: suggestion.text,
54
+ },
55
+ ]);
56
+ });
57
+
58
+ it("throws when given a test case with no suggestions", () => {
59
+ const report = {
60
+ ...mockReport,
61
+ suggestions: [
62
+ {
63
+ files: {
64
+ "file.ts": () => [{ range: { begin: 0, end: 3 }, text: "def" }],
65
+ },
66
+ id: "suggestion-report",
67
+ },
68
+ ],
69
+ };
70
+
71
+ expect(() =>
72
+ resolveReportedSuggestions([report], {
73
+ ...mockTestCaseNormalized,
74
+ suggestions: [
75
+ {
76
+ id: "suggestion-result",
77
+ updated: "...",
78
+ },
79
+ ],
80
+ }),
81
+ ).toThrowErrorMatchingInlineSnapshot(
82
+ `[Error: This test case describes suggestions across files, but the rule is only reporting changes to its own file.]`,
83
+ );
84
+ });
85
+
86
+ it("throws when given a test case that doesn't have cross-file suggestions", () => {
87
+ const report = {
88
+ ...mockReport,
89
+ suggestions: [
90
+ {
91
+ files: {
92
+ "file.ts": () => [{ range: { begin: 0, end: 3 }, text: "def" }],
93
+ },
94
+ id: "suggestion-report",
95
+ },
96
+ ],
97
+ };
98
+
99
+ expect(() =>
100
+ resolveReportedSuggestions([report], {
101
+ ...mockTestCaseNormalized,
102
+ suggestions: [
103
+ {
104
+ id: "suggestion-result",
105
+ updated: "...",
106
+ },
107
+ ],
108
+ }),
109
+ ).toThrowErrorMatchingInlineSnapshot(
110
+ `[Error: This test case describes suggestions across files, but the rule is only reporting changes to its own file.]`,
111
+ );
112
+ });
113
+
114
+ it("returns id and a files object when given multi-file suggestions with a single file", () => {
115
+ const report = {
116
+ ...mockReport,
117
+ suggestions: [
118
+ {
119
+ files: {
120
+ "file.ts": () => [{ range: { begin: 0, end: 3 }, text: "def" }],
121
+ },
122
+ id: "suggestion-report",
123
+ },
124
+ ],
125
+ };
126
+
127
+ const result = resolveReportedSuggestions([report], {
128
+ ...mockTestCaseNormalized,
129
+ suggestions: [
130
+ {
131
+ files: {
132
+ "file.ts": [{ original: "abc", updated: "def" }],
133
+ },
134
+ id: "suggestion-result",
135
+ },
136
+ ],
137
+ });
138
+
139
+ expect(result).toEqual([
140
+ {
141
+ files: {
142
+ "file.ts": [
143
+ {
144
+ original: "abc",
145
+ updated: "def",
146
+ },
147
+ ],
148
+ },
149
+ id: "suggestion-report",
150
+ },
151
+ ]);
152
+ });
153
+
154
+ it("returns id and a files object when given multi-file suggestions with multiple file", () => {
155
+ const report = {
156
+ ...mockReport,
157
+ suggestions: [
158
+ {
159
+ files: {
160
+ "fileA.ts": () => [{ range: { begin: 0, end: 5 }, text: "def-A" }],
161
+ "fileB.ts": () => [{ range: { begin: 0, end: 5 }, text: "def-B" }],
162
+ },
163
+ id: "suggestion-report",
164
+ },
165
+ ],
166
+ };
167
+
168
+ const result = resolveReportedSuggestions([report], {
169
+ ...mockTestCaseNormalized,
170
+ suggestions: [
171
+ {
172
+ files: {
173
+ "fileA.ts": [{ original: "abc-A", updated: "def-A" }],
174
+ "fileB.ts": [{ original: "abc-B", updated: "def-B" }],
175
+ },
176
+ id: "suggestion-result",
177
+ },
178
+ ],
179
+ });
180
+
181
+ expect(result).toEqual([
182
+ {
183
+ files: {
184
+ "fileA.ts": [
185
+ {
186
+ original: "abc-A",
187
+ updated: "def-A",
188
+ },
189
+ ],
190
+ "fileB.ts": [
191
+ {
192
+ original: "abc-B",
193
+ updated: "def-B",
194
+ },
195
+ ],
196
+ },
197
+ id: "suggestion-report",
198
+ },
199
+ ]);
200
+ });
201
+ });
@@ -7,6 +7,7 @@ import { SuggestionForFiles } from "@flint.fyi/core/src/types/changes.js";
7
7
  import { isTruthy } from "@flint.fyi/utils";
8
8
 
9
9
  import { TestCaseNormalized } from "./normalizeTestCase.js";
10
+ import { isTestSuggestionForFiles } from "./predicates.js";
10
11
  import { InvalidTestCase, TestSuggestionFileCase } from "./types.js";
11
12
 
12
13
  export function resolveReportedSuggestions(
@@ -21,19 +22,23 @@ export function resolveReportedSuggestions(
21
22
  return undefined;
22
23
  }
23
24
 
24
- return suggestionsReported.map((suggestionReported) => ({
25
- files: isSuggestionForFiles(suggestionReported)
26
- ? resolveReportedSuggestionForFiles(
27
- suggestionReported,
28
- testCaseNormalized,
29
- )
30
- : [
31
- {
32
- [testCaseNormalized.fileName]: suggestionReported,
33
- },
34
- ],
35
- id: suggestionReported.id,
36
- }));
25
+ return suggestionsReported.map((suggestionReported) =>
26
+ isSuggestionForFiles(suggestionReported)
27
+ ? {
28
+ files: resolveReportedSuggestionForFiles(
29
+ suggestionReported,
30
+ testCaseNormalized,
31
+ ),
32
+ id: suggestionReported.id,
33
+ }
34
+ : {
35
+ id: suggestionReported.id,
36
+ updated: applyChangesToText(
37
+ [suggestionReported],
38
+ testCaseNormalized.code,
39
+ ),
40
+ },
41
+ );
37
42
  }
38
43
 
39
44
  function resolveReportedSuggestionForFiles(
@@ -44,6 +49,12 @@ function resolveReportedSuggestionForFiles(
44
49
  return {};
45
50
  }
46
51
 
52
+ if (!testCaseNormalized.suggestions.every(isTestSuggestionForFiles)) {
53
+ throw new Error(
54
+ "This test case describes suggestions across files, but the rule is only reporting changes to its own file.",
55
+ );
56
+ }
57
+
47
58
  return Object.fromEntries(
48
59
  testCaseNormalized.suggestions
49
60
  .map((suggestionExpected): [string, TestSuggestionFileCase[]][] => {
@@ -2,9 +2,9 @@ import {
2
2
  AnyLanguage,
3
3
  AnyOptionalSchema,
4
4
  AnyRule,
5
- BaseAbout,
6
5
  InferredObject,
7
6
  LanguageFileFactory,
7
+ RuleAbout,
8
8
  } from "@flint.fyi/core";
9
9
  import { CachedFactory } from "cached-factory";
10
10
 
@@ -14,7 +14,7 @@ export interface TestCaseRuleConfiguration<
14
14
  OptionsSchema extends AnyOptionalSchema | undefined,
15
15
  > {
16
16
  options?: InferredObject<OptionsSchema>;
17
- rule: AnyRule<BaseAbout, OptionsSchema>;
17
+ rule: AnyRule<RuleAbout, OptionsSchema>;
18
18
  }
19
19
 
20
20
  export function runTestCaseRule<
package/src/types.ts CHANGED
@@ -11,19 +11,41 @@ export interface TestCase<
11
11
  > {
12
12
  code: string;
13
13
  fileName?: string;
14
+
15
+ /**
16
+ * Run only this test case. Useful for debugging.
17
+ *
18
+ * Do not commit code with this flag set.
19
+ */
20
+ only?: boolean;
21
+
14
22
  options?: Options;
15
- }
16
23
 
17
- export interface TestSuggestion {
18
- files: Record<string, TestSuggestionFileCase[]>;
19
- id: string;
24
+ /**
25
+ * Skip running this test case. Useful for work-in-progress tests.
26
+ *
27
+ * Do not commit code with this flag set.
28
+ */
29
+ skip?: boolean;
20
30
  }
21
31
 
32
+ export type TestSuggestion = TestSuggestionForFile | TestSuggestionForFiles;
33
+
22
34
  export interface TestSuggestionFileCase {
23
35
  original: string;
24
36
  updated: string;
25
37
  }
26
38
 
39
+ export interface TestSuggestionForFile {
40
+ id: string;
41
+ updated: string;
42
+ }
43
+
44
+ export interface TestSuggestionForFiles {
45
+ files: Record<string, TestSuggestionFileCase[]>;
46
+ id: string;
47
+ }
48
+
27
49
  export type ValidTestCase<Options extends object | undefined> =
28
50
  | string
29
51
  | ValidTestCaseObject<Options>;