.agent/skills/refactor/references/WritingUnitTests.md
Unit tests are standard *.spec.ts files colocated with the source they cover, throughout the packages in this workspace (e.g. packages/core/xml/index.spec.ts next to packages/core/xml/index.ts). They are written with Vitest and run per package through Nx.
Refer to the development-workflow guide for repo setup. Then run a package's test target:
npx nx run core:test
# watch mode
npx nx run core:test --watch
# isolate tests by describe/it name
npx nx run core:test -t 'XmlParser'
Packages with a test target (such as core and vite) each define their Vitest configuration in their own vite.config.ts / vitest.config.ts.
Use the standard Vitest API — describe, it/test, expect, beforeEach, vi for mocking. Globals are enabled, so imports from vitest are optional:
import { Observable } from '.';
describe('Observable', () => {
it('notifies a listener once', () => {
const observable = new Observable();
let callCount = 0;
observable.once('test', () => callCount++);
observable.notify({ eventName: 'test', object: observable });
observable.notify({ eventName: 'test', object: observable });
expect(callCount).toBe(1);
});
});
Async tests are plain async functions — return or await your promises and assert on the results.
Tests run in Node, not on a device. packages/core/vitest.setup.ts stubs the NativeScript platform globals (__IOS__, __ANDROID__, __UNIT_TEST__, minimal NSObject-style mocks, etc.) so core modules can load, but real iOS/Android APIs are not available. If your test needs more of the native surface, extend the mocks in that setup file.
Behavior that depends on the actual native runtime belongs in the e2e suite instead — see the apps/automated app and the development-workflow guide.