PromucFlow_constructor/app/client/src/utils/WidgetLoadingStateUtils.test.ts

523 lines
15 KiB
TypeScript
Raw Normal View History

import { PluginType } from "entities/Action";
fix: Improving performance of JS evaluations by splitting the data tree (#21547) ## Description This is the second phase of the split data tree. In the previous version, we collected all config paths in each entity and put them in the `__config__` property. All those config properties do get inserted into final data tree which we don't need at all. As part of this change, we will be creating another tree i.e **'configTree'** which will contain all config of each entity. unEvalTree is split into 2 trees => 1. unEvalTree 2. configTree Example: previous unEvalTree Api1 content <img width="1766" alt="image" src="https://user-images.githubusercontent.com/7846888/215990868-0b095421-e7b8-44bc-89aa-065b35e237d6.png"> After this change unEvalTree Api1 content <img width="1758" alt="image" src="https://user-images.githubusercontent.com/7846888/215991045-506fb10a-645a-4aad-8e77-0f3786a86977.png"> Note- above example doesn't have '__config__' property configTree Api1 content <img width="1760" alt="image" src="https://user-images.githubusercontent.com/7846888/215991169-a2e03443-5d6a-4ff1-97c5-a12593e46395.png"> ## Type of change - Chore (housekeeping or task changes that don't impact user perception) - #11351 ## How Has This Been Tested? - Manual - Jest - Cypress ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-03-20 11:04:02 +00:00
import type { WidgetEntity } from "entities/DataTree/dataTreeFactory";
import type { ActionEntity, JSActionEntity } from "entities/DataTree/types";
chore: upgrade to prettier v2 + enforce import types (#21013)Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com> ## Description This PR upgrades Prettier to v2 + enforces TypeScript’s [`import type`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export) syntax where applicable. It’s submitted as a separate PR so we can merge it easily. As a part of this PR, we reformat the codebase heavily: - add `import type` everywhere where it’s required, and - re-format the code to account for Prettier 2’s breaking changes: https://prettier.io/blog/2020/03/21/2.0.0.html#breaking-changes This PR is submitted against `release` to make sure all new code by team members will adhere to new formatting standards, and we’ll have fewer conflicts when merging `bundle-optimizations` into `release`. (I’ll merge `release` back into `bundle-optimizations` once this PR is merged.) ### Why is this needed? This PR is needed because, for the Lodash optimization from https://github.com/appsmithorg/appsmith/commit/7cbb12af886621256224be0c93e6a465dd710ad3, we need to use `import type`. Otherwise, `babel-plugin-lodash` complains that `LoDashStatic` is not a lodash function. However, just using `import type` in the current codebase will give you this: <img width="962" alt="Screenshot 2023-03-08 at 17 45 59" src="https://user-images.githubusercontent.com/2953267/223775744-407afa0c-e8b9-44a1-90f9-b879348da57f.png"> That’s because Prettier 1 can’t parse `import type` at all. To parse it, we need to upgrade to Prettier 2. ### Why enforce `import type`? Apart from just enabling `import type` support, this PR enforces specifying `import type` everywhere it’s needed. (Developers will get immediate TypeScript and ESLint errors when they forget to do so.) I’m doing this because I believe `import type` improves DX and makes refactorings easier. Let’s say you had a few imports like below. Can you tell which of these imports will increase the bundle size? (Tip: it’s not all of them!) ```ts // app/client/src/workers/Linting/utils.ts import { Position } from "codemirror"; import { LintError as JSHintError, LintOptions } from "jshint"; import { get, isEmpty, isNumber, keys, last, set } from "lodash"; ``` It’s pretty hard, right? What about now? ```ts // app/client/src/workers/Linting/utils.ts import type { Position } from "codemirror"; import type { LintError as JSHintError, LintOptions } from "jshint"; import { get, isEmpty, isNumber, keys, last, set } from "lodash"; ``` Now, it’s clear that only `lodash` will be bundled. This helps developers to see which imports are problematic, but it _also_ helps with refactorings. Now, if you want to see where `codemirror` is bundled, you can just grep for `import \{.*\} from "codemirror"` – and you won’t get any type-only imports. This also helps (some) bundlers. Upon transpiling, TypeScript erases type-only imports completely. In some environment (not ours), this makes the bundle smaller, as the bundler doesn’t need to bundle type-only imports anymore. ## Type of change - Chore (housekeeping or task changes that don't impact user perception) ## How Has This Been Tested? This was tested to not break the build. ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [x] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test --------- Co-authored-by: Satish Gandham <hello@satishgandham.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com>
2023-03-16 11:41:47 +00:00
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
import {
findLoadingEntities,
getEntityDependantPaths,
groupAndFilterDependantsMap,
} from "utils/WidgetLoadingStateUtils";
import WidgetFactory from "./WidgetFactory";
fix: Improving performance of JS evaluations by splitting the data tree (#21547) ## Description This is the second phase of the split data tree. In the previous version, we collected all config paths in each entity and put them in the `__config__` property. All those config properties do get inserted into final data tree which we don't need at all. As part of this change, we will be creating another tree i.e **'configTree'** which will contain all config of each entity. unEvalTree is split into 2 trees => 1. unEvalTree 2. configTree Example: previous unEvalTree Api1 content <img width="1766" alt="image" src="https://user-images.githubusercontent.com/7846888/215990868-0b095421-e7b8-44bc-89aa-065b35e237d6.png"> After this change unEvalTree Api1 content <img width="1758" alt="image" src="https://user-images.githubusercontent.com/7846888/215991045-506fb10a-645a-4aad-8e77-0f3786a86977.png"> Note- above example doesn't have '__config__' property configTree Api1 content <img width="1760" alt="image" src="https://user-images.githubusercontent.com/7846888/215991169-a2e03443-5d6a-4ff1-97c5-a12593e46395.png"> ## Type of change - Chore (housekeeping or task changes that don't impact user perception) - #11351 ## How Has This Been Tested? - Manual - Jest - Cypress ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-03-20 11:04:02 +00:00
const JS_object_tree: JSActionEntity = {
pluginType: PluginType.JS,
name: "",
ENTITY_TYPE: ENTITY_TYPE.JSACTION,
body: "",
meta: {},
dynamicBindingPathList: [],
bindingPaths: {},
reactivePaths: {},
variables: [],
dependencyMap: {},
actionId: "",
};
// @ts-expect-error: meta property not provided
fix: Improving performance of JS evaluations by splitting the data tree (#21547) ## Description This is the second phase of the split data tree. In the previous version, we collected all config paths in each entity and put them in the `__config__` property. All those config properties do get inserted into final data tree which we don't need at all. As part of this change, we will be creating another tree i.e **'configTree'** which will contain all config of each entity. unEvalTree is split into 2 trees => 1. unEvalTree 2. configTree Example: previous unEvalTree Api1 content <img width="1766" alt="image" src="https://user-images.githubusercontent.com/7846888/215990868-0b095421-e7b8-44bc-89aa-065b35e237d6.png"> After this change unEvalTree Api1 content <img width="1758" alt="image" src="https://user-images.githubusercontent.com/7846888/215991045-506fb10a-645a-4aad-8e77-0f3786a86977.png"> Note- above example doesn't have '__config__' property configTree Api1 content <img width="1760" alt="image" src="https://user-images.githubusercontent.com/7846888/215991169-a2e03443-5d6a-4ff1-97c5-a12593e46395.png"> ## Type of change - Chore (housekeeping or task changes that don't impact user perception) - #11351 ## How Has This Been Tested? - Manual - Jest - Cypress ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-03-20 11:04:02 +00:00
const Select_tree: WidgetEntity = {
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
widgetId: "",
type: "",
widgetName: "",
renderMode: "CANVAS",
version: 0,
parentColumnSpace: 0,
parentRowSpace: 0,
leftColumn: 0,
rightColumn: 0,
topRow: 0,
bottomRow: 0,
isLoading: false,
animateLoading: true,
};
fix: Improving performance of JS evaluations by splitting the data tree (#21547) ## Description This is the second phase of the split data tree. In the previous version, we collected all config paths in each entity and put them in the `__config__` property. All those config properties do get inserted into final data tree which we don't need at all. As part of this change, we will be creating another tree i.e **'configTree'** which will contain all config of each entity. unEvalTree is split into 2 trees => 1. unEvalTree 2. configTree Example: previous unEvalTree Api1 content <img width="1766" alt="image" src="https://user-images.githubusercontent.com/7846888/215990868-0b095421-e7b8-44bc-89aa-065b35e237d6.png"> After this change unEvalTree Api1 content <img width="1758" alt="image" src="https://user-images.githubusercontent.com/7846888/215991045-506fb10a-645a-4aad-8e77-0f3786a86977.png"> Note- above example doesn't have '__config__' property configTree Api1 content <img width="1760" alt="image" src="https://user-images.githubusercontent.com/7846888/215991169-a2e03443-5d6a-4ff1-97c5-a12593e46395.png"> ## Type of change - Chore (housekeeping or task changes that don't impact user perception) - #11351 ## How Has This Been Tested? - Manual - Jest - Cypress ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-03-20 11:04:02 +00:00
const Query_tree: ActionEntity = {
data: {},
actionId: "",
config: {},
run: {},
clear: {},
ENTITY_TYPE: ENTITY_TYPE.ACTION,
datasourceUrl: "",
responseMeta: {
isExecutionSuccess: true,
},
isLoading: false,
};
fix: Improving performance of JS evaluations by splitting the data tree (#21547) ## Description This is the second phase of the split data tree. In the previous version, we collected all config paths in each entity and put them in the `__config__` property. All those config properties do get inserted into final data tree which we don't need at all. As part of this change, we will be creating another tree i.e **'configTree'** which will contain all config of each entity. unEvalTree is split into 2 trees => 1. unEvalTree 2. configTree Example: previous unEvalTree Api1 content <img width="1766" alt="image" src="https://user-images.githubusercontent.com/7846888/215990868-0b095421-e7b8-44bc-89aa-065b35e237d6.png"> After this change unEvalTree Api1 content <img width="1758" alt="image" src="https://user-images.githubusercontent.com/7846888/215991045-506fb10a-645a-4aad-8e77-0f3786a86977.png"> Note- above example doesn't have '__config__' property configTree Api1 content <img width="1760" alt="image" src="https://user-images.githubusercontent.com/7846888/215991169-a2e03443-5d6a-4ff1-97c5-a12593e46395.png"> ## Type of change - Chore (housekeeping or task changes that don't impact user perception) - #11351 ## How Has This Been Tested? - Manual - Jest - Cypress ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-03-20 11:04:02 +00:00
const Api_tree: ActionEntity = {
data: {},
actionId: "",
config: {},
run: {},
clear: {},
ENTITY_TYPE: ENTITY_TYPE.ACTION,
datasourceUrl: "",
responseMeta: {
isExecutionSuccess: true,
},
isLoading: false,
};
fix: Improving performance of JS evaluations by splitting the data tree (#21547) ## Description This is the second phase of the split data tree. In the previous version, we collected all config paths in each entity and put them in the `__config__` property. All those config properties do get inserted into final data tree which we don't need at all. As part of this change, we will be creating another tree i.e **'configTree'** which will contain all config of each entity. unEvalTree is split into 2 trees => 1. unEvalTree 2. configTree Example: previous unEvalTree Api1 content <img width="1766" alt="image" src="https://user-images.githubusercontent.com/7846888/215990868-0b095421-e7b8-44bc-89aa-065b35e237d6.png"> After this change unEvalTree Api1 content <img width="1758" alt="image" src="https://user-images.githubusercontent.com/7846888/215991045-506fb10a-645a-4aad-8e77-0f3786a86977.png"> Note- above example doesn't have '__config__' property configTree Api1 content <img width="1760" alt="image" src="https://user-images.githubusercontent.com/7846888/215991169-a2e03443-5d6a-4ff1-97c5-a12593e46395.png"> ## Type of change - Chore (housekeeping or task changes that don't impact user perception) - #11351 ## How Has This Been Tested? - Manual - Jest - Cypress ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-03-20 11:04:02 +00:00
const Table_tree: WidgetEntity = {
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
widgetId: "",
type: "TABLE_WIDGET",
widgetName: "",
renderMode: "CANVAS",
version: 0,
parentColumnSpace: 0,
parentRowSpace: 0,
leftColumn: 0,
rightColumn: 0,
topRow: 0,
bottomRow: 0,
isLoading: false,
animateLoading: true,
meta: {},
};
const baseDataTree = {
JS_file: { ...JS_object_tree, name: "JS_file" },
Select1: { ...Select_tree, name: "Select1" },
Select2: { ...Select_tree, name: "Select2" },
Select3: { ...Select_tree, name: "Select3" },
Table1: { ...Table_tree, name: "Table1" },
Query1: { ...Query_tree, name: "Query1" },
Query2: { ...Query_tree, name: "Query2" },
Query3: { ...Query_tree, name: "Query3" },
Api1: { ...Api_tree, name: "Api1" },
};
describe("Widget loading state utils", () => {
describe("findLoadingEntites", () => {
// Select1.options -> JS_file.func1 -> Query1.data
// Select2.options -> JS_file.func2 -> Query2.data
// JS_file.func3 -> Query3.data
const baseInverseMap = {
"Query1.config": ["Query1"],
"Query1.config.body": ["Query1.config"],
"Query1.data": ["JS_file.func1", "Query1"],
"Query2.config": ["Query2"],
"Query2.config.body": ["Query2.config"],
"Query2.data": ["JS_file.func2", "Query2"],
"Query3.config": ["Query3"],
"Query3.config.body": ["Query3.config"],
"Query3.data": ["JS_file.func3"],
"JS_file.func1": ["Select1.options"],
"JS_file.func2": ["Select2.options"],
"Select1.options": [
"Select1.selectedOptionValue",
"Select1.selectedOptionLabel",
"Select1",
],
"Select2.options": [
"Select2.selectedOptionValue",
"Select2.selectedOptionLabel",
"Select2",
],
"Select3.options": [
"Select3.selectedOptionValue",
"Select3.selectedOptionLabel",
"Select3",
],
};
beforeAll(() => {
// mock WidgetFactory.getLoadingProperties
const loadingPropertiesMap = new Map<string, RegExp[]>();
loadingPropertiesMap.set("TABLE_WIDGET", [/.tableData$/]);
jest
.spyOn(WidgetFactory, "getLoadingProperties")
.mockImplementation((widgetType) =>
loadingPropertiesMap.get(widgetType),
);
});
afterAll(() => {
jest.restoreAllMocks();
});
// Select1.options -> JS_file.func1 -> Query1.data
it("handles linear dependencies", () => {
const loadingEntites = findLoadingEntities(
["Query1"],
baseDataTree,
baseInverseMap,
);
expect(loadingEntites).toStrictEqual(new Set(["Select1"]));
});
// Select1.options -> JS_file.func1 -> Query1.data
// Select2.options -> JS_file.func2 -> Query2.data
// Select3.options -> none
it("handles multiple dependencies", () => {
const loadingEntites = findLoadingEntities(
["Query1", "Query2", "Query3"],
baseDataTree,
baseInverseMap,
);
expect(loadingEntites).toStrictEqual(new Set(["Select1", "Select2"]));
});
// none -> Query3.data
it("handles no dependencies", () => {
const loadingEntites = findLoadingEntities(
["Query3"],
baseDataTree,
baseInverseMap,
);
expect(loadingEntites).toStrictEqual(new Set([]));
});
// JS_file.func1 -> Query1.run
// Select1.options -> Query1.data
it("handles Query.run and Query.data dependency", () => {
const loadingEntites = findLoadingEntities(["Query1"], baseDataTree, {
"Query1.config": ["Query1"],
"Query1.config.body": ["Query1.config"],
"Query1.run": ["JS_file.func1"],
"Query1.data": ["Select1.options", "Query1"],
"JS_file.func1": [],
"Select1.options": [
"Select1.selectedOptionValue",
"Select1.selectedOptionLabel",
"Select1",
],
});
expect(loadingEntites).toStrictEqual(new Set(["Select1"]));
});
// Select1.options -> JS_file.func1 -> JS_file.internalFunc -> Query1.data
it("handles nested JS dependencies within same file", () => {
const loadingEntites = findLoadingEntities(["Query1"], baseDataTree, {
"Query1.config": ["Query1"],
"Query1.config.body": ["Query1.config"],
"Query1.data": ["JS_file.internalFunc", "Query1"],
"JS_file.internalFunc": ["JS_file.func1"],
"JS_file.func1": ["Select1.options"],
"Select1.options": [
"Select1.selectedOptionValue",
"Select1.selectedOptionLabel",
"Select1",
],
});
expect(loadingEntites).toStrictEqual(new Set(["Select1"]));
});
// Select1.options -> JS_file1.func1 -> JS_file2.internalFunc -> Query1.data
it("handles nested JS dependencies between files", () => {
const loadingEntites = findLoadingEntities(
["Query1"],
{
...baseDataTree,
JS_file1: { ...JS_object_tree, name: "JS_file1" },
JS_file2: { ...JS_object_tree, name: "JS_file2" },
},
{
"Query1.config": ["Query1"],
"Query1.config.body": ["Query1.config"],
"Query1.data": ["JS_file2.internalFunc", "Query1"],
"JS_file2.internalFunc": ["JS_file1.func1"],
"JS_file1.func1": ["Select1.options"],
"Select1.options": [
"Select1.selectedOptionValue",
"Select1.selectedOptionLabel",
"Select1",
],
},
);
expect(loadingEntites).toStrictEqual(new Set(["Select1"]));
});
/* Select1.options -> JS.func1 -> Query1.data,
Select2.options -> Query2.data,
JS.func2 -> Query2.run
When Query2 is called.
Only Select2 should be listed, not Select1.
*/
it("handles selective dependencies in same JS file", () => {
const loadingEntites = findLoadingEntities(["Query2"], baseDataTree, {
"Query1.config": ["Query1"],
"Query1.config.body": ["Query1.config"],
"Query1.data": ["JS_file.func1"],
"Query2.config": ["Query2"],
"Query2.config.body": ["Query2.config"],
"Query2.data": ["JS_file.func2"],
"JS_file.func1": ["Select1.options"],
"JS_file.func2": ["Select2.options"],
"Select1.options": [
"Select1.selectedOptionValue",
"Select1.selectedOptionLabel",
"Select1",
],
"Select2.options": [
"Select2.selectedOptionValue",
"Select2.selectedOptionLabel",
"Select2",
],
});
expect(loadingEntites).toStrictEqual(new Set(["Select2"]));
});
it("includes loading properties", () => {
const loadingEntites = findLoadingEntities(["Api1"], baseDataTree, {
"Api1.data": ["Table1.tableData"],
});
expect(loadingEntites).toStrictEqual(new Set(["Table1"]));
});
it("ignores non-loading properties", () => {
const loadingEntites = findLoadingEntities(["Api1"], baseDataTree, {
"Api1.run": ["Table1.primaryColumns.action.onClick"],
});
expect(loadingEntites).toStrictEqual(new Set());
});
});
describe("groupAndFilterDependantsMap", () => {
it("groups entities and filters self-dependencies", () => {
const groupedDependantsMap = groupAndFilterDependantsMap(
{
"Query1.config": ["Query1"],
"Query1.config.body": ["Query1.config"],
"Query1.data": ["JS_file.func1", "Query1"], // dependant
"Query2.config": ["Query2"],
"Query2.config.body": ["Query2.config"],
"Query2.run": ["Query2", "JS_file.func2"], // dependant
"Query2.data": ["Query2", "Select2.options"], // dependant
"Query3.config": ["Query3"],
"Query3.config.body": ["Query3.config"],
"JS_file.func1": ["Select1.options"], // dependant
"Select1.options": [
"Select1.selectedOptionValue",
"Select1.selectedOptionLabel",
"Select1",
],
"Select2.options": [
"Select2.selectedOptionValue",
"Select2.selectedOptionLabel",
"Select2",
],
},
baseDataTree,
);
expect(groupedDependantsMap).toStrictEqual({
Query1: { "Query1.data": ["JS_file.func1"] },
Query2: {
"Query2.run": ["JS_file.func2"],
"Query2.data": ["Select2.options"],
},
JS_file: {
"JS_file.func1": ["Select1.options"],
},
});
});
it("includes JS object's self dependencies", () => {
const groupedDependantsMap = groupAndFilterDependantsMap(
{
"JS_file.func1": ["Select1.options"], // dependant
"JS_file.internalFunc": ["JS_file.func1"], // self-dependant JsObject
},
baseDataTree,
);
expect(groupedDependantsMap).toStrictEqual({
JS_file: {
"JS_file.func1": ["Select1.options"],
"JS_file.internalFunc": ["JS_file.func1"],
},
});
});
it("includes JS object's nested self dependencies", () => {
const groupedDependantsMap = groupAndFilterDependantsMap(
{
"JS_file.func1": ["Select1.options"], // dependant
"JS_file.internalFunc2": ["JS_file.func1"], // self-dependant JsObject
"JS_file.internalFunc1": ["JS_file.internalFunc2"], // self-dependant JsObject
},
baseDataTree,
);
expect(groupedDependantsMap).toStrictEqual({
JS_file: {
"JS_file.func1": ["Select1.options"],
"JS_file.internalFunc2": ["JS_file.func1"],
"JS_file.internalFunc1": ["JS_file.internalFunc2"],
},
});
});
});
describe("getEntityDependantPaths", () => {
// Select1.options -> JS_file.func1 -> Query1.data
it("handles simple dependency", () => {
const dependants = getEntityDependantPaths(
["Query1"],
{
Query1: {
"Query1.data": ["JS_file.func1"],
},
JS_file: {
"JS_file.func1": ["Select1.options"],
},
},
new Set<string>(),
);
expect(dependants).toStrictEqual(
new Set(["JS_file.func1", "Select1.options"]),
);
});
// Select1.options -> JS_file.func1 -> Query1.data
// Select2.options -> JS_file.func2 -> Query1.data
it("handles multiple dependencies", () => {
const dependants = getEntityDependantPaths(
["Query1"],
{
Query1: {
"Query1.data": ["JS_file.func1", "JS_file.func2"],
},
JS_file: {
"JS_file.func1": ["Select1.options"],
"JS_file.func2": ["Select2.options"],
},
},
new Set<string>(),
);
expect(dependants).toStrictEqual(
new Set([
"JS_file.func1",
"Select1.options",
"JS_file.func2",
"Select2.options",
]),
);
});
it("handles specific entity paths", () => {
const dependants = getEntityDependantPaths(
["JS_file.func2"], // specific path
{
Query1: {
"Query1.data": ["JS_file.func1"],
},
Query2: {
"Query2.data": ["JS_file.func2"],
},
JS_file: {
"JS_file.func1": ["Select1.options"],
"JS_file.func2": ["Select2.options"],
},
},
new Set<string>(),
);
expect(dependants).toStrictEqual(new Set(["Select2.options"]));
});
// Select1.options -> JS_file.func1 -> JS_file.internalFunc -> Query1.data
it("handles JS self-dependencies", () => {
const dependants = getEntityDependantPaths(
["Query1"],
{
Query1: {
"Query1.data": ["JS_file.internalFunc"],
},
JS_file: {
"JS_file.internalFunc": ["JS_file.func1"],
"JS_file.func1": ["Select1.options"],
},
},
new Set<string>(),
);
expect(dependants).toStrictEqual(
new Set(["JS_file.internalFunc", "JS_file.func1", "Select1.options"]),
);
});
// Select1.options -> JS_file.func -> JS_file.internalFunc1 -> JS_file.internalFunc2 -> Query1.data
it("handles nested JS self-dependencies", () => {
const dependants = getEntityDependantPaths(
["Query1"],
{
Query1: {
"Query1.data": ["JS_file.internalFunc2"],
},
JS_file: {
"JS_file.internalFunc2": ["JS_file.internalFunc1"],
"JS_file.internalFunc1": ["JS_file.func"],
"JS_file.func": ["Select1.options"],
},
},
new Set<string>(),
);
expect(dependants).toStrictEqual(
new Set([
"JS_file.internalFunc1",
"JS_file.internalFunc2",
"JS_file.func",
"Select1.options",
]),
);
});
/* Select1.options -> JS.func1 -> Query1.data,
Select2.options -> Query2.data,
JS.func2 -> Query2.run
When Query2 is called.
Only Select2 should be listed, not Select1.
*/
it("handles selective dependencies in same JS file", () => {
const dependants = getEntityDependantPaths(
["Query2"],
{
Query1: {
"Query1.data": ["JS_file.func1"],
},
Query2: {
"Query2.data": ["JS_file.func2"],
},
JS_file: {
"JS_file.func1": ["Select1.options"],
"JS_file.func2": ["Select2.options"],
},
},
new Set<string>(),
);
expect(dependants).toStrictEqual(
new Set(["JS_file.func2", "Select2.options"]),
);
});
});
});