@rstackjs/test-utils 0.0.0 → 0.2.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/README.md +67 -1
- package/dist/copyNodeModules.d.ts +2 -0
- package/dist/editFile.d.ts +3 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +44 -4
- package/dist/normalizeEol.d.ts +2 -0
- package/dist/prepareDist.d.ts +2 -0
- package/dist/readDirContents.d.ts +1 -1
- package/dist/waitForFile.d.ts +3 -0
- package/dist/waitForFileContent.d.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,28 @@ bun add @rstackjs/test-utils -D
|
|
|
25
25
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
28
|
+
### copyNodeModules
|
|
29
|
+
|
|
30
|
+
Replaces `node_modules` with a copy of `_node_modules` in the given directory. It uses the current working directory by default.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { copyNodeModules } from '@rstackjs/test-utils';
|
|
34
|
+
|
|
35
|
+
const nodeModulesPath = await copyNodeModules();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### editFile
|
|
39
|
+
|
|
40
|
+
Edits a file using a sync or async editor function.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { editFile } from '@rstackjs/test-utils';
|
|
44
|
+
|
|
45
|
+
await editFile('src/index.ts', (content) =>
|
|
46
|
+
content.replace('const value = 1', 'const value = 2'),
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
28
50
|
### findFile
|
|
29
51
|
|
|
30
52
|
Finds the first matching path in a file-content map. String matchers use suffix matching, and content hashes are ignored by default.
|
|
@@ -119,9 +141,31 @@ try {
|
|
|
119
141
|
console.log(logHelper.logs);
|
|
120
142
|
```
|
|
121
143
|
|
|
144
|
+
### normalizeEol
|
|
145
|
+
|
|
146
|
+
Normalizes CRLF line endings to LF.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { normalizeEol } from '@rstackjs/test-utils';
|
|
150
|
+
|
|
151
|
+
const content = normalizeEol('first line\r\nsecond line\r\n');
|
|
152
|
+
// first line\nsecond line\n
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### prepareDist
|
|
156
|
+
|
|
157
|
+
Removes a dist directory and returns its absolute path. It removes `dist` from the current working directory by default.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { prepareDist } from '@rstackjs/test-utils';
|
|
161
|
+
|
|
162
|
+
const distPath = await prepareDist();
|
|
163
|
+
const customDistPath = await prepareDist('dist-custom');
|
|
164
|
+
```
|
|
165
|
+
|
|
122
166
|
### readDirContents
|
|
123
167
|
|
|
124
|
-
Recursively reads UTF-8 files from a directory and returns a file-content map keyed by sorted absolute paths.
|
|
168
|
+
Recursively reads UTF-8 files from a directory and returns a file-content map keyed by sorted POSIX absolute paths.
|
|
125
169
|
|
|
126
170
|
```ts
|
|
127
171
|
import { readDirContents } from '@rstackjs/test-utils';
|
|
@@ -159,6 +203,28 @@ await waitFor(() => server.isReady(), {
|
|
|
159
203
|
|
|
160
204
|
Condition polling uses a 100ms interval and a 5-second timeout by default.
|
|
161
205
|
|
|
206
|
+
### waitForFile
|
|
207
|
+
|
|
208
|
+
Waits until a file path exists.
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import { waitForFile } from '@rstackjs/test-utils';
|
|
212
|
+
|
|
213
|
+
await waitForFile('dist/index.js');
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### waitForFileContent
|
|
217
|
+
|
|
218
|
+
Waits until a UTF-8 file includes the expected content.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { waitForFileContent } from '@rstackjs/test-utils';
|
|
222
|
+
|
|
223
|
+
await waitForFileContent('dist/index.js', 'compiled successfully');
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Both helpers accept the same `interval` and `timeout` options as `waitFor`.
|
|
227
|
+
|
|
162
228
|
## License
|
|
163
229
|
|
|
164
230
|
[MIT](./LICENSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
export { copyNodeModules } from './copyNodeModules.js';
|
|
2
|
+
export { editFile, type FileEditor } from './editFile.js';
|
|
1
3
|
export { type FileMatcher, findFile, type FindFileOptions, } from './findFile.js';
|
|
2
4
|
export { getDistFiles } from './getDistFiles.js';
|
|
3
5
|
export { getFileContent } from './getFileContent.js';
|
|
4
6
|
export { getRandomPort, isPortAvailable } from './getRandomPort.js';
|
|
7
|
+
export { normalizeEol } from './normalizeEol.js';
|
|
8
|
+
export { prepareDist } from './prepareDist.js';
|
|
5
9
|
export { type ConsoleType, createLogHelper, type ExtendedLogHelper, type LogHelper, proxyConsole, type ProxyConsoleOptions, } from './proxyConsole.js';
|
|
6
10
|
export { readDirContents } from './readDirContents.js';
|
|
7
11
|
export { toPosixPath } from './toPosixPath.js';
|
|
8
12
|
export { waitFor, type WaitForCondition, type WaitForOptions, } from './waitFor.js';
|
|
13
|
+
export { waitForFile } from './waitForFile.js';
|
|
14
|
+
export { waitForFileContent } from './waitForFileContent.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
|
-
import { readFile, readdir } from "node:fs/promises";
|
|
1
|
+
import { cp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve as external_node_path_resolve } from "node:path";
|
|
3
3
|
import node_net from "node:net";
|
|
4
4
|
import { stripVTControlCharacters, styleText } from "node:util";
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
|
+
const copyNodeModules = async (cwd = process.cwd())=>{
|
|
7
|
+
const rootPath = external_node_path_resolve(cwd);
|
|
8
|
+
const sourcePath = join(rootPath, '_node_modules');
|
|
9
|
+
const targetPath = join(rootPath, 'node_modules');
|
|
10
|
+
await rm(targetPath, {
|
|
11
|
+
force: true,
|
|
12
|
+
recursive: true
|
|
13
|
+
});
|
|
14
|
+
await cp(sourcePath, targetPath, {
|
|
15
|
+
recursive: true
|
|
16
|
+
});
|
|
17
|
+
return targetPath;
|
|
18
|
+
};
|
|
19
|
+
const editFile = async (filePath, editor)=>{
|
|
20
|
+
const content = await readFile(filePath, 'utf-8');
|
|
21
|
+
await writeFile(filePath, await editor(content));
|
|
22
|
+
};
|
|
5
23
|
const HASH_PATTERN = /\.[0-9a-z]{8,}(?=\.)/gi;
|
|
6
24
|
const toMatcher = (matcher)=>{
|
|
7
25
|
if ('function' == typeof matcher) return matcher;
|
|
@@ -21,6 +39,7 @@ const findFile = (files, matcher, options = {})=>{
|
|
|
21
39
|
}
|
|
22
40
|
throw new Error(`Unable to find file matching "${matcher.toString()}"`);
|
|
23
41
|
};
|
|
42
|
+
const toPosixPath = (filePath)=>filePath.replaceAll('\\', '/');
|
|
24
43
|
const collectFilePaths = async (directoryPath)=>{
|
|
25
44
|
const entries = await readdir(directoryPath, {
|
|
26
45
|
withFileTypes: true
|
|
@@ -38,7 +57,7 @@ const readDirContents = async (directoryPath)=>{
|
|
|
38
57
|
const filePaths = await collectFilePaths(external_node_path_resolve(directoryPath));
|
|
39
58
|
filePaths.sort();
|
|
40
59
|
const entries = await Promise.all(filePaths.map(async (filePath)=>[
|
|
41
|
-
filePath,
|
|
60
|
+
toPosixPath(filePath),
|
|
42
61
|
await readFile(filePath, 'utf-8')
|
|
43
62
|
]));
|
|
44
63
|
return Object.fromEntries(entries);
|
|
@@ -78,7 +97,15 @@ const getRandomPort = async (startPort = Math.ceil(30000 * Math.random()) + 1500
|
|
|
78
97
|
}
|
|
79
98
|
throw new Error('No available ports found in the valid range.');
|
|
80
99
|
};
|
|
81
|
-
const
|
|
100
|
+
const normalizeEol = (content)=>content.replaceAll('\r\n', '\n');
|
|
101
|
+
const prepareDist = async (distPath = 'dist')=>{
|
|
102
|
+
const absolutePath = external_node_path_resolve(distPath);
|
|
103
|
+
await rm(absolutePath, {
|
|
104
|
+
force: true,
|
|
105
|
+
recursive: true
|
|
106
|
+
});
|
|
107
|
+
return absolutePath;
|
|
108
|
+
};
|
|
82
109
|
const matchPattern = (log, pattern, options = {})=>{
|
|
83
110
|
const logToCheck = options.posix ? toPosixPath(log) : log;
|
|
84
111
|
if ('string' == typeof pattern) return options.strict ? logToCheck.split('\n').some((line)=>line.trim() === pattern.trim()) : logToCheck.includes(pattern);
|
|
@@ -191,4 +218,17 @@ async function waitFor(millisecondsOrCondition, options = {}) {
|
|
|
191
218
|
await delay(Math.min(interval, timeout - elapsedTime));
|
|
192
219
|
}
|
|
193
220
|
}
|
|
194
|
-
|
|
221
|
+
const waitForFile = async (filePath, options)=>{
|
|
222
|
+
await waitFor(()=>existsSync(filePath), options);
|
|
223
|
+
};
|
|
224
|
+
const waitForFileContent = async (filePath, expectedContent, options)=>{
|
|
225
|
+
await waitFor(async ()=>{
|
|
226
|
+
try {
|
|
227
|
+
const content = await readFile(filePath, 'utf-8');
|
|
228
|
+
return content.includes(expectedContent);
|
|
229
|
+
} catch {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
}, options);
|
|
233
|
+
};
|
|
234
|
+
export { copyNodeModules, createLogHelper, editFile, findFile, getDistFiles, getFileContent, getRandomPort, isPortAvailable, normalizeEol, prepareDist, proxyConsole, readDirContents, toPosixPath, waitFor, waitForFile, waitForFileContent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Recursively read UTF-8 files from a directory.
|
|
3
3
|
*
|
|
4
|
-
* The returned record uses sorted absolute file paths as keys.
|
|
4
|
+
* The returned record uses sorted POSIX absolute file paths as keys.
|
|
5
5
|
*/
|
|
6
6
|
export declare const readDirContents: (directoryPath: string) => Promise<Record<string, string>>;
|