diff --git a/CHANGELOG.md b/CHANGELOG.md index 303b729..27947cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [v1.0.1] - 2026-03-11 + +### Added +- Add tests + ## [v1.0.0] - 2026-03-11 Initial Release diff --git a/README.md b/README.md index dd63e84..8a3192f 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ npm install @aegisjsproject/iota ``` diff --git a/iota.test.js b/iota.test.js new file mode 100644 index 0000000..d7e31a7 --- /dev/null +++ b/iota.test.js @@ -0,0 +1,100 @@ +import '@shgysk8zer0/polyfills'; +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { + getRef, + RegistryKey, + hasSignalRef, + getSignalFromRef, + unregisterSignal, + $signal, + $computed, + $watch, + $unwatch +} from '@aegisjsproject/iota'; + +test('RegistryKey generation and disposal', () => { + const key = getRef('test'); + assert.ok(key instanceof RegistryKey); + assert.match(key.toString(), /^test-\d+-[0-9a-f]+$/); + assert.equal(key.disposed, false); + + key[Symbol.dispose](); + assert.equal(key.disposed, true); +}); + +test('Signal Registry operations', () => { + const state = $signal(10); + const ref = state.ref; + + assert.equal(hasSignalRef(ref), true); + assert.equal(getSignalFromRef(ref), state); + + unregisterSignal(ref); + assert.equal(hasSignalRef(ref), false); + assert.equal(getSignalFromRef(ref), undefined); +}); + +test('$signal (DisposableState) value tracking and disposal', () => { + const count = $signal(0); + assert.equal(count.get(), 0); + + count.set(5); + assert.equal(count.get(), 5); + + const ref = count.ref; + assert.equal(hasSignalRef(ref), true); + + count[Symbol.dispose](); + assert.equal(count.disposed, true); + assert.equal(hasSignalRef(ref), false); // Disposal should trigger unregister +}); + +test('$computed (DisposableComputed) reactivity and disposal', () => { + const base = $signal(5); + const square = $computed(() => base.get() ** 2); + + assert.equal(square.get(), 25); + + base.set(10); + assert.equal(square.get(), 100); + + const ref = square.ref; + assert.equal(hasSignalRef(ref), true); + + square[Symbol.dispose](); + assert.equal(square.disposed, true); + assert.equal(hasSignalRef(ref), false); +}); + +test('$watch and $unwatch microtask batching', async () => { + const text = $signal('a'); + let watcherRuns = 0; + let lastValue = null; + + const callback = (val) => { + watcherRuns++; + lastValue = val; + }; + + $watch(text, callback); + + // Trigger multiple synchronous updates + text.set('b'); + text.set('c'); + text.set('d'); + + // Yield to event loop to allow queueMicrotask to process + await new Promise(resolve => setTimeout(resolve, 0)); + + assert.equal(lastValue, 'd'); + assert.equal(watcherRuns, 1); // Batched into a single run + + $unwatch(text); + + text.set('e'); + await new Promise(resolve => setTimeout(resolve, 0)); + + assert.equal(lastValue, 'd'); // Should not have updated + assert.equal(watcherRuns, 1); +}); diff --git a/package-lock.json b/package-lock.json index 758c7b0..d69ff71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "npm-template", - "version": "1.1.3", + "name": "@aegisjsproject/iota", + "version": "1.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "npm-template", - "version": "1.1.3", + "name": "@aegisjsproject/iota", + "version": "1.0.1", "funding": [ { "type": "librepay", @@ -18,6 +18,9 @@ } ], "license": "MIT", + "dependencies": { + "@shgysk8zer0/signals": "^0.0.3" + }, "devDependencies": { "@aegisjsproject/dev-server": "^1.0.6", "@aegisjsproject/http-utils": "^1.0.4", @@ -25,7 +28,6 @@ "@shgysk8zer0/eslint-config": "^1.0.7", "@shgysk8zer0/http-server": "^1.1.1", "@shgysk8zer0/importmap": "^1.8.1", - "@shgysk8zer0/signals": "^0.0.3", "eslint": "^10.0.3", "rollup": "^4.59.0" }, @@ -950,7 +952,6 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/@shgysk8zer0/signals/-/signals-0.0.3.tgz", "integrity": "sha512-mUSWKyZILwAoVIhwjM/QGVYfihEZgepO6TUV2BtOlHLqXkwhUMirEMDNOER/mkc+JnhpVDa0luiqbxpo+ZVG0g==", - "dev": true, "funding": [ { "type": "librepay", @@ -2378,8 +2379,7 @@ "@shgysk8zer0/signals": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@shgysk8zer0/signals/-/signals-0.0.3.tgz", - "integrity": "sha512-mUSWKyZILwAoVIhwjM/QGVYfihEZgepO6TUV2BtOlHLqXkwhUMirEMDNOER/mkc+JnhpVDa0luiqbxpo+ZVG0g==", - "dev": true + "integrity": "sha512-mUSWKyZILwAoVIhwjM/QGVYfihEZgepO6TUV2BtOlHLqXkwhUMirEMDNOER/mkc+JnhpVDa0luiqbxpo+ZVG0g==" }, "@types/esrecurse": { "version": "4.3.1", diff --git a/package.json b/package.json index f2a6ed8..5179711 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aegisjsproject/iota", - "version": "1.0.0", + "version": "1.0.1", "description": "A Signals-based reactivity library", "keywords": [ "signals", diff --git a/refs.js b/refs.js index f64df0a..34fcd42 100644 --- a/refs.js +++ b/refs.js @@ -4,7 +4,7 @@ export class RegistryKey extends String { #stack = new DisposableStack(); get disposed() { - return this.#stack.diposed; + return this.#stack.disposed; } adopt(what, onDiposed) {