Skip to content

Commit

Permalink
Merge pull request #572 from player-ui/data-change-listener-fix
Browse files Browse the repository at this point in the history
Data change listener fix
  • Loading branch information
KetanReddy authored Feb 13, 2025
2 parents 5b1aac8 + 764dd6a commit d2cd181
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 4 deletions.
7 changes: 4 additions & 3 deletions plugins/common-expressions/core/src/expressions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ export const isNotEmpty: ExpressionHandler<[unknown], boolean> = (ctx, val) => {

export const concat = withoutContext((...args: Array<unknown>) => {
if (args.every((v) => Array.isArray(v))) {
const arrayArgs = args as Array<Array<unknown>>;
const merged: Array<unknown> = [];

return arrayArgs.reduce((merged, next) => {
args.forEach((next) => {
merged.push(...next);
return merged;
});

return merged;
}

return args.reduce((merged: any, next) => merged + (next ?? ""), "");
Expand Down
2 changes: 2 additions & 0 deletions plugins/data-change-listener/core/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ js_pipeline(
":node_modules/@player-ui/asset-transform-plugin",
":node_modules/@player-ui/common-types-plugin",
":node_modules/@player-ui/partial-match-registry",
":node_modules/@player-ui/reference-assets-plugin",
":node_modules/@player-ui/common-expressions-plugin",
"//:node_modules/@testing-library/react",
"//:vitest_config",
],
Expand Down
4 changes: 3 additions & 1 deletion plugins/data-change-listener/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"devDependencies": {
"@player-ui/partial-match-registry": "workspace:*",
"@player-ui/asset-transform-plugin": "workspace:*",
"@player-ui/common-types-plugin": "workspace:*"
"@player-ui/common-types-plugin": "workspace:*",
"@player-ui/reference-assets-plugin": "workspace:*",
"@player-ui/common-expressions-plugin": "workspace:*"
}
}
218 changes: 218 additions & 0 deletions plugins/data-change-listener/core/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { CommonTypesPlugin } from "@player-ui/common-types-plugin";
import { AssetTransformPlugin } from "@player-ui/asset-transform-plugin";
import { Registry } from "@player-ui/partial-match-registry";
import { DataChangeListenerPlugin } from "../index";
import { ReferenceAssetsPlugin } from "@player-ui/reference-assets-plugin";
import { CommonExpressionsPlugin } from "@player-ui/common-expressions-plugin";

/** Test transform function to add validation to asset */
const transform: TransformFunction = (asset: any, options: any) => {
Expand Down Expand Up @@ -431,3 +433,219 @@ describe("Data-Change-Listener that are chained", () => {
});
});
});

describe("Data-Change-Listener with array modification", () => {
let player: Player;
let testExpression: Mock<any, any>;

const flow = {
id: "action-with-expression",
views: [
{
id: "root",
type: "info",
listeners: {
"dataChange.array": ["test('array has changed ' + {{array}})"],
},
title: {
asset: {
id: "title",
type: "text",
value: "Hello",
},
},
primaryInfo: {
asset: {
id: "primaryInfo",
type: "text",
value: "Collection: [{{array}}]",
},
},
actions: [
{
asset: {
id: "action",
type: "action",
exp: "{{array}} = concat({{array}}, [4])",
label: {
asset: {
id: "actions-0-label",
type: "text",
value: "Add to collection",
},
},
},
},
],
},
],
data: {
array: [1, 2, 3],
},
navigation: {
BEGIN: "FLOW_1",
FLOW_1: {
startState: "VIEW_1",
VIEW_1: {
state_type: "VIEW",
ref: "root",
transitions: {
"*": "END_Done",
},
},
END_Done: {
state_type: "END",
outcome: "done",
},
},
},
};

const flowNum = {
id: "action-with-expression",
views: [
{
id: "root",
type: "info",
listeners: {
"dataChange.count": ["test('count has changed ' + {{count}})"],
},
title: {
asset: {
id: "title",
type: "text",
value: "Hello",
},
},
primaryInfo: {
asset: {
id: "primaryInfo",
type: "text",
value: "Count: {{count}}\\",
},
},
actions: [
{
asset: {
id: "action",
type: "action",
exp: "{{count}} = {{count}} + 1",
label: {
asset: {
id: "actions-0-label",
type: "text",
value: "Add to collection",
},
},
},
},
],
},
],
data: {
count: 0,
},
navigation: {
BEGIN: "FLOW_1",
FLOW_1: {
startState: "VIEW_1",
VIEW_1: {
state_type: "VIEW",
ref: "root",
transitions: {
"*": "END_Done",
},
},
END_Done: {
state_type: "END",
outcome: "done",
},
},
},
};

/** Helper function to get current Player state */
function getState() {
return player.getState() as InProgressState;
}

it("should call expression evaluator and data change listener when an array that is tracked changes", () => {
player = new Player({
plugins: [
new CommonTypesPlugin(),
new DataChangeListenerPlugin(),
new ReferenceAssetsPlugin(),
new CommonExpressionsPlugin(),
],
});

testExpression = vitest.fn();

player.hooks.expressionEvaluator.tap("test", (ev) => {
ev.addExpressionFunction("test", (context, ...args) => {
testExpression(...args);
});
});

player.start(flow);

const getCurrent = () => {
const status = player.getState();
if (status.status === "in-progress") {
const view = status.controllers.view.currentView?.lastUpdate;
if (view) {
return view;
}
}
};

expect(getState().controllers.data.get("array")).toStrictEqual([1, 2, 3]);

getCurrent()?.actions[0].asset.run();

expect(getState().controllers.data.get("array")).toStrictEqual([
1, 2, 3, 4,
]);

expect(testExpression).toHaveBeenCalledWith("array has changed 1,2,3,4");
});

it("should call expression evaluator and data change listener when count is changes", () => {
player = new Player({
plugins: [
new CommonTypesPlugin(),
new DataChangeListenerPlugin(),
new ReferenceAssetsPlugin(),
new CommonExpressionsPlugin(),
],
});

testExpression = vitest.fn();

player.hooks.expressionEvaluator.tap("test", (ev) => {
ev.addExpressionFunction("test", (context, ...args) => {
testExpression(...args);
});
});

player.start(flowNum);

const getCurrent = () => {
const status = player.getState();
if (status.status === "in-progress") {
const view = status.controllers.view.currentView?.lastUpdate;
if (view) {
return view;
}
}
};

expect(getState().controllers.data.get("count")).toStrictEqual(0);

getCurrent()?.actions[0].asset.run();

expect(getState().controllers.data.get("count")).toStrictEqual(1);

expect(testExpression).toHaveBeenCalledWith("count has changed 1");
});
});
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit d2cd181

Please sign in to comment.