@remix-run/test 0.1.0 → 0.3.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.
Files changed (159) hide show
  1. package/README.md +161 -50
  2. package/dist/app/client/entry.d.ts +2 -0
  3. package/dist/app/client/entry.d.ts.map +1 -0
  4. package/dist/app/client/entry.js +328 -0
  5. package/dist/app/client/iframe.d.ts +2 -0
  6. package/dist/app/client/iframe.d.ts.map +1 -0
  7. package/dist/app/client/iframe.js +22 -0
  8. package/dist/app/server.d.ts +6 -0
  9. package/dist/app/server.d.ts.map +1 -0
  10. package/dist/app/server.js +303 -0
  11. package/dist/cli-entry.d.ts +3 -0
  12. package/dist/cli-entry.d.ts.map +1 -0
  13. package/dist/cli-entry.js +14 -0
  14. package/dist/cli.d.ts +7 -2
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +319 -140
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/lib/colors.d.ts +2 -0
  20. package/dist/lib/colors.d.ts.map +1 -0
  21. package/dist/lib/colors.js +2 -0
  22. package/dist/lib/config.d.ts +59 -14
  23. package/dist/lib/config.d.ts.map +1 -1
  24. package/dist/lib/config.js +181 -38
  25. package/dist/lib/context.d.ts +37 -13
  26. package/dist/lib/context.d.ts.map +1 -1
  27. package/dist/lib/context.js +19 -3
  28. package/dist/lib/coverage-loader.d.ts +16 -0
  29. package/dist/lib/coverage-loader.d.ts.map +1 -0
  30. package/dist/lib/coverage-loader.js +20 -0
  31. package/dist/lib/coverage.d.ts +28 -0
  32. package/dist/lib/coverage.d.ts.map +1 -0
  33. package/dist/lib/coverage.js +212 -0
  34. package/dist/lib/executor.d.ts +3 -26
  35. package/dist/lib/executor.d.ts.map +1 -1
  36. package/dist/lib/executor.js +11 -6
  37. package/dist/lib/fake-timers.d.ts +13 -0
  38. package/dist/lib/fake-timers.d.ts.map +1 -0
  39. package/dist/lib/fake-timers.js +64 -0
  40. package/dist/lib/import-module.d.ts +2 -0
  41. package/dist/lib/import-module.d.ts.map +1 -0
  42. package/dist/lib/import-module.js +38 -0
  43. package/dist/lib/normalize.d.ts +2 -0
  44. package/dist/lib/normalize.d.ts.map +1 -0
  45. package/dist/lib/{utils.js → normalize.js} +0 -9
  46. package/dist/lib/playwright.d.ts +1 -1
  47. package/dist/lib/playwright.d.ts.map +1 -1
  48. package/dist/lib/playwright.js +5 -8
  49. package/dist/lib/reporters/dot.d.ts +1 -2
  50. package/dist/lib/reporters/dot.d.ts.map +1 -1
  51. package/dist/lib/reporters/dot.js +12 -1
  52. package/dist/lib/reporters/files.d.ts +1 -2
  53. package/dist/lib/reporters/files.d.ts.map +1 -1
  54. package/dist/lib/reporters/files.js +12 -1
  55. package/dist/lib/reporters/index.d.ts +4 -5
  56. package/dist/lib/reporters/index.d.ts.map +1 -1
  57. package/dist/lib/reporters/index.js +3 -3
  58. package/dist/lib/reporters/results.d.ts +30 -0
  59. package/dist/lib/reporters/results.d.ts.map +1 -0
  60. package/dist/lib/reporters/results.js +1 -0
  61. package/dist/lib/reporters/spec.d.ts +1 -2
  62. package/dist/lib/reporters/spec.d.ts.map +1 -1
  63. package/dist/lib/reporters/spec.js +12 -1
  64. package/dist/lib/reporters/tap.d.ts +1 -2
  65. package/dist/lib/reporters/tap.d.ts.map +1 -1
  66. package/dist/lib/reporters/tap.js +11 -1
  67. package/dist/lib/runner-browser.d.ts +21 -0
  68. package/dist/lib/runner-browser.d.ts.map +1 -0
  69. package/dist/lib/runner-browser.js +123 -0
  70. package/dist/lib/runner.d.ts +24 -2
  71. package/dist/lib/runner.d.ts.map +1 -1
  72. package/dist/lib/runner.js +216 -38
  73. package/dist/lib/runtime.d.ts +2 -0
  74. package/dist/lib/runtime.d.ts.map +1 -0
  75. package/dist/lib/runtime.js +2 -0
  76. package/dist/lib/ts-transform.d.ts +4 -0
  77. package/dist/lib/ts-transform.d.ts.map +1 -0
  78. package/dist/lib/ts-transform.js +29 -0
  79. package/dist/lib/worker-e2e-file.d.ts +11 -0
  80. package/dist/lib/worker-e2e-file.d.ts.map +1 -0
  81. package/dist/lib/worker-e2e-file.js +69 -0
  82. package/dist/lib/worker-e2e.js +11 -46
  83. package/dist/lib/worker-process.d.ts +2 -0
  84. package/dist/lib/worker-process.d.ts.map +1 -0
  85. package/dist/lib/worker-process.js +55 -0
  86. package/dist/lib/worker-results.d.ts +3 -0
  87. package/dist/lib/worker-results.d.ts.map +1 -0
  88. package/dist/lib/worker-results.js +20 -0
  89. package/dist/lib/worker-server.d.ts +10 -0
  90. package/dist/lib/worker-server.d.ts.map +1 -0
  91. package/dist/lib/worker-server.js +113 -0
  92. package/dist/lib/worker.js +7 -28
  93. package/dist/test/coverage/fixture.d.ts +5 -0
  94. package/dist/test/coverage/fixture.d.ts.map +1 -0
  95. package/dist/test/coverage/fixture.js +32 -0
  96. package/dist/test/coverage/test-browser.d.ts +2 -0
  97. package/dist/test/coverage/test-browser.d.ts.map +1 -0
  98. package/dist/test/coverage/test-browser.js +24 -0
  99. package/dist/test/coverage/test-e2e.d.ts +2 -0
  100. package/dist/test/coverage/test-e2e.d.ts.map +1 -0
  101. package/dist/test/coverage/test-e2e.js +60 -0
  102. package/dist/test/coverage/test-unit.d.ts +2 -0
  103. package/dist/test/coverage/test-unit.d.ts.map +1 -0
  104. package/dist/test/coverage/test-unit.js +27 -0
  105. package/dist/test/framework.test.browser.d.ts +2 -0
  106. package/dist/test/framework.test.browser.d.ts.map +1 -0
  107. package/dist/test/framework.test.browser.js +107 -0
  108. package/dist/test/framework.test.e2e.d.ts.map +1 -0
  109. package/dist/test/framework.test.e2e.js +34 -0
  110. package/package.json +30 -9
  111. package/src/app/client/entry.ts +357 -0
  112. package/src/app/client/iframe.ts +18 -0
  113. package/src/app/server.ts +336 -0
  114. package/src/cli-entry.ts +15 -0
  115. package/src/cli.ts +382 -145
  116. package/src/index.ts +2 -1
  117. package/src/lib/colors.ts +3 -0
  118. package/src/lib/config.ts +266 -54
  119. package/src/lib/context.ts +59 -17
  120. package/src/lib/coverage-loader.ts +31 -0
  121. package/src/lib/coverage.ts +320 -0
  122. package/src/lib/executor.ts +18 -35
  123. package/src/lib/fake-timers.ts +89 -0
  124. package/src/lib/import-module.ts +39 -0
  125. package/src/lib/{utils.ts → normalize.ts} +0 -18
  126. package/src/lib/playwright.ts +5 -7
  127. package/src/lib/reporters/dot.ts +12 -2
  128. package/src/lib/reporters/files.ts +12 -2
  129. package/src/lib/reporters/index.ts +4 -5
  130. package/src/lib/reporters/results.ts +29 -0
  131. package/src/lib/reporters/spec.ts +12 -2
  132. package/src/lib/reporters/tap.ts +11 -2
  133. package/src/lib/runner-browser.ts +171 -0
  134. package/src/lib/runner.ts +308 -53
  135. package/src/lib/runtime.ts +2 -0
  136. package/src/lib/ts-transform.ts +36 -0
  137. package/src/lib/worker-e2e-file.ts +98 -0
  138. package/src/lib/worker-e2e.ts +14 -49
  139. package/src/lib/worker-process.ts +69 -0
  140. package/src/lib/worker-results.ts +22 -0
  141. package/src/lib/worker-server.ts +123 -0
  142. package/src/lib/worker.ts +8 -28
  143. package/src/test/coverage/fixture.ts +34 -0
  144. package/src/test/coverage/test-browser.ts +29 -0
  145. package/src/test/coverage/test-e2e.ts +70 -0
  146. package/src/test/coverage/test-unit.ts +32 -0
  147. package/tsconfig.json +3 -1
  148. package/dist/lib/e2e-server.d.ts +0 -11
  149. package/dist/lib/e2e-server.d.ts.map +0 -1
  150. package/dist/lib/e2e-server.js +0 -15
  151. package/dist/lib/framework.test.d.ts +0 -2
  152. package/dist/lib/framework.test.d.ts.map +0 -1
  153. package/dist/lib/framework.test.e2e.d.ts.map +0 -1
  154. package/dist/lib/framework.test.e2e.js +0 -29
  155. package/dist/lib/framework.test.js +0 -283
  156. package/dist/lib/utils.d.ts +0 -16
  157. package/dist/lib/utils.d.ts.map +0 -1
  158. package/src/lib/e2e-server.ts +0 -28
  159. /package/dist/{lib → test}/framework.test.e2e.d.ts +0 -0
