Skip to content

Commit 5728ccc

Browse files
authored
feat: vitest support (#80)
1 parent b2b87e2 commit 5728ccc

86 files changed

Lines changed: 6735 additions & 5021 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,6 @@
1-
.DS_Store
2-
3-
test-app/
4-
5-
*.js
6-
*.js.map
7-
!nativescript.webpack.js
8-
!nativescript.webpack.compat.js
9-
!loaders/unit-test-loader.js
10-
11-
coverage
12-
lib-cov
13-
*.seed
14-
*.log
15-
*.csv
16-
*.dat
17-
*.out
18-
*.pid
19-
*.gz
1+
node_modules/
2+
dist/
203
*.tgz
21-
*.tmp
22-
*.sublime-workspace
23-
tscommand*.tmp.txt
24-
.tscache/
25-
26-
pids
27-
logs
28-
results
29-
scratch/
30-
.idea/
31-
.settings/
32-
.vscode/
33-
test-reports.xml
34-
package-lock.json
35-
36-
npm-debug.log
37-
node_modules
38-
.d.ts
39-
40-
platforms/android/nativescript_unit_test_runner.aar
41-
platforms/android/unit_test_runner.aar
4+
*.tsbuildinfo
5+
.DS_Store
6+
coverage/

‎.npmignore‎

Lines changed: 0 additions & 19 deletions
This file was deleted.

‎README.md‎

Lines changed: 134 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,146 @@
1-
Unit test runner for NativeScript
2-
=================================
1+
# @nativescript/unit-test-runner
32

4-
Refer to the documentation of NativeScript CLI's `ns test init` command for usage.
3+
Run [Vitest](https://vitest.dev) unit **and UI** tests inside real NativeScript
4+
runtimes on Android, iOS, and visionOS.
55

6-
If you encounter an issue, please log it at https://github.com/NativeScript/nativescript-cli/
6+
Vitest stays on your machine as the orchestrator — configuration, CLI,
7+
reporters, `--ui`, coverage, and editor integrations all work as usual — while
8+
your specs execute on device/emulator inside the actual V8/JSC runtimes, with
9+
full access to native APIs and the NativeScript UI layer.
710

8-
### Troubleshooting
11+
> Version 5 is a complete rewrite. Karma-based testing (v4 and below) is
12+
> deprecated; see the [migration guide](./docs/migrating-from-karma.md).
913
10-
If you see an error like this:
14+
## Quick start
1115

16+
```bash
17+
ns test init --framework vitest
18+
ns test ios # or: ns test android / ns test visionos
1219
```
13-
Error: connect ECONNREFUSED ::1:9876
14-
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1195:16)
20+
21+
Or run Vitest directly (what editor extensions and CI use):
22+
23+
```bash
24+
NS_PLATFORM=ios npx vitest run
25+
```
26+
27+
## How it works
28+
29+
- A Vitest plugin installs a custom pool that forwards Vitest's standard
30+
worker protocol over a WebSocket bridge (bound to `127.0.0.1`).
31+
- The plugin launches your app via `ns run <platform> --no-hmr
32+
--env.unitTesting`; the webpack helper (auto-discovered from this package)
33+
swaps the bundle entry to your `test.ts` for test builds only.
34+
- On device, a coordinator connects back to the host and executes specs:
35+
- **Main-thread context (default):** specs run on the UI thread, so they can
36+
create Views, navigate Frames, and use every NativeScript API.
37+
- **Worker contexts (opt-in):** additional isolated NativeScript `Worker`
38+
runtimes for parallel, non-UI specs.
39+
- Results flow through Vitest's normal RPC, so every reporter works unchanged.
40+
41+
## Configuration
42+
43+
```ts
44+
// vitest.config.mts
45+
import { defineConfig } from 'vitest/config';
46+
import { nativeScript } from '@nativescript/unit-test-runner';
47+
48+
export default defineConfig({
49+
plugins: [
50+
nativeScript({
51+
platform: process.env.NS_PLATFORM || 'ios', // 'android' | 'ios' | 'visionos'
52+
device: process.env.NS_DEVICE || undefined,
53+
// workers: 2, // extra Worker runtimes for non-UI specs
54+
// mainThread: false, // disable the UI-capable slot (workers only)
55+
// port: 17878,
56+
// launch: false, // attach to an app you run yourself
57+
}),
58+
],
59+
});
60+
```
61+
62+
Per-platform setups are possible with [Vitest projects](https://vitest.dev/guide/projects)
63+
— give each project its own `nativeScript({ platform })` plugin instance.
64+
65+
## UI testing
66+
67+
```ts
68+
import { describe, expect, it } from 'vitest';
69+
import { Button } from '@nativescript/core';
70+
import { mount, tap } from '@nativescript/unit-test-runner/testing';
71+
72+
describe('counter button', () => {
73+
it('increments on tap', async () => {
74+
let count = 0;
75+
const { view } = await mount(() => {
76+
const button = new Button();
77+
button.text = 'Count';
78+
button.on('tap', () => (count += 1));
79+
return button;
80+
});
81+
82+
await tap(view);
83+
expect(count).toBe(1);
84+
expect(view.isLayoutValid).toBe(true);
85+
});
86+
});
1587
```
1688

17-
When using node 17 or higher, make sure your `karma.conf.js` contains a server hostname setting, for example:
89+
`mount()` attaches the view to the host page scaffolded in your `test.ts`,
90+
waits for `loaded` + a real layout pass, and auto-unmounts when the test
91+
finishes. Also available from `./testing`: `tap`, `doubleTap`, `longPress`,
92+
`enterText`, `returnPress`, `waitForLayout`, `waitUntil`, `nextRenderPass`.
93+
94+
UI specs require the main-thread context (the default). Files routed to
95+
Worker contexts must not touch Views.
1896

97+
## Coverage
98+
99+
```bash
100+
ns test ios --env.codeCoverage
101+
# or: NS_PLATFORM=ios npx vitest run --coverage
19102
```
20-
// web server hostname (ensure this is present)
21-
hostname: '127.0.0.1',
22103

23-
// web server port
24-
port: 9876,
104+
Use the `istanbul` provider — device runtimes do not expose V8 coverage:
105+
106+
```ts
107+
test: {
108+
coverage: { provider: 'istanbul', reporter: ['text', 'lcov'] },
109+
},
25110
```
26-
See [here](https://github.com/NativeScript/nativescript-cli/commit/81cb9c37cdd4e24115be79b24b68dfbaf8cdcfd2) for changeset in CLI which adds that to all newly initialized unit test setups.
111+
112+
## Devices and networking
113+
114+
| Target | Transport |
115+
| --- | --- |
116+
| iOS / visionOS simulator | host loopback (`127.0.0.1`) |
117+
| Android emulator | `10.0.2.2` → host loopback |
118+
| Physical Android | USB via automatic `adb reverse` |
119+
| Physical iOS / Apple Vision Pro | pass a LAN-reachable `url` to the coordinator in `test.ts` |
120+
121+
The host server binds `127.0.0.1` by default. Test builds on Android may need
122+
a scoped cleartext exception for `10.0.2.2`/`127.0.0.1`; on iOS and visionOS,
123+
`NSAllowsLocalNetworking`.
124+
125+
## Support matrix
126+
127+
| Feature | Status |
128+
| --- | --- |
129+
| `describe` / `it` / hooks / `expect` | ✅ |
130+
| Reporters, `vitest --ui`, JUnit output | ✅ |
131+
| Istanbul coverage | ✅ |
132+
| UI testing (`mount`, gestures) | ✅ main-thread context |
133+
| `vi.fn` / `vi.spyOn` / fake timers | 🚧 planned |
134+
| Snapshots | 🚧 planned |
135+
| Watch mode | 🚧 planned (one-shot `vitest run` today) |
136+
| `vi.mock` module mocking | ❌ not supported (webpack static bundle) — prefer DI |
137+
138+
## Credits
139+
140+
The host↔device bridge design originates from
141+
[`@cross-code/vitest-ns`](https://github.com/listepo/cross-code) by
142+
[@listepo](https://github.com/listepo) (MIT). Thank you!
143+
144+
## License
145+
146+
Apache-2.0

‎app/app-root.xml‎

Lines changed: 0 additions & 2 deletions
This file was deleted.

‎app/app.css‎

Lines changed: 0 additions & 81 deletions
This file was deleted.

‎app/app.ts‎

Lines changed: 0 additions & 3 deletions
This file was deleted.

‎app/bundle-app-root.xml‎

Lines changed: 0 additions & 2 deletions
This file was deleted.

‎app/bundle-app.ts‎

Lines changed: 0 additions & 13 deletions
This file was deleted.

‎app/bundle-main-page.ts‎

Lines changed: 0 additions & 5 deletions
This file was deleted.

‎app/bundle-main-page.xml‎

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)