marcs-observable
Advanced tools
Comparing version 1.0.3 to 1.0.4
{ | ||
"name": "marcs-observable", | ||
"version": "1.0.3", | ||
"version": "1.0.4", | ||
"description": "a typed version of marc grabanski's observablish-values supporting frontend masters website realtime operations", | ||
@@ -5,0 +5,0 @@ "type": "module", |
# marcs-observable | ||
[www.npmjs.com/package/marcs-observable](https://www.npmjs.com/package/marcs-observable) | ||
marcs-observable is a TypeScript library that provides a simple and efficient way to create and manage observables. An observable is a stream of values or events that other values can react to. This library allows you to create observables, subscribe to them, and publish changes to them. It also supports computed observables, which are observables that depend on other observables. | ||
@@ -4,0 +6,0 @@ |
112
test.ts
import { assertEquals } from "https://deno.land/std@0.199.0/testing/asserts.ts"; | ||
import { deferred } from "https://deno.land/std@0.199.0/async/deferred.ts"; | ||
import { ObservableFactory, Observable } from "./index.ts"; | ||
// import { ObservableFactory, Observable } from "./observable.ts"; | ||
@@ -14,11 +15,12 @@ // Publish changes to subscriber functions when values change. | ||
Deno.test("Observable publish and subscribe", () => { | ||
// observable is effectively a signal or a stream of values/events that other values can react to | ||
const observable = ObservableFactory.create(42); | ||
// trackedVal is a variable that will be updated when the observable is updated | ||
const observable = ObservableFactory.create(41); | ||
let trackedVal: number | null = null; | ||
observable.subscribe((current: number) => { | ||
console.log("Subscription callback called with value:", current); // Add this log | ||
trackedVal = current; | ||
}); | ||
console.log("Setting value to 42"); // Add this log | ||
observable.value = 42; | ||
assertEquals(trackedVal, 42); | ||
console.log("Setting value to 43"); // Add this log | ||
observable.value = 43; | ||
@@ -28,3 +30,3 @@ assertEquals(trackedVal, 43); | ||
// Requirement 2 | ||
// // Requirement 2 | ||
Deno.test("Observable publish on array replacement, not modification", () => { | ||
@@ -46,3 +48,3 @@ const observable = ObservableFactory.create([]); | ||
// Requirement 3 | ||
// // Requirement 3 | ||
Deno.test("Observable sets value with a function and arguments", () => { | ||
@@ -54,3 +56,3 @@ const func = (a: number, b: number) => a + b; | ||
// Requirement 3.5 | ||
// // Requirement 3.5 | ||
Deno.test( | ||
@@ -66,3 +68,3 @@ "Observable sets value with a function and variable number of arguments", | ||
// Requirements 4 & 5 | ||
// // Requirements 4 & 5 | ||
Deno.test("Observable recomputes value when child observables change", () => { | ||
@@ -77,3 +79,3 @@ const childObservable = ObservableFactory.create(5); | ||
// Requirement 6 | ||
// // Requirement 6 | ||
Deno.test("ObservableValue compute with async function", async () => { | ||
@@ -106,3 +108,3 @@ // Save the original delay method | ||
// Requirement 7 reassign computed observable value without affecting its internal computed dependencies calculation (setting the value won't override the computed function) | ||
// // Requirement 7 reassign computed observable value without affecting its internal computed dependencies calculation (setting the value won't override the computed function) | ||
Deno.test( | ||
@@ -116,3 +118,3 @@ "Overwrite computed observable value without changing computed function", | ||
const i = ObservableFactory.create(1); | ||
const z = ObservableFactory.create(10); | ||
const j = ObservableFactory.create(10); | ||
const func = () => { | ||
@@ -129,11 +131,93 @@ return i.value; | ||
const newFunc = () => { | ||
return z.value; | ||
return j.value; | ||
}; | ||
computed.value = newFunc(); | ||
assertEquals(computed.value, 10); | ||
z.value = 2; // no change | ||
j.value = 2; // no change | ||
assertEquals(computed.value, 10); | ||
i.value = 2; // logChanges(2,10) | ||
assertEquals(computed.value, 2); | ||
i.value = 3; // logChanges(2,10) | ||
assertEquals(computed.value, 3); | ||
} | ||
); | ||
Deno.test("cancel stale requests", async () => { | ||
// create a child promise with request delay 100ms | ||
function childFnPromise() { | ||
return Observable.delay(100).promise.then(() => 1); | ||
} | ||
function parentFn() { | ||
const childValue = child.value; | ||
if (childValue instanceof Promise) { | ||
return childValue.then((val) => val + 1); | ||
} else { | ||
return childValue + 1; | ||
} | ||
} | ||
function grandparentFn() { | ||
const parentValue = parent.value; | ||
if (parentValue instanceof Promise) { | ||
return parentValue.then((val) => val + 1); | ||
} else { | ||
return parentValue + 1; | ||
} | ||
} | ||
// init the child and computed parent observables | ||
const child = ObservableFactory.create(childFnPromise); | ||
const parent = ObservableFactory.create(parentFn); | ||
const grandparent = ObservableFactory.create(grandparentFn); | ||
// subscribe the console to the observables' updates | ||
child.subscribe((value: any) => { | ||
console.log( | ||
`child update; current value: ${JSON.stringify(value, null, 2)}` | ||
); | ||
}); | ||
parent.subscribe((value: any) => { | ||
console.log( | ||
`parent update; current value: ${JSON.stringify(value, null, 2)}` | ||
); | ||
}); | ||
grandparent.subscribe((value: any) => { | ||
console.log( | ||
`grandparent update; current value: ${JSON.stringify(value, null, 2)}` | ||
); | ||
}); | ||
// log the current values of the observables after a delay of 200ms to make sure the child promise is resolved and the parent observables have been initialized | ||
Observable.delay(200).promise.then(() => { | ||
console.log( | ||
`child.value after creation: ${JSON.stringify(child.value, null, 2)}` | ||
); | ||
}); | ||
Observable.delay(200).promise.then(() => { | ||
console.log( | ||
`parent.value after creation: ${JSON.stringify(parent.value, null, 2)}` | ||
); | ||
}); | ||
Observable.delay(200).promise.then(() => { | ||
console.log( | ||
`grandparent.value after creation: ${JSON.stringify( | ||
grandparent.value, | ||
null, | ||
2 | ||
)}` | ||
); | ||
}); | ||
// test a stale request that begins after a delay of 1000ms to allow for the creation of the observables, which resolve after some time; this first generation request (Promise) will begin first and end last (it will be stale) | ||
Observable.delay(1000).promise.then(() => { | ||
console.log( | ||
`setting child.value = 22 beginning in 1000ms and ending in 3000ms` | ||
); | ||
child.value = Observable.delay(3000).promise.then(() => 22); | ||
}); | ||
// this second Promise (request) will begin last and end first (it will invalidate the Promise with which it was running concurrently) | ||
Observable.delay(2000).promise.then(() => { | ||
console.log( | ||
`setting child.value = 3 beginning in 2000ms and ending in 10ms` | ||
); | ||
child.value = Observable.delay(10).promise.then(() => 3); | ||
}); | ||
// delay the test from completing for the duration | ||
const { promise } = Observable.delay(5000); // Adjust the delay time as needed | ||
await promise; | ||
assertEquals(grandparent.value, 5); | ||
}); |
18833
369
104