pi-lens 2.0.7 â 2.0.8
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/clients/ast-grep-client.test.ts +146 -116
- package/clients/ast-grep-client.ts +645 -551
- package/clients/biome-client.test.ts +154 -137
- package/clients/biome-client.ts +397 -337
- package/clients/complexity-client.test.ts +188 -200
- package/clients/complexity-client.ts +815 -667
- package/clients/dependency-checker.test.ts +55 -55
- package/clients/dependency-checker.ts +358 -333
- package/clients/go-client.test.ts +121 -111
- package/clients/go-client.ts +218 -216
- package/clients/jscpd-client.test.ts +132 -132
- package/clients/jscpd-client.ts +155 -118
- package/clients/knip-client.test.ts +123 -133
- package/clients/knip-client.ts +231 -218
- package/clients/metrics-client.test.ts +171 -167
- package/clients/metrics-client.ts +283 -252
- package/clients/ruff-client.test.ts +128 -117
- package/clients/ruff-client.ts +300 -269
- package/clients/rust-client.test.ts +104 -85
- package/clients/rust-client.ts +241 -234
- package/clients/subprocess-client.ts +1 -1
- package/clients/test-runner-client.test.ts +248 -215
- package/clients/test-runner-client.ts +728 -608
- package/clients/test-utils.ts +10 -3
- package/clients/todo-scanner.test.ts +288 -202
- package/clients/todo-scanner.ts +225 -187
- package/clients/type-coverage-client.test.ts +119 -119
- package/clients/type-coverage-client.ts +142 -115
- package/clients/types.ts +28 -28
- package/clients/typescript-client.test.ts +99 -93
- package/clients/typescript-client.ts +527 -502
- package/index.ts +662 -212
- package/package.json +1 -1
- package/tsconfig.json +12 -12
package/clients/test-utils.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
2
|
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a temporary file within the given temp directory.
|
|
7
7
|
* Automatically creates parent directories if they don't exist.
|
|
8
8
|
*/
|
|
9
|
-
export function createTempFile(
|
|
9
|
+
export function createTempFile(
|
|
10
|
+
tmpDir: string,
|
|
11
|
+
name: string,
|
|
12
|
+
content: string,
|
|
13
|
+
): string {
|
|
10
14
|
const filePath = path.join(tmpDir, name);
|
|
11
15
|
const dir = path.dirname(filePath);
|
|
12
16
|
if (!fs.existsSync(dir)) {
|
|
@@ -20,7 +24,10 @@ export function createTempFile(tmpDir: string, name: string, content: string): s
|
|
|
20
24
|
* Creates a temporary directory for testing.
|
|
21
25
|
* Returns the path and a cleanup function.
|
|
22
26
|
*/
|
|
23
|
-
export function setupTestEnvironment(prefix: string): {
|
|
27
|
+
export function setupTestEnvironment(prefix: string): {
|
|
28
|
+
tmpDir: string;
|
|
29
|
+
cleanup: () => void;
|
|
30
|
+
} {
|
|
24
31
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
25
32
|
const cleanup = () => {
|
|
26
33
|
if (tmpDir && fs.existsSync(tmpDir)) {
|
|
@@ -1,266 +1,352 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TodoScanner } from "./todo-scanner.js";
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
2
|
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
3
|
+
import { TodoScanner } from "./todo-scanner.js";
|
|
4
4
|
|
|
5
5
|
describe("TodoScanner", () => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
let client: TodoScanner;
|
|
7
|
+
let tmpDir: string;
|
|
8
|
+
let cleanup: () => void;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
client = new TodoScanner();
|
|
12
|
+
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-todo-test-"));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
cleanup();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("scanFile", () => {
|
|
20
|
+
it("should return empty array for non-existent files", () => {
|
|
21
|
+
const result = client.scanFile("/nonexistent/file.ts");
|
|
22
|
+
expect(result).toEqual([]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should find TODO comments", () => {
|
|
26
|
+
const content = `
|
|
27
27
|
// TODO: implement this function
|
|
28
28
|
function foo() {}
|
|
29
29
|
`;
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
31
|
+
const result = client.scanFile(filePath);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
expect(result.length).toBe(1);
|
|
34
|
+
expect(result[0].type).toBe("TODO");
|
|
35
|
+
expect(result[0].message).toContain("implement this function");
|
|
36
|
+
});
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
it("should find FIXME comments", () => {
|
|
39
|
+
const content = `
|
|
40
40
|
// FIXME: this is broken
|
|
41
41
|
function foo() {}
|
|
42
42
|
`;
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
44
|
+
const result = client.scanFile(filePath);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
expect(result.length).toBe(1);
|
|
47
|
+
expect(result[0].type).toBe("FIXME");
|
|
48
|
+
});
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
it("should find HACK comments", () => {
|
|
51
|
+
const content = `
|
|
52
52
|
// HACK: temporary workaround
|
|
53
53
|
const x = 1;
|
|
54
54
|
`;
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
56
|
+
const result = client.scanFile(filePath);
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
expect(result.length).toBe(1);
|
|
59
|
+
expect(result[0].type).toBe("HACK");
|
|
60
|
+
});
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
it("should find BUG comments", () => {
|
|
63
|
+
const content = `
|
|
64
64
|
// BUG: this causes a crash
|
|
65
65
|
const x = 1;
|
|
66
66
|
`;
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
68
|
+
const result = client.scanFile(filePath);
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
expect(result.length).toBe(1);
|
|
71
|
+
expect(result[0].type).toBe("BUG");
|
|
72
|
+
});
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
it("should find NOTE comments", () => {
|
|
75
|
+
const content = `
|
|
76
76
|
// NOTE: important design decision
|
|
77
77
|
const x = 1;
|
|
78
78
|
`;
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
80
|
+
const result = client.scanFile(filePath);
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
expect(result.length).toBe(1);
|
|
83
|
+
expect(result[0].type).toBe("NOTE");
|
|
84
|
+
});
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
it("should find TODO in block comments", () => {
|
|
87
|
+
const content = `
|
|
88
88
|
/*
|
|
89
89
|
* TODO: refactor this later
|
|
90
90
|
*/
|
|
91
91
|
const x = 1;
|
|
92
92
|
`;
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
94
|
+
const result = client.scanFile(filePath);
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
expect(result.length).toBe(1);
|
|
97
|
+
expect(result[0].type).toBe("TODO");
|
|
98
|
+
});
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
it("should find TODO in JSDoc comments", () => {
|
|
101
|
+
const content = `
|
|
102
102
|
/**
|
|
103
103
|
* TODO: add proper documentation
|
|
104
104
|
*/
|
|
105
105
|
function foo() {}
|
|
106
106
|
`;
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
108
|
+
const result = client.scanFile(filePath);
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
expect(result.length).toBe(1);
|
|
111
|
+
expect(result[0].type).toBe("TODO");
|
|
112
|
+
});
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
it("should find TODO in Python comments", () => {
|
|
115
|
+
const content = `
|
|
116
116
|
# TODO: implement this
|
|
117
117
|
def foo():
|
|
118
118
|
pass
|
|
119
119
|
`;
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
const filePath = createTempFile(tmpDir, "test.py", content);
|
|
121
|
+
const result = client.scanFile(filePath);
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
expect(result.length).toBe(1);
|
|
124
|
+
expect(result[0].type).toBe("TODO");
|
|
125
|
+
});
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
it("should skip TODO in strings", () => {
|
|
128
|
+
const content = `
|
|
129
129
|
const message = "TODO: buy milk";
|
|
130
130
|
`;
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
132
|
+
const result = client.scanFile(filePath);
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
expect(result.length).toBe(0);
|
|
135
|
+
});
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
it("should report correct line numbers", () => {
|
|
138
|
+
const content = `
|
|
139
139
|
const x = 1;
|
|
140
140
|
const y = 2;
|
|
141
141
|
// TODO: fix this
|
|
142
142
|
const z = 3;
|
|
143
143
|
`;
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
145
|
+
const result = client.scanFile(filePath);
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
expect(result[0].line).toBe(4);
|
|
148
|
+
});
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
it("should find multiple annotations in one file", () => {
|
|
151
|
+
const content = `
|
|
152
152
|
// TODO: first
|
|
153
153
|
// FIXME: second
|
|
154
154
|
// HACK: third
|
|
155
155
|
`;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
156
|
+
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
157
|
+
const result = client.scanFile(filePath);
|
|
158
|
+
|
|
159
|
+
expect(result.length).toBe(3);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("scanDirectory", () => {
|
|
164
|
+
it("should scan all files in directory", () => {
|
|
165
|
+
createTempFile(tmpDir, "file1.ts", "// TODO: task 1");
|
|
166
|
+
createTempFile(tmpDir, "file2.ts", "// FIXME: bug 1");
|
|
167
|
+
createTempFile(tmpDir, "file3.py", "# HACK: workaround");
|
|
168
|
+
|
|
169
|
+
const result = client.scanDirectory(tmpDir);
|
|
170
|
+
|
|
171
|
+
expect(result.items.length).toBe(3);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("should skip node_modules", () => {
|
|
175
|
+
createTempFile(tmpDir, "src/file.ts", "// TODO: task 1");
|
|
176
|
+
createTempFile(
|
|
177
|
+
tmpDir,
|
|
178
|
+
"node_modules/lib/file.ts",
|
|
179
|
+
"// TODO: should be skipped",
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const result = client.scanDirectory(tmpDir);
|
|
183
|
+
|
|
184
|
+
expect(result.items.length).toBe(1);
|
|
185
|
+
expect(result.items[0].file).not.toContain("node_modules");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("should group items by type", () => {
|
|
189
|
+
createTempFile(tmpDir, "file1.ts", "// TODO: task 1");
|
|
190
|
+
createTempFile(tmpDir, "file2.ts", "// TODO: task 2");
|
|
191
|
+
createTempFile(tmpDir, "file3.ts", "// FIXME: bug 1");
|
|
192
|
+
|
|
193
|
+
const result = client.scanDirectory(tmpDir);
|
|
194
|
+
|
|
195
|
+
expect(result.byType.get("TODO")?.length).toBe(2);
|
|
196
|
+
expect(result.byType.get("FIXME")?.length).toBe(1);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should group items by file", () => {
|
|
200
|
+
createTempFile(tmpDir, "file1.ts", "// TODO: task 1\n// FIXME: bug 1");
|
|
201
|
+
createTempFile(tmpDir, "file2.ts", "// TODO: task 2");
|
|
202
|
+
|
|
203
|
+
const result = client.scanDirectory(tmpDir);
|
|
204
|
+
|
|
205
|
+
const file1Items = [...result.byFile.entries()].find(([k]) =>
|
|
206
|
+
k.includes("file1.ts"),
|
|
207
|
+
);
|
|
208
|
+
expect(file1Items?.[1].length).toBe(2);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe("formatResult", () => {
|
|
213
|
+
it("should return empty string for no results", () => {
|
|
214
|
+
const result = { items: [], byType: new Map(), byFile: new Map() };
|
|
215
|
+
expect(client.formatResult(result)).toBe("");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should format results with counts", () => {
|
|
219
|
+
const result = {
|
|
220
|
+
items: [
|
|
221
|
+
{
|
|
222
|
+
type: "TODO" as const,
|
|
223
|
+
message: "task 1",
|
|
224
|
+
file: "test.ts",
|
|
225
|
+
line: 1,
|
|
226
|
+
column: 0,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: "FIXME" as const,
|
|
230
|
+
message: "bug 1",
|
|
231
|
+
file: "test.ts",
|
|
232
|
+
line: 2,
|
|
233
|
+
column: 0,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
byType: new Map([
|
|
237
|
+
[
|
|
238
|
+
"TODO",
|
|
239
|
+
[
|
|
240
|
+
{
|
|
241
|
+
type: "TODO" as const,
|
|
242
|
+
message: "task 1",
|
|
243
|
+
file: "test.ts",
|
|
244
|
+
line: 1,
|
|
245
|
+
column: 0,
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
],
|
|
249
|
+
]),
|
|
250
|
+
byFile: new Map([
|
|
251
|
+
[
|
|
252
|
+
"test.ts",
|
|
253
|
+
[
|
|
254
|
+
{
|
|
255
|
+
type: "TODO" as const,
|
|
256
|
+
message: "task 1",
|
|
257
|
+
file: "test.ts",
|
|
258
|
+
line: 1,
|
|
259
|
+
column: 0,
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
],
|
|
263
|
+
]),
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const formatted = client.formatResult(result);
|
|
267
|
+
expect(formatted).toContain("2 annotation(s)");
|
|
268
|
+
expect(formatted).toContain("TODO");
|
|
269
|
+
expect(formatted).toContain("FIXME");
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("should prioritize FIXME/HACK before TODO", () => {
|
|
273
|
+
const result = {
|
|
274
|
+
items: [
|
|
275
|
+
{
|
|
276
|
+
type: "FIXME" as const,
|
|
277
|
+
message: "bug",
|
|
278
|
+
file: "test.ts",
|
|
279
|
+
line: 2,
|
|
280
|
+
column: 0,
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
type: "TODO" as const,
|
|
284
|
+
message: "task",
|
|
285
|
+
file: "test.ts",
|
|
286
|
+
line: 1,
|
|
287
|
+
column: 0,
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
byType: new Map(),
|
|
291
|
+
byFile: new Map(),
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const formatted = client.formatResult(result);
|
|
295
|
+
// Check that FIXME line comes before TODO line in the sorted output
|
|
296
|
+
const fixmeLineIndex = formatted.indexOf("đ´");
|
|
297
|
+
const todoLineIndex = formatted.indexOf("đ");
|
|
298
|
+
expect(fixmeLineIndex).toBeLessThan(todoLineIndex);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("should show correct icons", () => {
|
|
302
|
+
const result = {
|
|
303
|
+
items: [
|
|
304
|
+
{
|
|
305
|
+
type: "FIXME" as const,
|
|
306
|
+
message: "bug",
|
|
307
|
+
file: "test.ts",
|
|
308
|
+
line: 1,
|
|
309
|
+
column: 0,
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
type: "HACK" as const,
|
|
313
|
+
message: "hack",
|
|
314
|
+
file: "test.ts",
|
|
315
|
+
line: 2,
|
|
316
|
+
column: 0,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
type: "BUG" as const,
|
|
320
|
+
message: "bug",
|
|
321
|
+
file: "test.ts",
|
|
322
|
+
line: 3,
|
|
323
|
+
column: 0,
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
type: "TODO" as const,
|
|
327
|
+
message: "todo",
|
|
328
|
+
file: "test.ts",
|
|
329
|
+
line: 4,
|
|
330
|
+
column: 0,
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
type: "NOTE" as const,
|
|
334
|
+
message: "note",
|
|
335
|
+
file: "test.ts",
|
|
336
|
+
line: 5,
|
|
337
|
+
column: 0,
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
byType: new Map(),
|
|
341
|
+
byFile: new Map(),
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const formatted = client.formatResult(result);
|
|
345
|
+
expect(formatted).toContain("đ´"); // FIXME
|
|
346
|
+
expect(formatted).toContain("đ "); // HACK
|
|
347
|
+
expect(formatted).toContain("đ"); // BUG
|
|
348
|
+
expect(formatted).toContain("đ"); // TODO
|
|
349
|
+
expect(formatted).toContain("âšī¸"); // NOTE
|
|
350
|
+
});
|
|
351
|
+
});
|
|
266
352
|
});
|