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:
Rishabh Rathod 2024-05-21 15:43:07 +05:30 committed by GitHub
parent 0767a37a3a
commit 263448c84b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 120 additions and 4 deletions

View File

@ -98,15 +98,21 @@ export const addDataTreeToContext = (args: {
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 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(
entityFunctionCollection,
)) {
EVAL_CONTEXT[entityName] = Object.assign(
evalContext[entityName] = Object.assign(
{},
EVAL_CONTEXT[entityName],
evalContext[entityName],
funcObj,
);
}

View 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");
});
});

View File

@ -15,7 +15,7 @@ import type {
import { isWidget } from "@appsmith/workers/Evaluation/evaluationUtils";
import { klona } from "klona";
import { getDynamicBindings, isDynamicValue } from "utils/DynamicBindingUtils";
import evaluateSync from "../evaluate";
import evaluateSync, { setEvalContext } from "../evaluate";
import type { DescendantWidgetMap } from "sagas/WidgetOperationUtils";
import type { MetaState } from "reducers/entityReducers/metaReducer";
import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
@ -126,6 +126,14 @@ function resetWidgetMetaProperty(
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({
fullPropertyPath: `${widget.widgetName}.${defaultPropertyPath}`,
widget: unEvalEntity,