fix: function undefined error after resetWidget is called due to sync… (#33600)
## Description Fixed the error of async function like `Api.run` being `undefined` after running `resetWidget`. #### Context:- we have 2 types of evaluation i.e., sync and async evaluation. These are dependent on the field we are evaluating, for the data field we use sync evaluation and for the trigger field, we use async evaluation. In Async evaluation, we also define entity functions like `Api.run`. - In resetWidget code, internally we were switching to sync evaluation and we forgot to add code to switch back to async and due to this code that was after it was throwing an `undefined` error. Fixes https://github.com/appsmithorg/appsmith/issues/33601 ### Steps to reproduce 1. Import user’s application ( shared on slack ) 2. Go to JSObj_Main JSObject 3. Check the onClickCopySheetTemplate function 4. Comment the await Qry_C_CopySheetTemplate.run(); line and run the function. 5. On release it will throw error for Qry_R_SheetTemplate.run(); not being defined but will work fine on DP. ## Automation /ok-to-test tags="@tag.JS" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/9170093222> > Commit: f9e8893d12cedbd9d2368cd9609bda7b86816588 > Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9170093222&attempt=1" target="_blank">Click here!</a> <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No
This commit is contained in:
parent
0767a37a3a
commit
263448c84b
|
|
@ -98,15 +98,21 @@ export const addDataTreeToContext = (args: {
|
||||||
EVAL_CONTEXT,
|
EVAL_CONTEXT,
|
||||||
);
|
);
|
||||||
|
|
||||||
// if eval is not trigger based i.e., sync eval then we skip adding entity and platform function to evalContext
|
|
||||||
if (!isTriggerBased) return;
|
if (!isTriggerBased) return;
|
||||||
|
// if eval is not trigger based i.e., sync eval then we skip adding entity function to evalContext
|
||||||
|
addEntityFunctionsToEvalContext(EVAL_CONTEXT, entityFunctionCollection);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const addEntityFunctionsToEvalContext = (
|
||||||
|
evalContext: EvalContext,
|
||||||
|
entityFunctionCollection: Record<string, Record<string, Function>>,
|
||||||
|
) => {
|
||||||
for (const [entityName, funcObj] of Object.entries(
|
for (const [entityName, funcObj] of Object.entries(
|
||||||
entityFunctionCollection,
|
entityFunctionCollection,
|
||||||
)) {
|
)) {
|
||||||
EVAL_CONTEXT[entityName] = Object.assign(
|
evalContext[entityName] = Object.assign(
|
||||||
{},
|
{},
|
||||||
EVAL_CONTEXT[entityName],
|
evalContext[entityName],
|
||||||
funcObj,
|
funcObj,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
102
app/client/src/workers/Evaluation/fns/__tests__/index.test.ts
Normal file
102
app/client/src/workers/Evaluation/fns/__tests__/index.test.ts
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { MAIN_THREAD_ACTION } from "@appsmith/workers/Evaluation/evalWorkerActions";
|
||||||
|
import { addPlatformFunctionsToEvalContext } from "@appsmith/workers/Evaluation/Actions";
|
||||||
|
import { setEvalContext } from "workers/Evaluation/evaluate";
|
||||||
|
import type { DataTree } from "entities/DataTree/dataTreeTypes";
|
||||||
|
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
||||||
|
import { RenderModes } from "constants/WidgetConstants";
|
||||||
|
|
||||||
|
const dataTree: DataTree = {
|
||||||
|
action1: {
|
||||||
|
actionId: "123",
|
||||||
|
data: {},
|
||||||
|
config: {},
|
||||||
|
datasourceUrl: "",
|
||||||
|
isLoading: false,
|
||||||
|
run: {},
|
||||||
|
clear: {},
|
||||||
|
responseMeta: { isExecutionSuccess: false },
|
||||||
|
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||||
|
},
|
||||||
|
WidgetName: {
|
||||||
|
widgetName: "WidgetName",
|
||||||
|
bottomRow: 0,
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: 0,
|
||||||
|
topRow: 0,
|
||||||
|
type: "TABLE_WIDGET",
|
||||||
|
version: 1,
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||||
|
meta: {},
|
||||||
|
widgetId: "sfwe",
|
||||||
|
renderMode: RenderModes.CANVAS,
|
||||||
|
parentColumnSpace: 3,
|
||||||
|
parentRowSpace: 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock("workers/Evaluation/handlers/evalTree", () => ({
|
||||||
|
get dataTreeEvaluator() {
|
||||||
|
return {
|
||||||
|
evalTree: dataTree,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const requestMock = jest.fn();
|
||||||
|
jest.mock("../utils/Messenger.ts", () => ({
|
||||||
|
...jest.requireActual("../utils/Messenger.ts"),
|
||||||
|
get WorkerMessenger() {
|
||||||
|
return {
|
||||||
|
request: (...args: any) => requestMock(...args),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("Tests for entity function to be defined", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
self["$isDataField"] = false;
|
||||||
|
setEvalContext({
|
||||||
|
dataTree: dataTree,
|
||||||
|
isTriggerBased: true,
|
||||||
|
isDataField: false,
|
||||||
|
});
|
||||||
|
addPlatformFunctionsToEvalContext(self);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("1. After resetWidget is executed", async () => {
|
||||||
|
requestMock.mockReturnValue(
|
||||||
|
Promise.resolve({
|
||||||
|
data: ["resolved"],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const evalContext = globalThis as any;
|
||||||
|
evalContext.resetWidget("WidgetName", true);
|
||||||
|
|
||||||
|
const successHandler = jest.fn();
|
||||||
|
const invocation = evalContext.action1.run();
|
||||||
|
invocation.then(successHandler);
|
||||||
|
expect(requestMock).toBeCalledWith({
|
||||||
|
method: MAIN_THREAD_ACTION.PROCESS_TRIGGER,
|
||||||
|
data: {
|
||||||
|
enableJSFnPostProcessors: true,
|
||||||
|
enableJSVarUpdateTracking: true,
|
||||||
|
trigger: {
|
||||||
|
type: "RUN_PLUGIN_ACTION",
|
||||||
|
payload: {
|
||||||
|
actionId: "123",
|
||||||
|
params: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
triggerMeta: {
|
||||||
|
source: {},
|
||||||
|
triggerPropertyName: undefined,
|
||||||
|
onPageLoad: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await expect(invocation).resolves.toEqual("resolved");
|
||||||
|
expect(successHandler).toBeCalledWith("resolved");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -15,7 +15,7 @@ import type {
|
||||||
import { isWidget } from "@appsmith/workers/Evaluation/evaluationUtils";
|
import { isWidget } from "@appsmith/workers/Evaluation/evaluationUtils";
|
||||||
import { klona } from "klona";
|
import { klona } from "klona";
|
||||||
import { getDynamicBindings, isDynamicValue } from "utils/DynamicBindingUtils";
|
import { getDynamicBindings, isDynamicValue } from "utils/DynamicBindingUtils";
|
||||||
import evaluateSync from "../evaluate";
|
import evaluateSync, { setEvalContext } from "../evaluate";
|
||||||
import type { DescendantWidgetMap } from "sagas/WidgetOperationUtils";
|
import type { DescendantWidgetMap } from "sagas/WidgetOperationUtils";
|
||||||
import type { MetaState } from "reducers/entityReducers/metaReducer";
|
import type { MetaState } from "reducers/entityReducers/metaReducer";
|
||||||
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||||
|
|
@ -126,6 +126,14 @@ function resetWidgetMetaProperty(
|
||||||
finalValue = klona(expressionToEvaluate);
|
finalValue = klona(expressionToEvaluate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Switch back to async evaluation once done with sync tasks.
|
||||||
|
setEvalContext({
|
||||||
|
dataTree: evalTree,
|
||||||
|
configTree: dataTreeEvaluator.getConfigTree(),
|
||||||
|
isDataField: false,
|
||||||
|
isTriggerBased: true,
|
||||||
|
});
|
||||||
|
|
||||||
const parsedValue = validateAndParseWidgetProperty({
|
const parsedValue = validateAndParseWidgetProperty({
|
||||||
fullPropertyPath: `${widget.widgetName}.${defaultPropertyPath}`,
|
fullPropertyPath: `${widget.widgetName}.${defaultPropertyPath}`,
|
||||||
widget: unEvalEntity,
|
widget: unEvalEntity,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user