///
/**
* Test Pattern: computed() and derive() equivalence
*
* This test pattern validates that computed() and derive() are functionally
* identical by verifying they produce the same values and update in lockstep.
*
* Pattern under test: ./index.tsx
*/
import { Cell, computed, handler, pattern } from "commontools";
import TestPattern from "./index.tsx";
// 2. Define test actions at module scope (handlers with void event, hardcoded test data)
const changeFirstName = handler }>(
(_event, { firstName }) => {
firstName.set("Alice");
},
);
const changeLastName = handler }>(
(_event, { lastName }) => {
lastName.set("Smith");
},
);
const changeAge = handler }>((_event, { age }) => {
age.set(25);
});
const changeAll = handler<
void,
{ firstName: Cell; lastName: Cell; age: Cell }
>((_event, { firstName, lastName, age }) => {
firstName.set("Bob");
lastName.set("Johnson");
age.set(42);
});
const setEmptyFirstName = handler }>(
(_event, { firstName }) => {
firstName.set("");
},
);
export default pattern(() => {
// 1. Instantiate the pattern under test with initial state
const subject = TestPattern({
firstName: Cell.of("John"),
lastName: Cell.of("Doe"),
age: Cell.of(30),
});
// Bind handlers to subject cells
const action_change_firstName = changeFirstName({
firstName: subject.firstName,
});
const action_change_lastName = changeLastName({ lastName: subject.lastName });
const action_change_age = changeAge({ age: subject.age });
const action_change_all = changeAll({
firstName: subject.firstName,
lastName: subject.lastName,
age: subject.age,
});
const action_set_empty_firstName = setEmptyFirstName({
firstName: subject.firstName,
});
// 3. Define assertions as Cell
// Initial state assertion
const assert_initial_values_identical = computed(() => {
const expected = "John Doe (age 30)";
return (
subject.computedFullName === expected &&
subject.deriveFullName === expected &&
subject.deriveWithDeps === expected
);
});
// After firstName change
const assert_firstName_change_propagates = computed(() => {
const expected = "Alice Doe (age 30)";
return (
subject.computedFullName === expected &&
subject.deriveFullName === expected &&
subject.deriveWithDeps === expected
);
});
// After lastName change
const assert_lastName_change_propagates = computed(() => {
const expected = "Alice Smith (age 30)";
return (
subject.computedFullName === expected &&
subject.deriveFullName === expected &&
subject.deriveWithDeps === expected
);
});
// After age change
const assert_age_change_propagates = computed(() => {
const expected = "Alice Smith (age 25)";
return (
subject.computedFullName === expected &&
subject.deriveFullName === expected &&
subject.deriveWithDeps === expected
);
});
// After changing all values
const assert_all_changes_propagate = computed(() => {
const expected = "Bob Johnson (age 42)";
return (
subject.computedFullName === expected &&
subject.deriveFullName === expected &&
subject.deriveWithDeps === expected
);
});
// After setting empty firstName
const assert_empty_string_handled = computed(() => {
const expected = " Johnson (age 42)";
return (
subject.computedFullName === expected &&
subject.deriveFullName === expected &&
subject.deriveWithDeps === expected
);
});
// 4. Return tests array - processed sequentially
return {
tests: [
// Test 1: Initial values are identical
{ assertion: assert_initial_values_identical },
// Test 2: firstName change propagates to all three
{ action: action_change_firstName },
{ assertion: assert_firstName_change_propagates },
// Test 3: lastName change propagates to all three
{ action: action_change_lastName },
{ assertion: assert_lastName_change_propagates },
// Test 4: age change propagates to all three
{ action: action_change_age },
{ assertion: assert_age_change_propagates },
// Test 5: Multiple changes propagate
{ action: action_change_all },
{ assertion: assert_all_changes_propagate },
// Test 6: Empty string handled correctly
{ action: action_set_empty_firstName },
{ assertion: assert_empty_string_handled },
],
// Expose subject for debugging when deployed as piece
subject,
};
});