@isentinel/jest-roblox 0.0.8 → 0.1.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/LICENSE.md +21 -0
- package/README.md +128 -83
- package/bin/jest-roblox.js +14 -2
- package/dist/cli.d.mts +4 -2
- package/dist/cli.mjs +920 -183
- package/dist/{schema-DcDQmTyn.d.mts → executor-DqZE3wME.d.mts} +236 -31
- package/dist/{game-output-M8du29nj.mjs → game-output-C0_-YIAY.mjs} +1095 -468
- package/dist/index.d.mts +6 -145
- package/dist/index.mjs +2 -3
- package/dist/sea/jest-roblox +0 -0
- package/dist/sea-entry.cjs +61580 -0
- package/package.json +17 -42
- package/plugin/JestRobloxRunner.rbxm +0 -0
- package/plugin/out/shared/instance-resolver.luau +3 -8
- package/plugin/out/shared/runner.luau +62 -13
- package/plugin/out/shared/snapshot-patch.luau +2 -7
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christopher Buss
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
# jest-roblox-cli
|
|
2
2
|
|
|
3
|
+
[](https://www.npmx.dev/package/@isentinel/jest-roblox)
|
|
4
|
+
[](https://github.com/christopher-buss/jest-roblox-cli/actions/workflows/ci.yaml)
|
|
5
|
+
[](https://github.com/christopher-buss/jest-roblox-cli/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
|
|
3
8
|
Run your TypeScript and Luau tests inside Roblox, then see the results in your
|
|
4
9
|
terminal.
|
|
5
10
|
|
|
6
|
-
jest-roblox-cli
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
back to your original source.
|
|
11
|
+
jest-roblox-cli builds a Roblox place from your test files, runs it in Roblox,
|
|
12
|
+
and reports results in your terminal. It works with roblox-ts and pure Luau
|
|
13
|
+
projects. For TypeScript, it maps Luau errors back to your `.ts` source.
|
|
10
14
|
|
|
11
|
-
## Why
|
|
15
|
+
## Why?
|
|
12
16
|
|
|
13
|
-
Roblox code
|
|
14
|
-
the Roblox API
|
|
15
|
-
real Roblox session
|
|
17
|
+
Roblox code can only run inside the Roblox engine. Standard test runners
|
|
18
|
+
can't access the Roblox API. This tool bridges that gap by running tests in a
|
|
19
|
+
real Roblox session and piping results back to your terminal.
|
|
16
20
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
+
- roblox-ts and pure Luau
|
|
22
|
+
- Source-mapped errors (Luau line numbers back to `.ts` files)
|
|
23
|
+
- Code coverage
|
|
24
|
+
- Two backends: Open Cloud (remote) and Studio (local)
|
|
21
25
|
|
|
22
26
|
## Install
|
|
23
27
|
|
|
@@ -25,11 +29,28 @@ real Roblox session, then reports results in your terminal.
|
|
|
25
29
|
npm install @isentinel/jest-roblox
|
|
26
30
|
```
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
### Standalone binary (no Node.js required)
|
|
33
|
+
|
|
34
|
+
Pre-built binaries are attached to each
|
|
35
|
+
[GitHub release](https://github.com/christopher-buss/jest-roblox-cli/releases).
|
|
36
|
+
Install with your preferred tool manager:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
mise use github:christopher-buss/jest-roblox-cli
|
|
40
|
+
rokit add christopher-buss/jest-roblox-cli
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The standalone binary has a few limitations compared to the npm package:
|
|
45
|
+
|
|
46
|
+
- `--typecheck` and `--typecheckOnly` are not available
|
|
47
|
+
- `.ts` config files are not supported (use `.json`, `.js`, or `.mjs`)
|
|
48
|
+
- External tools (rojo, lute for coverage) must still be on your `PATH`
|
|
29
49
|
|
|
30
|
-
|
|
50
|
+
## Quick start
|
|
31
51
|
|
|
32
|
-
|
|
52
|
+
Add a `jest.config.ts` (or `.js`, `.json`, `.yaml`, `.toml`) to your project
|
|
53
|
+
root:
|
|
33
54
|
|
|
34
55
|
```typescript
|
|
35
56
|
import { defineConfig } from "@isentinel/jest-roblox";
|
|
@@ -40,17 +61,7 @@ export default defineConfig({
|
|
|
40
61
|
});
|
|
41
62
|
```
|
|
42
63
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```json
|
|
46
|
-
{
|
|
47
|
-
"luauRoots": ["./src"],
|
|
48
|
-
"placeFile": "./game.rbxl",
|
|
49
|
-
"projects": ["ReplicatedStorage/shared"]
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Then run your tests:
|
|
64
|
+
Then run:
|
|
54
65
|
|
|
55
66
|
```bash
|
|
56
67
|
jest-roblox
|
|
@@ -80,53 +91,110 @@ jest-roblox --backend open-cloud
|
|
|
80
91
|
jest-roblox --coverage
|
|
81
92
|
|
|
82
93
|
# Output JSON results
|
|
83
|
-
jest-roblox --json --outputFile results.json
|
|
94
|
+
jest-roblox --formatters json --outputFile results.json
|
|
84
95
|
|
|
85
96
|
# Short output for AI tools
|
|
86
|
-
jest-roblox --
|
|
97
|
+
jest-roblox --formatters agent
|
|
98
|
+
|
|
99
|
+
# Save game output (print/warn/error) to file
|
|
100
|
+
jest-roblox --gameOutput game-logs.txt
|
|
101
|
+
|
|
102
|
+
# Run only specific named projects
|
|
103
|
+
jest-roblox --project client
|
|
87
104
|
```
|
|
88
105
|
|
|
89
106
|
## Configuration
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
Config files are loaded by [c12](https://github.com/unjs/c12), which
|
|
109
|
+
auto-discovers `jest.config.*` in any format it supports (`.ts`, `.js`, `.mjs`,
|
|
110
|
+
`.cjs`, `.json`, `.yaml`, `.toml`).
|
|
93
111
|
|
|
94
|
-
|
|
95
|
-
- `jest.config.json` / `jest.config.yaml` / `jest.config.toml`
|
|
112
|
+
Configs can extend a shared base with `extends`:
|
|
96
113
|
|
|
97
|
-
|
|
98
|
-
|
|
114
|
+
```typescript
|
|
115
|
+
export default defineConfig({
|
|
116
|
+
extends: "../../jest.shared.ts",
|
|
117
|
+
projects: ["ReplicatedStorage/shared"],
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Precedence: CLI flags > config file > extended config > defaults.
|
|
99
122
|
|
|
100
123
|
### Config fields
|
|
101
124
|
|
|
102
125
|
| Field | What it does | Default |
|
|
103
126
|
|---|---|---|
|
|
104
127
|
| `projects` | Where to look for tests in the DataModel | **required** |
|
|
105
|
-
| `backend` | `"
|
|
128
|
+
| `backend` | `"open-cloud"` or `"studio"` | — |
|
|
106
129
|
| `placeFile` | Path to your `.rbxl` file | `"./game.rbxl"` |
|
|
107
130
|
| `timeout` | Max time for tests to run (ms) | `300000` (5 min) |
|
|
108
131
|
| `sourceMap` | Map Luau errors back to TypeScript (roblox-ts only) | `true` |
|
|
109
132
|
| `port` | WebSocket port for Studio backend | `3001` |
|
|
110
133
|
| `testMatch` | Glob patterns that find test files | `**/*.spec.ts`, `**/*.test.ts`, etc. |
|
|
111
|
-
| `testPathIgnorePatterns` | Patterns to skip | `/node_modules/`, `/dist/` |
|
|
134
|
+
| `testPathIgnorePatterns` | Patterns to skip | `/node_modules/`, `/dist/`, `/out/` |
|
|
112
135
|
| `rojoProject` | Path to your Rojo project file | auto |
|
|
113
136
|
| `jestPath` | Where Jest lives in the DataModel | auto |
|
|
114
137
|
| `setupFiles` | Scripts to run before the test environment loads | — |
|
|
115
138
|
| `setupFilesAfterEnv` | Scripts to run after the test environment loads | — |
|
|
139
|
+
| `formatters` | Output formatters (`"default"`, `"agent"`, `"json"`, `"github-actions"`) | `["default"]` |
|
|
140
|
+
| `gameOutput` | Path to write game print/warn/error output | — |
|
|
141
|
+
| `showLuau` | Show Luau code snippets in failure output | `true` |
|
|
142
|
+
| `cache` | Cache place file uploads by content hash | `true` |
|
|
143
|
+
| `pollInterval` | How often to poll for results in ms (Open Cloud) | `500` |
|
|
116
144
|
|
|
117
145
|
### Coverage fields
|
|
118
146
|
|
|
147
|
+
> [!IMPORTANT]
|
|
148
|
+
> Coverage requires [Lute](https://github.com/4lve/lute) to be installed and
|
|
149
|
+
> on your `PATH`. Lute parses Luau ASTs so the CLI can insert coverage probes.
|
|
150
|
+
|
|
119
151
|
| Field | What it does | Default |
|
|
120
152
|
|---|---|---|
|
|
121
153
|
| `collectCoverage` | Turn on coverage | `false` |
|
|
122
154
|
| `coverageDirectory` | Where to write coverage reports | `"coverage"` |
|
|
123
155
|
| `coverageReporters` | Which report formats to use | `["text", "lcov"]` |
|
|
124
156
|
| `coverageThreshold` | Minimum coverage to pass | — |
|
|
125
|
-
| `coveragePathIgnorePatterns` | Files to leave out of coverage | test files, node_modules |
|
|
157
|
+
| `coveragePathIgnorePatterns` | Files to leave out of coverage | test files, `node_modules`, `rbxts_include` |
|
|
126
158
|
| `collectCoverageFrom` | Globs for files to include in coverage | — |
|
|
127
159
|
| `luauRoots` | Where Luau files live (auto from tsconfig `outDir` for roblox-ts, or set by hand for pure Luau) | auto |
|
|
128
160
|
|
|
129
|
-
###
|
|
161
|
+
### Project-level config
|
|
162
|
+
|
|
163
|
+
`projects` can be strings (DataModel paths) or objects with per-project
|
|
164
|
+
overrides:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { defineConfig, defineProject } from "@isentinel/jest-roblox";
|
|
168
|
+
|
|
169
|
+
export default defineConfig({
|
|
170
|
+
placeFile: "./game.rbxl",
|
|
171
|
+
projects: [
|
|
172
|
+
{
|
|
173
|
+
test: defineProject({
|
|
174
|
+
displayName: { name: "core", color: "magenta" },
|
|
175
|
+
include: ["src/**/*.spec.ts"],
|
|
176
|
+
mockDataModel: true,
|
|
177
|
+
outDir: "out-test/src",
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
test: defineProject({
|
|
182
|
+
displayName: { name: "core:integration", color: "white" },
|
|
183
|
+
include: ["test/**/*.spec.ts"],
|
|
184
|
+
mockDataModel: true,
|
|
185
|
+
outDir: "out-test/test",
|
|
186
|
+
}),
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Available per-project fields: `displayName`, `include`, `exclude`, `testMatch`,
|
|
193
|
+
`testRegex`, `testPathIgnorePatterns`, `setupFiles`, `setupFilesAfterEnv`,
|
|
194
|
+
`testTimeout`, `slowTestThreshold`, `testEnvironment`, `snapshotFormat`,
|
|
195
|
+
`outDir`, `root`, and the Jest mock flags (`clearMocks`, `resetMocks`, etc.).
|
|
196
|
+
|
|
197
|
+
### Full example
|
|
130
198
|
|
|
131
199
|
```typescript
|
|
132
200
|
import { defineConfig } from "@isentinel/jest-roblox";
|
|
@@ -146,32 +214,13 @@ export default defineConfig({
|
|
|
146
214
|
});
|
|
147
215
|
```
|
|
148
216
|
|
|
149
|
-
### Full example (Luau)
|
|
150
|
-
|
|
151
|
-
```json
|
|
152
|
-
{
|
|
153
|
-
"backend": "open-cloud",
|
|
154
|
-
"collectCoverage": true,
|
|
155
|
-
"coverageThreshold": {
|
|
156
|
-
"branches": 70,
|
|
157
|
-
"functions": 80,
|
|
158
|
-
"statements": 80
|
|
159
|
-
},
|
|
160
|
-
"jestPath": "ReplicatedStorage/Packages/Jest",
|
|
161
|
-
"luauRoots": ["./src"],
|
|
162
|
-
"placeFile": "./game.rbxl",
|
|
163
|
-
"projects": ["ReplicatedStorage/client", "ServerScriptService/server"],
|
|
164
|
-
"timeout": 60000
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
217
|
## Backends
|
|
169
218
|
|
|
170
|
-
|
|
219
|
+
Two ways to run tests:
|
|
171
220
|
|
|
172
221
|
### Open Cloud (remote)
|
|
173
222
|
|
|
174
|
-
Uploads your place file to Roblox
|
|
223
|
+
Uploads your place file to Roblox and polls for results.
|
|
175
224
|
|
|
176
225
|
You need these environment variables:
|
|
177
226
|
|
|
@@ -183,29 +232,26 @@ You need these environment variables:
|
|
|
183
232
|
|
|
184
233
|
### Studio (local)
|
|
185
234
|
|
|
186
|
-
Connects to Roblox Studio
|
|
187
|
-
|
|
188
|
-
and running the plugin.
|
|
189
|
-
|
|
190
|
-
> [!TIP]
|
|
191
|
-
> In auto mode, the CLI tries Studio first. If Studio is not running, it falls back to Open Cloud.
|
|
235
|
+
Connects to Roblox Studio over WebSocket. Faster than Open Cloud (no upload
|
|
236
|
+
step), but Studio must be open with the plugin running.
|
|
192
237
|
|
|
193
238
|
## CLI flags
|
|
194
239
|
|
|
195
240
|
| Flag | What it does |
|
|
196
241
|
|---|---|
|
|
197
|
-
| `--backend <type>` | Choose `
|
|
242
|
+
| `--backend <type>` | Choose `open-cloud` or `studio` |
|
|
198
243
|
| `--port <n>` | WebSocket port for Studio |
|
|
199
244
|
| `--config <path>` | Path to config file |
|
|
200
245
|
| `--testPathPattern <regex>` | Filter test files by path |
|
|
201
246
|
| `-t, --testNamePattern <regex>` | Filter tests by name |
|
|
202
|
-
| `--
|
|
203
|
-
| `--compact` | Short output for AI tools |
|
|
247
|
+
| `--formatters <name...>` | Output formatters (`default`, `agent`, `json`, `github-actions`) |
|
|
204
248
|
| `--outputFile <path>` | Write results to a file |
|
|
249
|
+
| `--gameOutput <path>` | Write game print/warn/error to a file |
|
|
205
250
|
| `--coverage` | Collect coverage |
|
|
206
251
|
| `--coverageDirectory <path>` | Where to put coverage reports |
|
|
207
252
|
| `--coverageReporters <r...>` | Which report formats to use |
|
|
208
253
|
| `--luauRoots <path...>` | Where compiled Luau files live |
|
|
254
|
+
| `--no-show-luau` | Hide Luau code in failure output |
|
|
209
255
|
| `-u, --updateSnapshot` | Update snapshot files |
|
|
210
256
|
| `--sourceMap` | Map Luau errors to TypeScript (roblox-ts only) |
|
|
211
257
|
| `--rojoProject <path>` | Path to Rojo project file |
|
|
@@ -214,6 +260,7 @@ and running the plugin.
|
|
|
214
260
|
| `--no-color` | Turn off colors |
|
|
215
261
|
| `--no-cache` | Force a fresh place file upload |
|
|
216
262
|
| `--pollInterval <ms>` | How often to check for results (Open Cloud) |
|
|
263
|
+
| `--project <name...>` | Filter which named projects to run |
|
|
217
264
|
| `--projects <path...>` | DataModel paths that hold tests |
|
|
218
265
|
| `--setupFiles <path...>` | Scripts to run before env |
|
|
219
266
|
| `--setupFilesAfterEnv <path...>` | Scripts to run after env |
|
|
@@ -223,24 +270,21 @@ and running the plugin.
|
|
|
223
270
|
|
|
224
271
|
## How it works
|
|
225
272
|
|
|
226
|
-
1.
|
|
227
|
-
2.
|
|
228
|
-
3. Sends the place to Roblox
|
|
229
|
-
4.
|
|
230
|
-
5.
|
|
231
|
-
|
|
232
|
-
6. Prints pass/fail results in your terminal
|
|
273
|
+
1. Finds files matching `testMatch` patterns
|
|
274
|
+
2. Builds a `.rbxl` via Rojo
|
|
275
|
+
3. Sends the place to Roblox (Open Cloud upload or Studio WebSocket)
|
|
276
|
+
4. Parses Jest JSON output from the session
|
|
277
|
+
5. Maps Luau line numbers to TypeScript via source maps (roblox-ts only)
|
|
278
|
+
6. Prints results
|
|
233
279
|
|
|
234
280
|
> [!NOTE]
|
|
235
|
-
>
|
|
236
|
-
>
|
|
237
|
-
>
|
|
238
|
-
> maps through source maps to show TypeScript lines.
|
|
281
|
+
> Coverage adds extra steps: copy Luau files, insert tracking probes, build a
|
|
282
|
+
> separate place file, then map hit counts back to source. For roblox-ts, this
|
|
283
|
+
> goes through source maps to report TypeScript lines.
|
|
239
284
|
|
|
240
285
|
## Test file patterns
|
|
241
286
|
|
|
242
|
-
|
|
243
|
-
`testMatch`):
|
|
287
|
+
Default `testMatch` patterns (configurable):
|
|
244
288
|
|
|
245
289
|
- TypeScript: `*.spec.ts`, `*.test.ts`, `*.spec.tsx`, `*.test.tsx`
|
|
246
290
|
- Luau: `*.spec.lua`, `*.test.lua`, `*.spec.luau`, `*.test.luau`
|
|
@@ -255,7 +299,8 @@ jest-roblox-cli/
|
|
|
255
299
|
│ ├── backends/ Open Cloud and Studio backends
|
|
256
300
|
│ ├── config/ Config loading and validation
|
|
257
301
|
│ ├── coverage/ Coverage instrumentation pipeline
|
|
258
|
-
│ ├── formatters/
|
|
302
|
+
│ ├── formatters/ Output formatters (default, agent, JSON, GitHub Actions)
|
|
303
|
+
│ ├── highlighter/ Luau syntax highlighting
|
|
259
304
|
│ ├── reporter/ Result parsing and validation
|
|
260
305
|
│ ├── source-mapper/ Luau-to-TypeScript error mapping
|
|
261
306
|
│ ├── snapshot/ Snapshot file handling
|
|
@@ -292,7 +337,7 @@ eslint .
|
|
|
292
337
|
```
|
|
293
338
|
|
|
294
339
|
> [!IMPORTANT]
|
|
295
|
-
>
|
|
340
|
+
> 100% test coverage is enforced. Write tests first. Every PR must maintain full coverage.
|
|
296
341
|
|
|
297
342
|
## License
|
|
298
343
|
|
package/bin/jest-roblox.js
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
const sourceEntry = resolve(dirname(fileURLToPath(import.meta.url)), "../src/cli.ts");
|
|
7
|
+
|
|
8
|
+
if (existsSync(sourceEntry)) {
|
|
9
|
+
const { register } = await import("node:module");
|
|
10
|
+
register("../loaders/luau-raw.mjs", import.meta.url);
|
|
11
|
+
const { main } = await import("../src/cli.ts");
|
|
12
|
+
main();
|
|
13
|
+
} else {
|
|
14
|
+
const { main } = await import("../dist/cli.mjs");
|
|
15
|
+
main();
|
|
16
|
+
}
|
package/dist/cli.d.mts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as ResolvedProjectConfig, n as ExecuteResult, v as CliOptions } from "./executor-DqZE3wME.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/cli.d.ts
|
|
4
4
|
declare function parseArgs(args: Array<string>): CliOptions;
|
|
5
|
+
declare function filterByName(projects: Array<ResolvedProjectConfig>, names: Array<string>): Array<ResolvedProjectConfig>;
|
|
6
|
+
declare function mergeProjectResults(results: Array<ExecuteResult>): ExecuteResult;
|
|
5
7
|
declare function run(args: Array<string>): Promise<number>;
|
|
6
8
|
declare function main(): Promise<void>;
|
|
7
9
|
//#endregion
|
|
8
|
-
export { main, parseArgs, run };
|
|
10
|
+
export { filterByName, main, mergeProjectResults, parseArgs, run };
|