@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 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
+ [![npm version](https://img.shields.io/npm/v/@isentinel/jest-roblox)](https://www.npmx.dev/package/@isentinel/jest-roblox)
4
+ [![CI](https://github.com/christopher-buss/jest-roblox-cli/actions/workflows/ci.yaml/badge.svg)](https://github.com/christopher-buss/jest-roblox-cli/actions/workflows/ci.yaml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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 takes your test files, builds a Roblox place, runs the tests
7
- in Roblox, and brings the results back to you. It works with both roblox-ts
8
- (TypeScript) and pure Luau projects. For TypeScript projects, it maps errors
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 use this?
15
+ ## Why?
12
16
 
13
- Roblox code needs Roblox to run. You can't test it with normal tools because
14
- the Roblox API only exists inside the engine. This tool runs your tests in a
15
- real Roblox session, then reports results in your terminal.
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
- - Works with roblox-ts and pure Luau projects
18
- - For TypeScript projects, maps Luau errors back to your `.ts` files
19
- - Collects code coverage so you know which lines your tests touch
20
- - Supports two backends: Roblox Open Cloud (remote) and Roblox Studio (local)
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
- ## Quick start
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
- Create a config file in your project root.
50
+ ## Quick start
31
51
 
32
- **roblox-ts project** (`jest.config.ts`):
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
- **Luau project** (`jest.config.json`):
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 --compact
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
- You can put your config in any of these formats (c12 discovers them
92
- automatically):
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
- - `jest.config.ts` / `jest.config.js` / `jest.config.mjs` / `jest.config.cjs`
95
- - `jest.config.json` / `jest.config.yaml` / `jest.config.toml`
112
+ Configs can extend a shared base with `extends`:
96
113
 
97
- CLI flags always win over config file values. Config file values always win over
98
- built-in defaults.
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` | `"auto"`, `"open-cloud"`, or `"studio"` | `"auto"` |
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
- ### Full example (roblox-ts)
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
- jest-roblox-cli can run tests two ways:
219
+ Two ways to run tests:
171
220
 
172
221
  ### Open Cloud (remote)
173
222
 
174
- Uploads your place file to Roblox, runs the tests there, and polls for results.
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 on your machine through a WebSocket plugin. This is
187
- faster because there is no upload step, but requires Roblox Studio to be open
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 `auto`, `open-cloud`, or `studio` |
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
- | `--json` | Output results as JSON |
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. Scans your project for files that match `testMatch` patterns
227
- 2. Uses Rojo to build a `.rbxl` file with your code
228
- 3. Sends the place to Roblox via Open Cloud or Studio over WebSocket
229
- 4. Reads Jest JSON output from the Roblox session
230
- 5. For roblox-ts projects, turns Luau line numbers into TypeScript line numbers
231
- using source maps
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
- > For coverage, there are extra steps. The tool copies your Luau files, adds
236
- > tracking code to each line, and builds a special place file. After the tests
237
- > run, it maps the tracking data back to your source. For roblox-ts projects, it
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
- The tool finds test files by these patterns (you can change them with
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/ Human, JSON, and compact output
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
- > This project keeps 100% test coverage. Write tests before you write code. Every pull request must keep full coverage.
340
+ > 100% test coverage is enforced. Write tests first. Every PR must maintain full coverage.
296
341
 
297
342
  ## License
298
343
 
@@ -1,4 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { main } from "../dist/cli.mjs";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
3
5
 
4
- main();
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 { t as CliOptions } from "./schema-DcDQmTyn.mjs";
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 };