@@ -0,0 +1,6 @@
1
+ import * as http from 'node:http';
2
+ export declare function startServer(browserFiles: string[]): Promise<{
3
+ server: http.Server;
4
+ port: number;
5
+ }>;
6
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/app/server.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAQjC,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC;IAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkChD"}
@@ -0,0 +1,303 @@
1
+ import { init as initEsModuleLexer, parse as parseEsModule } from 'es-module-lexer';
2
+ import MagicString from 'magic-string';
3
+ import * as fsp from 'node:fs/promises';
4
+ import * as http from 'node:http';
5
+ import { createRequire } from 'node:module';
6
+ import * as path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { SourceMapConsumer, SourceMapGenerator } from 'source-map-js';
9
+ import { getBrowserTestRootDir, IS_RUNNING_FROM_SRC } from "../lib/config.js";
10
+ import { transformTypeScript } from "../lib/ts-transform.js";
11
+ export async function startServer(browserFiles) {
12
+ let handle = createRequestHandler(browserFiles);
13
+ let port = 44101;
14
+ let lastError;
15
+ for (let i = 0; i < 5; i++) {
16
+ try {
17
+ let server = http.createServer((req, res) => {
18
+ handle(req, res).catch((error) => {
19
+ console.error(`[remix-test] Unhandled error for ${req.url}:`, error);
20
+ if (!res.headersSent) {
21
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
22
+ }
23
+ if (!res.writableEnded)
24
+ res.end();
25
+ });
26
+ });
27
+ await new Promise((resolve, reject) => {
28
+ server.once('error', reject);
29
+ server.listen(port, () => {
30
+ server.removeListener('error', reject);
31
+ console.log(`Test server running on http://localhost:${port}`);
32
+ resolve();
33
+ });
34
+ });
35
+ return { server, port };
36
+ }
37
+ catch (error) {
38
+ if (error.code !== 'EADDRINUSE')
39
+ throw error;
40
+ lastError = error;
41
+ console.log(`Port ${port} is in use, trying another port...`);
42
+ port += 1;
43
+ }
44
+ }
45
+ throw lastError;
46
+ }
47
+ function createRequestHandler(browserFiles) {
48
+ let rootDir = getBrowserTestRootDir();
49
+ let srcDir = IS_RUNNING_FROM_SRC
50
+ ? // Up one directory from src/app/
51
+ path.join(path.dirname(fileURLToPath(import.meta.url)), '..')
52
+ : // Directory of the published index.js file
53
+ path.dirname(fileURLToPath(import.meta.resolve('@remix-run/test')));
54
+ let clientDir = path.join(srcDir, 'app', 'client');
55
+ let scriptExt = IS_RUNNING_FROM_SRC ? 'ts' : 'js';
56
+ let entryUrl = filePathToUrl(path.join(clientDir, `entry.${scriptExt}`), rootDir);
57
+ let iframeUrl = filePathToUrl(path.join(clientDir, `iframe.${scriptExt}`), rootDir);
58
+ if (!entryUrl || !iframeUrl) {
59
+ throw new Error(`Harness scripts in ${clientDir} are outside rootDir ${rootDir}`);
60
+ }
61
+ let testPaths = browserFiles.map((f) => filePathToUrl(f, rootDir));
62
+ return async (req, res) => {
63
+ let url = new URL(req.url ?? '/', 'http://localhost');
64
+ if (req.method !== 'GET') {
65
+ sendText(res, 405, 'Method Not Allowed');
66
+ return;
67
+ }
68
+ if (url.pathname === '/') {
69
+ let setupJson = JSON.stringify({ testPaths, baseDir: process.cwd() });
70
+ let body = `<script type="application/json" id="test-setup">` +
71
+ `${escapeJsonForScript(setupJson)}` +
72
+ `</script>` +
73
+ `<div id="test-root"></div>` +
74
+ `<script type="module" src="${entryUrl}"></script>`;
75
+ sendHtml(res, 'Tests', body);
76
+ return;
77
+ }
78
+ if (url.pathname === '/iframe') {
79
+ let test = decodeURIComponent(url.searchParams.get('file') || '');
80
+ sendHtml(res, `Test: ${test}`, `<script type="module" src="${iframeUrl}"></script>`);
81
+ return;
82
+ }
83
+ if (url.pathname.startsWith('/scripts/')) {
84
+ let filePath = urlPathToFilePath(url.pathname, rootDir);
85
+ if (filePath) {
86
+ try {
87
+ await serveScript(res, filePath, url.pathname, rootDir);
88
+ return;
89
+ }
90
+ catch (error) {
91
+ console.error(`[remix-test] Error serving ${url.pathname}:`, error);
92
+ sendText(res, 500, String(error));
93
+ return;
94
+ }
95
+ }
96
+ }
97
+ sendText(res, 404, 'Not found');
98
+ };
99
+ }
100
+ function filePathToUrl(filePath, rootDir) {
101
+ let rel = path.relative(rootDir, filePath);
102
+ if (rel.startsWith('..') || path.isAbsolute(rel))
103
+ return null;
104
+ return '/scripts/' + rel.split(path.sep).join('/');
105
+ }
106
+ // `/scripts/<rel>` → `<rootDir>/<rel>` (URL space mirrors the filesystem
107
+ // rooted at rootDir, with `..` segments rejected so requests can't escape).
108
+ function urlPathToFilePath(urlPath, rootDir) {
109
+ if (!urlPath.startsWith('/scripts/'))
110
+ return null;
111
+ let relative = urlPath.slice('/scripts/'.length);
112
+ if (!relative)
113
+ return null;
114
+ let filePath = path.resolve(rootDir, relative);
115
+ if (filePath !== rootDir && !filePath.startsWith(rootDir + path.sep))
116
+ return null;
117
+ return filePath;
118
+ }
119
+ const TS_EXTS = new Set(['.ts', '.tsx', '.mts', '.cts']);
120
+ const JS_EXTS = new Set(['.js', '.mjs', '.cjs', '.jsx']);
121
+ async function serveScript(res, filePath, urlPath, rootDir) {
122
+ let ext = path.extname(filePath);
123
+ let isTs = TS_EXTS.has(ext);
124
+ let isJs = JS_EXTS.has(ext);
125
+ if (!isTs && !isJs) {
126
+ sendText(res, 400, `Unsupported script extension "${ext}" for ${urlPath}`);
127
+ return;
128
+ }
129
+ let source = await fsp.readFile(filePath, 'utf-8');
130
+ let code;
131
+ if (isTs) {
132
+ try {
133
+ let result = await transformTypeScript(source, filePath);
134
+ code = result.code;
135
+ }
136
+ catch (error) {
137
+ let msg = error instanceof Error ? error.message : String(error);
138
+ console.error(`[remix-test] Failed to transform ${urlPath}: ${msg}`);
139
+ sendText(res, 500, msg);
140
+ return;
141
+ }
142
+ }
143
+ else {
144
+ code = source;
145
+ }
146
+ try {
147
+ code = await rewriteImports(code, filePath, rootDir);
148
+ }
149
+ catch (error) {
150
+ let msg = error instanceof Error ? error.message : String(error);
151
+ console.error(`[remix-test] Failed to rewrite imports for ${urlPath}: ${msg}`);
152
+ sendText(res, 500, msg);
153
+ return;
154
+ }
155
+ res.writeHead(200, { 'Content-Type': 'application/javascript' });
156
+ res.end(code);
157
+ }
158
+ // Rewrite every import/export specifier in the (already-transformed) source so
159
+ // it points at an absolute `/scripts/<rel>` URL the harness can serve. Bare
160
+ // specifiers go through Node's resolver; relative specifiers resolve against
161
+ // the importer file's directory. This keeps the URL space === filesystem
162
+ // layout so harness scripts (under clientDir) and source files (anywhere
163
+ // under rootDir) can import each other without URL-relative confusion.
164
+ //
165
+ // Uses es-module-lexer (purpose-built ESM scanner) + magic-string so that the
166
+ // edits compose cleanly with the inline TS→JS source map from
167
+ // transformTypeScript: the resulting inline map is a true rewrittenJS → TS
168
+ // map, not just the original TS → JS map slapped on top of mutated bytes.
169
+ async function rewriteImports(code, importerFile, rootDir) {
170
+ await initEsModuleLexer;
171
+ let { code: codeNoMap, map: tsToJsMap } = extractInlineSourceMap(code);
172
+ let [imports] = parseEsModule(codeNoMap);
173
+ let s = new MagicString(codeNoMap);
174
+ let edited = false;
175
+ for (let imp of imports) {
176
+ // n is the parsed specifier value (with escapes resolved); undefined when
177
+ // the dynamic import argument isn't a static string literal.
178
+ if (imp.n == null)
179
+ continue;
180
+ let url = resolveSpecifier(imp.n, importerFile, rootDir);
181
+ if (url == null || url === imp.n)
182
+ continue;
183
+ s.overwrite(imp.s, imp.e, url);
184
+ edited = true;
185
+ }
186
+ if (!edited)
187
+ return code;
188
+ let rewrittenCode = s.toString();
189
+ let rewriteMap = JSON.parse(s.generateMap({ hires: true }).toString());
190
+ let finalMap = tsToJsMap ? composeSourceMaps(rewriteMap, tsToJsMap) : rewriteMap;
191
+ let mapJson = JSON.stringify(finalMap);
192
+ let mapBase64 = Buffer.from(mapJson).toString('base64');
193
+ return `${rewrittenCode}\n//# sourceMappingURL=data:application/json;base64,${mapBase64}`;
194
+ }
195
+ // Strip the trailing `//# sourceMappingURL=data:application/json;base64,...`
196
+ // comment and decode the embedded JSON.
197
+ function extractInlineSourceMap(code) {
198
+ let re = /\n?\/\/# sourceMappingURL=data:application\/json(?:;charset=[^;,]+)?[;,]base64,([A-Za-z0-9+/=]+)\s*$/;
199
+ let match = code.match(re);
200
+ if (!match || match.index == null)
201
+ return { code, map: null };
202
+ try {
203
+ let decoded = Buffer.from(match[1], 'base64').toString('utf-8');
204
+ return { code: code.slice(0, match.index), map: JSON.parse(decoded) };
205
+ }
206
+ catch {
207
+ return { code, map: null };
208
+ }
209
+ }
210
+ // Compose two source maps so positions in `secondMap`'s generated code map all
211
+ // the way back to `firstMap`'s original sources. `secondMap`'s "original" must
212
+ // be in the same coordinate space as `firstMap`'s "generated" — i.e. for our
213
+ // case the input to magic-string is the output of transformTypeScript.
214
+ function composeSourceMaps(secondMap, firstMap) {
215
+ let secondConsumer = new SourceMapConsumer(secondMap);
216
+ let firstConsumer = new SourceMapConsumer(firstMap);
217
+ let gen = new SourceMapGenerator();
218
+ secondConsumer.eachMapping((mapping) => {
219
+ if (mapping.originalLine == null || mapping.originalColumn == null)
220
+ return;
221
+ let original = firstConsumer.originalPositionFor({
222
+ line: mapping.originalLine,
223
+ column: mapping.originalColumn,
224
+ });
225
+ if (original.line == null || original.column == null || original.source == null)
226
+ return;
227
+ gen.addMapping({
228
+ generated: { line: mapping.generatedLine, column: mapping.generatedColumn },
229
+ original: { line: original.line, column: original.column },
230
+ source: original.source,
231
+ name: original.name ?? mapping.name ?? undefined,
232
+ });
233
+ });
234
+ for (let source of firstConsumer.sources) {
235
+ let content = firstConsumer.sourceContentFor(source, true);
236
+ if (content !== null)
237
+ gen.setSourceContent(source, content);
238
+ }
239
+ return gen.toJSON();
240
+ }
241
+ function resolveSpecifier(spec, importerFile, rootDir) {
242
+ if (spec.startsWith('node:') ||
243
+ spec.startsWith('http:') ||
244
+ spec.startsWith('https:') ||
245
+ spec.startsWith('data:') ||
246
+ spec.startsWith('/scripts/')) {
247
+ return null;
248
+ }
249
+ let resolvedPath;
250
+ if (spec.startsWith('.') || spec.startsWith('/')) {
251
+ resolvedPath = path.resolve(path.dirname(importerFile), spec);
252
+ }
253
+ else {
254
+ // Bare specifiers must be resolved from the importer's filesystem
255
+ // location, not this module's. `import.meta.resolve(spec, parent)` looks
256
+ // like the right tool but its `parent` argument is gated behind
257
+ // `--experimental-import-meta-resolve` through at least Node 24 —
258
+ // without the flag, the parent argument is silently ignored and
259
+ // resolution happens from `import.meta.url` of the calling module. That
260
+ // made bare specifiers only resolvable when they were direct deps of
261
+ // `@remix-run/test` itself (so `remix/assert` failed even when the
262
+ // importing package depended on `remix`). `createRequire` walks
263
+ // node_modules from the importer's actual location and has been stable
264
+ // since Node 12 with no flags.
265
+ try {
266
+ resolvedPath = createRequire(importerFile).resolve(spec);
267
+ }
268
+ catch {
269
+ return null;
270
+ }
271
+ }
272
+ return filePathToUrl(resolvedPath, rootDir);
273
+ }
274
+ function sendHtml(res, title, body) {
275
+ let doc = `<!DOCTYPE html>` +
276
+ `<html>` +
277
+ `<head>` +
278
+ `<meta charset="utf-8">` +
279
+ `<title>${escapeHtml(title)}</title>` +
280
+ `</head>` +
281
+ `<body>${body}</body>` +
282
+ `</html>`;
283
+ res.writeHead(200, { 'Content-Type': 'text/html' });
284
+ res.end(doc);
285
+ }
286
+ function sendText(res, status, body) {
287
+ res.writeHead(status, { 'Content-Type': 'text/plain' });
288
+ res.end(body);
289
+ }
290
+ function escapeHtml(s) {
291
+ return s
292
+ .replace(/&/g, '&amp;')
293
+ .replace(/</g, '&lt;')
294
+ .replace(/>/g, '&gt;')
295
+ .replace(/"/g, '&quot;');
296
+ }
297
+ // Prevent the embedded JSON from terminating the surrounding <script> element
298
+ // or being interpreted as HTML. Only `</` needs escaping inside an
299
+ // `application/json` block; the leading `<` is preserved as `<` in the
300
+ // emitted JSON so JSON.parse round-trips it unchanged.
301
+ function escapeJsonForScript(json) {
302
+ return json.replace(/</g, '\\u003c');
303
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-entry.d.ts","sourceRoot":"","sources":["../src/cli-entry.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import * as process from 'node:process';
3
+ import { runRemixTest } from "./cli.js";
4
+ try {
5
+ let exitCode = await runRemixTest({
6
+ argv: process.argv.slice(2),
7
+ cwd: process.cwd(),
8
+ });
9
+ process.exit(exitCode);
10
+ }
11
+ catch (error) {
12
+ console.error('Error running tests:', error);
13
+ process.exit(1);
14
+ }
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- #!/usr/bin/env node
2
- export {};
1
+ import { getRemixTestHelpText } from './lib/config.ts';
2
+ export { getRemixTestHelpText };
3
+ export interface RunRemixTestOptions {
4
+ argv?: string[];
5
+ cwd?: string;
6
+ }
7
+ export declare function runRemixTest(options?: RunRemixTestOptions): Promise<number>;
3
8
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,oBAAoB,EAIrB,MAAM,iBAAiB,CAAA;AAWxB,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAK/B,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAWD,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAerF"}