Skip to content

Commit

Permalink
Uses new deep clone library (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
tamb authored Feb 18, 2024
1 parent 0474203 commit 5686e34
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 117 deletions.
80 changes: 63 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "substate",
"version": "9.0.0-alpha.1",
"version": "9.0.0-alpha.2",
"description": "Simple State Management with Optional Deep Cloning",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -12,7 +12,7 @@
"scripts": {
"test": "jest",
"build": "rollup -c",
"test.dev": "jest --watch",
"test.watch": "jest --watch",
"pre": "npm test && npm run build && npm publish --tag next",
"safe-publish": "npm test && npm run build && npm publish"
},
Expand All @@ -32,8 +32,8 @@
"license": "MIT",
"devDependencies": {
"@babel/preset-env": "^7.10.2",
"@types/clone-deep": "^4.0.4",
"@types/jest": "^29.5.12",
"@types/rfdc": "^1.1.0",
"husky": "^4.2.5",
"jest": "^29.7.0",
"prettier": "^2.0.5",
Expand All @@ -47,8 +47,8 @@
"typescript": "^5.3.3"
},
"dependencies": {
"object-bystring": "^5.0.1",
"rfdc": "^1.3.1"
"clone-deep": "^4.0.1",
"object-bystring": "^6.0.1"
},
"husky": {
"hooks": {
Expand Down
182 changes: 120 additions & 62 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
//FizzBuzz.test.ts
/// <reference types="jest" />
import substate from "./index";

const func1 = jest.fn((x) => {
x.count ? (x.count = ++x.count) : (x.count = 1);
});
const func2 = jest.fn((x) => {
x.count2 ? ++x.count2 : (x.count2 = 1);
});
import Substate, { ISubstate } from "./index";

const STATE = {
name: "Thomas",
Expand All @@ -19,70 +12,135 @@ const STATE = {
},
};

const A = new substate({
name: "HamburgerStore",
defaultDeep: true,
state: STATE,
beforeUpdate: [func1],
afterUpdate: [func2],
});
let A: ISubstate;
let func1: jest.Mock;
let func2: jest.Mock;
let func3: jest.Mock;
let func4: jest.Mock;

/** initialization tests */
test("creates new instance of substate", () => {
expect(A instanceof substate).toBe(true);
});
describe("Substate instantiation", () => {
beforeEach(() => {
func1 = jest.fn();
func2 = jest.fn();
func3 = jest.fn();
func4 = jest.fn();

test("expects store to have name", () => {
expect(A.name).toBe("HamburgerStore");
});
A = new Substate({
name: "HamburgerStore",
defaultDeep: true,
state: STATE,
beforeUpdate: [func1, func3],
afterUpdate: [func2, func4],
});
});
test("creates new instance of substate", () => {
expect(A instanceof Substate).toBe(true);
});

test("events to contain UPDATE_STATE on initialization", () => {
expect(A.events.UPDATE_STATE).toHaveLength(1);
});
test("expects store to have name", () => {
expect(A.name).toBe("HamburgerStore");
});

test("get props to return correct value", () => {
expect(A.getProp("nested.double.reason")).toBe("Just the start");
test("events to contain UPDATE_STATE on initialization", () => {
expect(A.events.UPDATE_STATE).toHaveLength(1);
});
});

test("getCurrentState returns current state and fires middleware", () => {
expect(A.getCurrentState()).toMatchObject(STATE);
A.emit("UPDATE_STATE", { timeOfFun: new Date().toISOString() });
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(1);
});
describe("Substate getters", () => {
beforeEach(() => {
func1 = jest.fn();
func2 = jest.fn();
func3 = jest.fn();
func4 = jest.fn();

test("getState returns correct state from array", () => {
expect(A.getState(0)).toMatchObject(STATE);
});
A = new Substate({
name: "HamburgerStore",
defaultDeep: true,
state: STATE,
beforeUpdate: [func1, func3],
afterUpdate: [func2, func4],
});
});

test("deep clone works and does not alter older nested state", () => {
const NEWTEXT = "This has changed";
A.emit("UPDATE_STATE", { "nested.double.reason": NEWTEXT });
expect(func1).toHaveBeenCalledTimes(2);
expect(func2).toHaveBeenCalledTimes(2);
expect(A.getState(0)).not.toBe(NEWTEXT);
});
test("get props to return correct value", () => {
expect(A.getProp("nested.double.reason")).toBe("Just the start");
});

// FIXME: This test is not working as expected
test("updateState updates state and fires middleware", () => {
const NEWTEXT = "This has changed";
A.updateState({ "nested.double.reason": NEWTEXT });
expect(func1).toHaveBeenCalledTimes(3);
expect(func2).toHaveBeenCalledTimes(3);
});
test("getCurrentState returns current state and fires middleware", () => {
expect(A.getCurrentState()).toMatchObject(STATE);
A.emit("UPDATE_STATE", { timeOfFun: new Date().toISOString() });
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(1);
expect(func3).toHaveBeenCalledTimes(1);
expect(func4).toHaveBeenCalledTimes(1);
});

test("callback fires for custom $type", () => {
const myMock = jest.fn();
const DATEUPDATED = "DATE_UPDATED";
A.on(DATEUPDATED, myMock);
A.emit("UPDATE_STATE", { timeOfFun: new Date(), $type: DATEUPDATED });
expect(myMock).toHaveBeenCalled();
test("getState returns correct state from array", () => {
expect(A.getState(0)).toMatchObject(STATE);
});
});

test("callback for custom $type contains correct $type value", () => {
const myMock = jest.fn();
const DATEUPDATED = "DATE_UPDATED";
A.on(DATEUPDATED, myMock);
A.emit("UPDATE_STATE", { timeOfFun: new Date(), $type: DATEUPDATED });
expect(A.getProp("$type")).toBe(DATEUPDATED);
describe("Substate state management", () => {
beforeEach(() => {
func1 = jest.fn();
func2 = jest.fn();
func3 = jest.fn();
func4 = jest.fn();

A = new Substate({
name: "HamburgerStore",
defaultDeep: true,
state: STATE,
beforeUpdate: [func1, func3],
afterUpdate: [func2, func4],
});
});

test("deep clone does not alter older nested state", () => {
const NEWTEXT = "This has changed";
A.emit("UPDATE_STATE", { "nested.double.reason": NEWTEXT });
expect(A.getState(0)).not.toMatchObject(A.getCurrentState());
expect(A.getState(0)).not.toMatchObject(A.getCurrentState());
});

test("update via string notation works", () => {
const NEWTEXT = "This has changed";
A.emit("UPDATE_STATE", { "nested.double": NEWTEXT });
expect(A.getProp("nested.double")).toMatch(NEWTEXT);
});

test("updateState updates state updates nested string", () => {
const NEWTEXT = "foobar";
A.updateState({ "nested.double": NEWTEXT });
expect(A.getCurrentState().nested.double).toBe(NEWTEXT);
});

test("updateState fires middleware", () => {
const NEWTEXT = "foobar";
A.updateState({ "nested.double": NEWTEXT });
expect(func1).toHaveBeenCalledTimes(1);
expect(func2).toHaveBeenCalledTimes(1);
expect(func3).toHaveBeenCalledTimes(1);
expect(func4).toHaveBeenCalledTimes(1);
});

test("callback fires for custom $type", () => {
const myMock = jest.fn();
const DATEUPDATED = "DATE_UPDATED";
A.on(DATEUPDATED, myMock);
A.emit("UPDATE_STATE", { timeOfFun: new Date(), $type: DATEUPDATED });
expect(myMock).toHaveBeenCalled();
});

test("UPDATE_STATE emit sets $type", () => {
const DATEUPDATED = "DATE_UPDATED";
A.emit("UPDATE_STATE", { timeOfFun: new Date(), $type: DATEUPDATED });
expect(A.getProp("$type")).toMatch(DATEUPDATED);
});

test("Update state sets $type value", () => {
const DATEUPDATED = "DATE_UPDATED";
A.updateState({ timeOfFun: new Date(), $type: DATEUPDATED });
expect(A.getProp("$type")).toMatch(DATEUPDATED);
});
});
Loading

0 comments on commit 5686e34

Please sign in to comment.