UNPKG

@player-ui/player

Version:

154 lines (136 loc) 4.68 kB
import { describe, it, beforeEach, vi, expect } from "vitest"; import { BindingParser } from "../../../binding"; import { ExpressionEvaluator } from "../../../expressions"; import { LocalModel, withParser } from "../../../data"; import { SchemaController } from "../../../schema"; import { Resolve, Resolver } from ".."; import type { Node } from "../../parser"; import { NodeType, Parser } from "../../parser"; const simpleViewWithAsync: Node.View = { type: NodeType.View, children: [ { path: ["value"], value: { type: NodeType.Async, id: "async-node", value: { type: NodeType.Value, value: { id: "async-node", }, }, }, }, { path: ["value"], value: { type: NodeType.Value, value: { id: "value-node", }, }, }, ], value: { type: "view", id: "view", }, }; describe("Async Node Resolution", () => { let resolverOptions: Resolve.ResolverOptions; beforeEach(() => { const model = new LocalModel({}); const parser = new Parser(); const bindingParser = new BindingParser(); resolverOptions = { model, parseBinding: bindingParser.parse.bind(bindingParser), parseNode: parser.parseObject.bind(parser), evaluator: new ExpressionEvaluator({ model: withParser(model, bindingParser.parse), }), schema: new SchemaController(), }; }); it("should clear the cache for the async node and its parent when it is updated", () => { const beforeResolveFunction = vi.fn((node: Node.Node | null) => node); const resolver = new Resolver(simpleViewWithAsync, resolverOptions); resolver.hooks.beforeResolve.tap("test", beforeResolveFunction); // Update once to setup cache resolver.update(); // Should call beforeResolve once for each node. expect(beforeResolveFunction).toHaveBeenCalledTimes(3); // Clear call information before next update. beforeResolveFunction.mockClear(); // Confirm cache by running another update with no changes. resolver.update(new Set()); // Should not need to call before resolve on cached nodes. expect(beforeResolveFunction).toHaveBeenCalledTimes(0); // Updating with changes marked on "async-node". Should invalidate cache for itself and its parent. resolver.update(new Set(), new Set(["async-node"])); // Should be called for the async node and the view parent. expect(beforeResolveFunction).toHaveBeenCalledTimes(2); expect(beforeResolveFunction).toHaveBeenCalledWith( expect.objectContaining({ type: NodeType.View, value: { type: "view", id: "view", }, }), expect.anything(), ); expect(beforeResolveFunction).toHaveBeenCalledWith( expect.objectContaining({ type: NodeType.Async, id: "async-node", value: { type: NodeType.Value, value: { id: "async-node", }, }, }), expect.anything(), ); }); it("should clear the cache for anything with a matching async node in its resolved list on update", () => { const beforeResolveFunction = vi.fn((node: Node.Node | null) => { // Add asyncNodesResolved to view to test tracking and invalidation of just the view. if (node?.type === NodeType.View) { return { ...node, asyncNodesResolved: ["other-async-id"], }; } return node; }); const resolver = new Resolver(simpleViewWithAsync, resolverOptions); resolver.hooks.beforeResolve.tap("test", beforeResolveFunction); // Update once to setup cache resolver.update(); // Should call beforeResolve once for each node. expect(beforeResolveFunction).toHaveBeenCalledTimes(3); // Clear call information before next update. beforeResolveFunction.mockClear(); // Confirm cache by running another update with no changes. resolver.update(new Set()); // Should not need to call before resolve on cached nodes. expect(beforeResolveFunction).toHaveBeenCalledTimes(0); // Updating with changes marked on "async-node". Should invalidate cache for itself and its parent. resolver.update(new Set(), new Set(["other-async-id"])); // Should be called just for the view. expect(beforeResolveFunction).toHaveBeenCalledOnce(); expect(beforeResolveFunction).toHaveBeenCalledWith( expect.objectContaining({ type: NodeType.View, value: { type: "view", id: "view", }, }), expect.anything(), ); }); });