mirror of
https://github.com/re-rxjs/react-rxjs.git
synced 2025-12-08 18:01:51 +00:00
combineStates 100% covfefe
This commit is contained in:
parent
c9abc0bb6a
commit
8a3c5cb227
@ -4,6 +4,7 @@ import { substate } from "./substate"
|
||||
import { combineStates } from "./combineStates"
|
||||
import { StateNode } from "./types"
|
||||
import { routeState } from "./route-state"
|
||||
import { instanceNode } from "./test-utils/instance-node"
|
||||
|
||||
describe("combineStates", () => {
|
||||
it("combines state nodes into one", () => {
|
||||
@ -125,4 +126,159 @@ describe("combineStates", () => {
|
||||
|
||||
expect(combined.getValue({ root: "" })).toEqual({ nodeA: "a2", nodeB: "b" })
|
||||
})
|
||||
|
||||
it("combines states with keys of different lengths", () => {
|
||||
const root = createRoot()
|
||||
/** I want 3 nodes with key length 1,2,3 and pass it down in the order 1,3,2
|
||||
* And to make it more realistic, combine nodes that don't have a context relationship
|
||||
* sA1
|
||||
* r-iA1< sB2
|
||||
* iB2<
|
||||
* iC3
|
||||
* -> Combine [sA1,iC3,sB2]
|
||||
*/
|
||||
const iA1 = instanceNode(root, "a")
|
||||
const iB2 = instanceNode(iA1, "b")
|
||||
const iC3 = instanceNode(iB2, "c")
|
||||
|
||||
const sA1 = substate(iA1, (_ctx, _obs, key) => of("sA" + key.a))
|
||||
const sB2 = substate(iB2, (_ctx, _obs, key) => of("sB" + key.b))
|
||||
|
||||
const combined = combineStates({ a: sA1, c: iC3, b: sB2 })
|
||||
root.run()
|
||||
|
||||
iA1.addInstance({
|
||||
a: 1,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 1,
|
||||
b: 1,
|
||||
})
|
||||
iC3.addInstance({
|
||||
a: 1,
|
||||
b: 1,
|
||||
c: 1,
|
||||
})
|
||||
|
||||
// Adding this one but it should not exist on the combined state
|
||||
iB2.addInstance({
|
||||
a: 1,
|
||||
b: 2,
|
||||
})
|
||||
|
||||
iA1.addInstance({
|
||||
a: 2,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 2,
|
||||
b: 1,
|
||||
})
|
||||
iC3.addInstance({
|
||||
a: 2,
|
||||
b: 1,
|
||||
c: 1,
|
||||
})
|
||||
iC3.addInstance({
|
||||
a: 2,
|
||||
b: 1,
|
||||
c: 3,
|
||||
})
|
||||
|
||||
expect(combined.getValue({ a: 1, b: 1, c: 1 })).toEqual({
|
||||
a: "sA1",
|
||||
b: "sB1",
|
||||
c: 1,
|
||||
})
|
||||
expect(combined.getValue({ a: 2, b: 1, c: 1 })).toEqual({
|
||||
a: "sA2",
|
||||
b: "sB1",
|
||||
c: 1,
|
||||
})
|
||||
expect(combined.getValue({ a: 2, b: 1, c: 3 })).toEqual({
|
||||
a: "sA2",
|
||||
b: "sB1",
|
||||
c: 3,
|
||||
})
|
||||
expect(() => combined.getValue({ a: 1, b: 2, c: 1 })).toThrow()
|
||||
expect(() => combined.getValue({ a: 2, b: 2, c: 1 })).toThrow()
|
||||
expect(() => combined.getValue({ a: 2, b: 2, c: 3 })).toThrow()
|
||||
})
|
||||
|
||||
it("removes instances when they are removed", () => {
|
||||
const root = createRoot()
|
||||
const iA1 = instanceNode(root, "a")
|
||||
const iB2 = instanceNode(iA1, "b")
|
||||
|
||||
const combined = combineStates({ a: iA1, b: iB2 })
|
||||
root.run()
|
||||
|
||||
iA1.addInstance({
|
||||
a: 1,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 1,
|
||||
b: 1,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 1,
|
||||
b: 2,
|
||||
})
|
||||
|
||||
iA1.addInstance({
|
||||
a: 2,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 2,
|
||||
b: 1,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 2,
|
||||
b: 2,
|
||||
})
|
||||
|
||||
expect(combined.getValue({ a: 1, b: 1 })).toEqual({
|
||||
a: 1,
|
||||
b: 1,
|
||||
})
|
||||
expect(combined.getValue({ a: 1, b: 2 })).toEqual({
|
||||
a: 1,
|
||||
b: 2,
|
||||
})
|
||||
|
||||
iA1.removeInstance({
|
||||
a: 1,
|
||||
})
|
||||
|
||||
expect(() => combined.getValue({ a: 1, b: 1 })).toThrow()
|
||||
expect(() => combined.getValue({ a: 1, b: 2 })).toThrow()
|
||||
expect(combined.getValue({ a: 2, b: 1 })).toEqual({
|
||||
a: 2,
|
||||
b: 1,
|
||||
})
|
||||
expect(combined.getValue({ a: 2, b: 2 })).toEqual({
|
||||
a: 2,
|
||||
b: 2,
|
||||
})
|
||||
})
|
||||
|
||||
it("combines states when it's declared after having instances already in running", () => {
|
||||
const root = createRoot()
|
||||
const iA1 = instanceNode(root, "a")
|
||||
const iB2 = instanceNode(iA1, "b")
|
||||
root.run()
|
||||
|
||||
iA1.addInstance({
|
||||
a: 1,
|
||||
})
|
||||
iB2.addInstance({
|
||||
a: 1,
|
||||
b: 1,
|
||||
})
|
||||
const combined = combineStates({ a: iA1, b: iB2 })
|
||||
|
||||
expect(combined.getValue({ a: 1, b: 1 })).toEqual({
|
||||
a: 1,
|
||||
b: 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -50,9 +50,8 @@ export const combineStates = <
|
||||
),
|
||||
)
|
||||
) {
|
||||
const key = keysOrder.map((k) => instance.key[k])
|
||||
result.addInstance(key)
|
||||
toActivate.push(key)
|
||||
result.addInstance(instance.key)
|
||||
toActivate.push(instance.key)
|
||||
}
|
||||
}
|
||||
for (let key of toActivate) {
|
||||
@ -65,7 +64,7 @@ export const combineStates = <
|
||||
keysToRemove.push(instance.key)
|
||||
}
|
||||
for (let key of keysToRemove) {
|
||||
result.removeInstance(keysOrder.map((k) => key[k]))
|
||||
result.removeInstance(key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +84,7 @@ export const combineStates = <
|
||||
)
|
||||
addInstances(
|
||||
keysOrder.map((k) =>
|
||||
k in node.keysOrder ? change.key[k] : Wildcard,
|
||||
node.keysOrder.includes(k) ? change.key[k] : Wildcard,
|
||||
),
|
||||
)
|
||||
} else if (change.type === "removed") {
|
||||
@ -95,7 +94,7 @@ export const combineStates = <
|
||||
)
|
||||
removeInstances(
|
||||
keysOrder.map((k) =>
|
||||
k in node.keysOrder ? change.key[k] : Wildcard,
|
||||
node.keysOrder.includes(k) ? change.key[k] : Wildcard,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
28
packages/context-state2/src/test-utils/instance-node.ts
Normal file
28
packages/context-state2/src/test-utils/instance-node.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { of } from "rxjs"
|
||||
import { InternalStateNode, createStateNode, getInternals } from "../internal"
|
||||
import { KeysBaseType, StateNode } from "../types"
|
||||
|
||||
export function instanceNode<T, K extends KeysBaseType, KN extends string>(
|
||||
parent: StateNode<T, K>,
|
||||
keyName: KN,
|
||||
) {
|
||||
type MergedKey = {
|
||||
[key in keyof (K & Record<KN, any>)]: (K & Record<KN, any>)[key]
|
||||
}
|
||||
const parentInternals = getInternals(parent)
|
||||
const result: InternalStateNode<any, MergedKey> = createStateNode(
|
||||
[...parentInternals.keysOrder, keyName],
|
||||
[parentInternals],
|
||||
(_ctx, _obs, key) => of(key[keyName]),
|
||||
)
|
||||
|
||||
return Object.assign(result.public, {
|
||||
addInstance(key: MergedKey) {
|
||||
result.addInstance(key)
|
||||
result.activateInstance(key)
|
||||
},
|
||||
removeInstance(key: MergedKey) {
|
||||
result.removeInstance(key)
|
||||
},
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user