@isentinel/jest-roblox 0.0.8 → 0.1.1

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,28 @@
1
- # jest-roblox-cli
1
+ <h1 align="center">jest-roblox-cli</h1>
2
2
 
3
- Run your TypeScript and Luau tests inside Roblox, then see the results in your
4
- terminal.
3
+ <p align="center">
4
+ <a href="https://www.npmx.dev/package/@isentinel/jest-roblox"><img src="https://img.shields.io/npm/v/@isentinel/jest-roblox" alt="npm version"></a>
5
+ <a href="https://github.com/christopher-buss/jest-roblox-cli/actions/workflows/ci.yaml"><img src="https://github.com/christopher-buss/jest-roblox-cli/actions/workflows/ci.yaml/badge.svg" alt="CI"></a>
6
+ <a href="https://github.com/christopher-buss/jest-roblox-cli/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
7
+ </p>
5
8
 
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.
10
9
 
11
- ## Why use this?
10
+ Run your roblox-ts and Luau tests inside Roblox, get results in your terminal.
12
11
 
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.
12
+ <p align="center">
13
+ <img src="assets/cli-example.png" alt="jest-roblox-cli output" width="700">
14
+ </p>
16
15
 
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)
16
+ - roblox-ts and pure Luau
17
+ - Source-mapped errors (Luau line numbers back to `.ts` files)
18
+ - Code coverage (via [Lute](https://github.com/luau-lang/lute) instrumentation)
19
+ - Two backends: Open Cloud (remote) and Studio (local)
20
+ - Multiple output formatters (human, agent, JSON, GitHub Actions)
21
+
22
+ > [!NOTE]
23
+ > roblox-ts projects currently require
24
+ > [@isentinel/roblox-ts](https://npmx.dev/package/@isentinel/roblox-ts) for
25
+ > source maps and coverage support.
21
26
 
22
27
  ## Install
23
28
 
@@ -25,11 +30,28 @@ real Roblox session, then reports results in your terminal.
25
30
  npm install @isentinel/jest-roblox
26
31
  ```
27
32
 
28
- ## Quick start
33
+ ### Standalone binary (no Node.js required)
34
+
35
+ Pre-built binaries are attached to each
36
+ [GitHub release](https://github.com/christopher-buss/jest-roblox-cli/releases).
37
+ Install with your preferred tool manager:
38
+
39
+ ```bash
40
+ mise use github:christopher-buss/jest-roblox-cli
41
+ rokit add christopher-buss/jest-roblox-cli
42
+
43
+ ```
44
+
45
+ Limitations vs the npm package:
29
46
 
30
- Create a config file in your project root.
47
+ - `--typecheck` and `--typecheckOnly` are not available
48
+ - `.ts` config files are not supported (use `.json`, `.js`, or `.mjs`)
49
+ - External tools (rojo, lute for coverage) must still be on your `PATH`
50
+
51
+ ## Quick start
31
52
 
32
- **roblox-ts project** (`jest.config.ts`):
53
+ Add a `jest.config.ts` (or `.js`, `.json`, `.yaml`, `.toml`) to your project
54
+ root:
33
55
 
34
56
  ```typescript
35
57
  import { defineConfig } from "@isentinel/jest-roblox";
@@ -40,17 +62,7 @@ export default defineConfig({
40
62
  });
41
63
  ```
42
64
 
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:
65
+ Then run:
54
66
 
55
67
  ```bash
56
68
  jest-roblox
@@ -71,6 +83,7 @@ jest-roblox -t "should spawn"
71
83
 
72
84
  # Filter by file path
73
85
  jest-roblox --testPathPattern player
86
+ jest-roblox --testPathPattern="modifiers|define\\.spec|triggers"
74
87
 
75
88
  # Use a specific backend
76
89
  jest-roblox --backend studio
@@ -79,54 +92,99 @@ jest-roblox --backend open-cloud
79
92
  # Collect coverage
80
93
  jest-roblox --coverage
81
94
 
82
- # Output JSON results
83
- jest-roblox --json --outputFile results.json
95
+ # Save game output (print/warn/error) to file
96
+ jest-roblox --gameOutput game-logs.txt
84
97
 
85
- # Short output for AI tools
86
- jest-roblox --compact
98
+ # Run only specific named projects
99
+ jest-roblox --project client
87
100
  ```
88
101
 
89
102
  ## Configuration
90
103
 
91
- You can put your config in any of these formats (c12 discovers them
92
- automatically):
104
+ Config files are loaded by [c12](https://github.com/unjs/c12), which
105
+ auto-discovers `jest.config.*` in any format it supports (`.ts`, `.js`, `.mjs`,
106
+ `.cjs`, `.json`, `.yaml`, `.toml`).
93
107
 
94
- - `jest.config.ts` / `jest.config.js` / `jest.config.mjs` / `jest.config.cjs`
95
- - `jest.config.json` / `jest.config.yaml` / `jest.config.toml`
108
+ Configs can extend a shared base with `extends`:
96
109
 
97
- CLI flags always win over config file values. Config file values always win over
98
- built-in defaults.
110
+ ```typescript
111
+ export default defineConfig({
112
+ extends: "../../jest.shared.ts",
113
+ projects: ["ReplicatedStorage/shared"],
114
+ });
115
+ ```
116
+
117
+ Precedence: CLI flags > config file > extended config > defaults.
99
118
 
100
119
  ### Config fields
101
120
 
102
121
  | Field | What it does | Default |
103
122
  |---|---|---|
104
123
  | `projects` | Where to look for tests in the DataModel | **required** |
105
- | `backend` | `"auto"`, `"open-cloud"`, or `"studio"` | `"auto"` |
124
+ | `backend` | `"open-cloud"` or `"studio"` | |
106
125
  | `placeFile` | Path to your `.rbxl` file | `"./game.rbxl"` |
107
126
  | `timeout` | Max time for tests to run (ms) | `300000` (5 min) |
108
127
  | `sourceMap` | Map Luau errors back to TypeScript (roblox-ts only) | `true` |
109
128
  | `port` | WebSocket port for Studio backend | `3001` |
110
129
  | `testMatch` | Glob patterns that find test files | `**/*.spec.ts`, `**/*.test.ts`, etc. |
111
- | `testPathIgnorePatterns` | Patterns to skip | `/node_modules/`, `/dist/` |
130
+ | `testPathIgnorePatterns` | Patterns to skip | `/node_modules/`, `/dist/`, `/out/` |
112
131
  | `rojoProject` | Path to your Rojo project file | auto |
113
132
  | `jestPath` | Where Jest lives in the DataModel | auto |
114
133
  | `setupFiles` | Scripts to run before the test environment loads | — |
115
134
  | `setupFilesAfterEnv` | Scripts to run after the test environment loads | — |
135
+ | `formatters` | Output formatters (`"default"`, `"agent"`, `"json"`, `"github-actions"`) | `["default"]` |
136
+ | `gameOutput` | Path to write game print/warn/error output | — |
137
+ | `showLuau` | Show Luau code snippets in failure output | `true` |
138
+ | `cache` | Cache place file uploads by content hash | `true` |
139
+ | `pollInterval` | How often to poll for results in ms (Open Cloud) | `500` |
116
140
 
117
141
  ### Coverage fields
118
142
 
143
+ > [!IMPORTANT]
144
+ > Coverage requires [Lute](https://github.com/luau-lang/lute) to be installed and
145
+ > on your `PATH`. Lute parses Luau ASTs so the CLI can insert coverage probes.
146
+
119
147
  | Field | What it does | Default |
120
148
  |---|---|---|
121
149
  | `collectCoverage` | Turn on coverage | `false` |
122
150
  | `coverageDirectory` | Where to write coverage reports | `"coverage"` |
123
151
  | `coverageReporters` | Which report formats to use | `["text", "lcov"]` |
124
152
  | `coverageThreshold` | Minimum coverage to pass | — |
125
- | `coveragePathIgnorePatterns` | Files to leave out of coverage | test files, node_modules |
153
+ | `coveragePathIgnorePatterns` | Files to leave out of coverage | test files, `node_modules`, `rbxts_include` |
126
154
  | `collectCoverageFrom` | Globs for files to include in coverage | — |
127
155
  | `luauRoots` | Where Luau files live (auto from tsconfig `outDir` for roblox-ts, or set by hand for pure Luau) | auto |
128
156
 
129
- ### Full example (roblox-ts)
157
+ ### Project-level config
158
+
159
+ `projects` can be strings (DataModel paths) or objects with per-project
160
+ overrides:
161
+
162
+ ```typescript
163
+ import { defineConfig, defineProject } from "@isentinel/jest-roblox";
164
+
165
+ export default defineConfig({
166
+ placeFile: "./game.rbxl",
167
+ projects: [
168
+ {
169
+ test: defineProject({
170
+ displayName: { name: "client", color: "magenta" },
171
+ include: ["**/*.spec.ts"],
172
+ mockDataModel: true,
173
+ outDir: "out/src/client",
174
+ }),
175
+ },
176
+ {
177
+ test: defineProject({
178
+ displayName: { name: "server", color: "white" },
179
+ include: ["**/*.spec.ts"],
180
+ outDir: "out/src/server",
181
+ }),
182
+ },
183
+ ],
184
+ });
185
+ ```
186
+
187
+ ### Full example
130
188
 
131
189
  ```typescript
132
190
  import { defineConfig } from "@isentinel/jest-roblox";
@@ -146,32 +204,13 @@ export default defineConfig({
146
204
  });
147
205
  ```
148
206
 
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
207
  ## Backends
169
208
 
170
- jest-roblox-cli can run tests two ways:
209
+ Two ways to run tests:
171
210
 
172
211
  ### Open Cloud (remote)
173
212
 
174
- Uploads your place file to Roblox, runs the tests there, and polls for results.
213
+ Uploads your place file to Roblox and polls for results.
175
214
 
176
215
  You need these environment variables:
177
216
 
@@ -183,29 +222,37 @@ You need these environment variables:
183
222
 
184
223
  ### Studio (local)
185
224
 
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.
225
+ Connects to Roblox Studio over WebSocket. Faster than Open Cloud (no upload
226
+ step), but Studio must be open with the plugin running. Studio doesn't expose which place is open, so
227
+ multiple concurrent projects aren't supported yet.
228
+
229
+ Install the plugin with [Drillbit](https://github.com/jacktabscode/drillbit):
189
230
 
190
- > [!TIP]
191
- > In auto mode, the CLI tries Studio first. If Studio is not running, it falls back to Open Cloud.
231
+ ```bash
232
+ drillbit install christopher-buss/jest-roblox-cli
233
+ ```
234
+
235
+ Or download `JestRobloxRunner.rbxm` from the
236
+ [latest release](https://github.com/christopher-buss/jest-roblox-cli/releases)
237
+ and drop it into your Studio plugins folder.
192
238
 
193
239
  ## CLI flags
194
240
 
195
241
  | Flag | What it does |
196
242
  |---|---|
197
- | `--backend <type>` | Choose `auto`, `open-cloud`, or `studio` |
243
+ | `--backend <type>` | Choose `open-cloud` or `studio` |
198
244
  | `--port <n>` | WebSocket port for Studio |
199
245
  | `--config <path>` | Path to config file |
200
246
  | `--testPathPattern <regex>` | Filter test files by path |
201
247
  | `-t, --testNamePattern <regex>` | Filter tests by name |
202
- | `--json` | Output results as JSON |
203
- | `--compact` | Short output for AI tools |
248
+ | `--formatters <name...>` | Output formatters (`default`, `agent`, `json`, `github-actions`) |
204
249
  | `--outputFile <path>` | Write results to a file |
250
+ | `--gameOutput <path>` | Write game print/warn/error to a file |
205
251
  | `--coverage` | Collect coverage |
206
252
  | `--coverageDirectory <path>` | Where to put coverage reports |
207
253
  | `--coverageReporters <r...>` | Which report formats to use |
208
254
  | `--luauRoots <path...>` | Where compiled Luau files live |
255
+ | `--no-show-luau` | Hide Luau code in failure output |
209
256
  | `-u, --updateSnapshot` | Update snapshot files |
210
257
  | `--sourceMap` | Map Luau errors to TypeScript (roblox-ts only) |
211
258
  | `--rojoProject <path>` | Path to Rojo project file |
@@ -214,6 +261,7 @@ and running the plugin.
214
261
  | `--no-color` | Turn off colors |
215
262
  | `--no-cache` | Force a fresh place file upload |
216
263
  | `--pollInterval <ms>` | How often to check for results (Open Cloud) |
264
+ | `--project <name...>` | Filter which named projects to run |
217
265
  | `--projects <path...>` | DataModel paths that hold tests |
218
266
  | `--setupFiles <path...>` | Scripts to run before env |
219
267
  | `--setupFilesAfterEnv <path...>` | Scripts to run after env |
@@ -223,76 +271,29 @@ and running the plugin.
223
271
 
224
272
  ## How it works
225
273
 
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
274
+ 1. Finds files matching `testMatch` patterns
275
+ 2. Builds a `.rbxl` via Rojo
276
+ 3. Sends the place to Roblox (Open Cloud upload or Studio WebSocket)
277
+ 4. Parses Jest JSON output from the session
278
+ 5. Maps Luau line numbers to TypeScript via source maps (roblox-ts only)
279
+ 6. Prints results
233
280
 
234
281
  > [!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.
282
+ > Coverage adds extra steps: copy Luau files, insert tracking probes, build a
283
+ > separate place file, then map hit counts back to source. For roblox-ts, this
284
+ > goes through source maps to report TypeScript lines.
239
285
 
240
286
  ## Test file patterns
241
287
 
242
- The tool finds test files by these patterns (you can change them with
243
- `testMatch`):
288
+ Default `testMatch` patterns (configurable):
244
289
 
245
290
  - TypeScript: `*.spec.ts`, `*.test.ts`, `*.spec.tsx`, `*.test.tsx`
246
291
  - Luau: `*.spec.lua`, `*.test.lua`, `*.spec.luau`, `*.test.luau`
247
292
  - Type tests: `*.spec-d.ts`, `*.test-d.ts`
248
293
 
249
- ## Project structure
250
-
251
- ```text
252
- jest-roblox-cli/
253
- ├── bin/ CLI entry point
254
- ├── src/
255
- │ ├── backends/ Open Cloud and Studio backends
256
- │ ├── config/ Config loading and validation
257
- │ ├── coverage/ Coverage instrumentation pipeline
258
- │ ├── formatters/ Human, JSON, and compact output
259
- │ ├── reporter/ Result parsing and validation
260
- │ ├── source-mapper/ Luau-to-TypeScript error mapping
261
- │ ├── snapshot/ Snapshot file handling
262
- │ ├── typecheck/ Type test runner
263
- │ ├── types/ Shared type definitions
264
- │ └── utils/ Helpers (glob, hash, cache, paths)
265
- ├── luau/ Luau code that runs inside Roblox
266
- ├── plugin/ Roblox Studio WebSocket plugin
267
- └── test/ Test fixtures and mocks
268
- ```
269
-
270
294
  ## Contributing
271
295
 
272
- ### Build
273
-
274
- ```bash
275
- pnpm build # Full build
276
- pnpm watch # Watch mode
277
- pnpm typecheck # Check types
278
- ```
279
-
280
- ### Test
281
-
282
- ```bash
283
- vitest run # All tests
284
- vitest run src/formatters # One folder
285
- vitest run src/cli.spec.ts # One file
286
- ```
287
-
288
- ### Lint
289
-
290
- ```bash
291
- eslint .
292
- ```
293
-
294
- > [!IMPORTANT]
295
- > This project keeps 100% test coverage. Write tests before you write code. Every pull request must keep full coverage.
296
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
296
297
 
297
298
  ## License
298
299
 
@@ -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 };