chore: decouple widget-config.json from main chunk (#36924)

## Description
We decoupled the widget-config.json file (177KB when zipped) from the
main bundle and implemented lazy loading during DSL migrations. This
optimisation reduces the size of the main chunk by 10%, which should
lead to better performance, specifically improving FCP and LCP, as the
main chunk's fetch and evaluation times are reduced

Fixes #`Issue Number`  
_or_  
Fixes `Issue URL`
> [!WARNING]  
> _If no issue exists, please create an issue first, and check with the
maintainers if the issue is valid._

## Automation

/ok-to-test tags="@tag.All"

### 🔍 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/11384816747>
> Commit: ae14b3f40c4c1ef77250157e56aed97acae5cbaf
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11384816747&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Thu, 17 Oct 2024 15:04:34 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary by CodeRabbit

- **New Features**
- Enhanced migration logic for DSL widgets with asynchronous operations.
	- Improved performance with lazy loading of widget configurations.
	- Added optional properties to page response data structures.

- **Bug Fixes**
	- Resolved issues with dynamic binding path migrations.

- **Tests**
- Updated test cases to handle asynchronous operations for better
reliability and accuracy.

- **Chores**
- Improved type safety and error handling in widget factory utilities
and mock functions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Vemparala Surya Vamsi 2024-10-17 20:48:39 +05:30 committed by GitHub
parent ebec99c407
commit b122c8195f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 405 additions and 248 deletions

View File

@ -146,7 +146,7 @@ const migrateUnversionedDSL = (currentDSL: DSLWidget) => {
// A rudimentary transform function which updates the DSL based on its version.
// A more modular approach needs to be designed.
// This needs the widget config to be already built to migrate correctly
const migrateVersionedDSL = (currentDSL: DSLWidget, newPage = false) => {
const migrateVersionedDSL = async (currentDSL: DSLWidget, newPage = false) => {
if (currentDSL.version === 1) {
if (currentDSL.children && currentDSL.children.length > 0)
currentDSL.children = currentDSL.children.map(updateContainers);
@ -205,7 +205,7 @@ const migrateVersionedDSL = (currentDSL: DSLWidget, newPage = false) => {
}
if (currentDSL.version === 12) {
currentDSL = migrateIncorrectDynamicBindingPathLists(currentDSL);
currentDSL = await migrateIncorrectDynamicBindingPathLists(currentDSL);
currentDSL.version = 13;
}
@ -619,15 +619,15 @@ const migrateVersionedDSL = (currentDSL: DSLWidget, newPage = false) => {
return currentDSL;
};
export const migrateDSL = (
export const migrateDSL = async (
currentDSL: DSLWidget,
newPage = false,
): DSLWidget => {
): Promise<DSLWidget> => {
if (currentDSL.version === undefined) {
const initialDSL = migrateUnversionedDSL(currentDSL);
return migrateVersionedDSL(initialDSL, newPage) as DSLWidget;
return (await migrateVersionedDSL(initialDSL, newPage)) as DSLWidget;
} else {
return migrateVersionedDSL(currentDSL, newPage) as DSLWidget;
return (await migrateVersionedDSL(currentDSL, newPage)) as DSLWidget;
}
};

View File

@ -7,7 +7,6 @@ import isString from "lodash/isString";
import memoize from "micro-memoize";
import { isObject, isUndefined } from "lodash";
import { generateReactKey, isDynamicValue } from "../utils";
import widgetConfigs from "../helpers/widget-configs.json";
export const WidgetHeightLimits = {
MAX_HEIGHT_IN_ROWS: 9000,
@ -511,8 +510,33 @@ export function addSearchConfigToPanelConfig(config: readonly any[]) {
return configItem;
});
}
// Cache for lazy-loaded widget configurations
let cachedWidgetConfigs: any | null = null;
const getWidgetPropertyPaneContentConfig = (type: string): readonly any[] => {
/*
Lazily load this file since it is very large and used in migrations for certain DSL versions. By lazily loading
this large file it can be reduce the main chunk only be loaded for certain limited conditions.
*/
const loadWidgetConfig = async () => {
if (!cachedWidgetConfigs) {
try {
const { default: widgetConfigs } = await import(
"../helpers/widget-configs.json"
);
cachedWidgetConfigs = widgetConfigs; // Cache the module for future use
} catch (e) {
log.error("Error loading WidgetConfig", e);
}
}
return cachedWidgetConfigs;
};
const getWidgetPropertyPaneContentConfig = async (
type: string,
): Promise<readonly any[]> => {
const widgetConfigs = await loadWidgetConfig();
const propertyPaneContentConfig = (widgetConfigs as any)[type]
.propertyPaneContentConfig;
@ -540,7 +564,11 @@ const getWidgetPropertyPaneContentConfig = (type: string): readonly any[] => {
}
};
const getWidgetPropertyPaneStyleConfig = (type: string): readonly any[] => {
const getWidgetPropertyPaneStyleConfig = async (
type: string,
): Promise<readonly any[]> => {
const widgetConfigs = await loadWidgetConfig();
const propertyPaneStyleConfig = (widgetConfigs as any)[type]
.propertyPaneStyleConfig;
@ -567,14 +595,20 @@ const getWidgetPropertyPaneStyleConfig = (type: string): readonly any[] => {
}
};
const getWidgetPropertyPaneCombinedConfig = (type: string): readonly any[] => {
const contentConfig = getWidgetPropertyPaneContentConfig(type);
const styleConfig = getWidgetPropertyPaneStyleConfig(type);
const getWidgetPropertyPaneCombinedConfig = async (
type: string,
): Promise<readonly any[]> => {
const contentConfig = await getWidgetPropertyPaneContentConfig(type);
const styleConfig = await getWidgetPropertyPaneStyleConfig(type);
return [...contentConfig, ...styleConfig];
};
const getWidgetPropertyPaneConfig = (type: string): readonly any[] => {
const getWidgetPropertyPaneConfig = async (
type: string,
): Promise<readonly any[]> => {
const widgetConfigs = await loadWidgetConfig();
const propertyPaneConfig = (widgetConfigs as any)[type].propertyPaneConfig;
const features = (widgetConfigs as any)[type].features;
@ -590,7 +624,7 @@ const getWidgetPropertyPaneConfig = (type: string): readonly any[] => {
return enhancedPropertyPaneConfig;
} else {
const config = getWidgetPropertyPaneCombinedConfig(type);
const config = await getWidgetPropertyPaneCombinedConfig(type);
if (config === undefined) {
log.error("Widget property pane config not defined", type);
@ -957,14 +991,14 @@ const getAllPathsFromPropertyConfig = memoize(
{ maxSize: 1000 },
);
export const migrateIncorrectDynamicBindingPathLists = (
export const migrateIncorrectDynamicBindingPathLists = async (
currentDSL: Readonly<DSLWidget>,
): DSLWidget => {
): Promise<DSLWidget> => {
const migratedDsl = {
...currentDSL,
};
const dynamicBindingPathList: any[] = [];
const propertyPaneConfig = getWidgetPropertyPaneConfig(currentDSL.type);
const propertyPaneConfig = await getWidgetPropertyPaneConfig(currentDSL.type);
const { bindingPaths } = getAllPathsFromPropertyConfig(
currentDSL,
propertyPaneConfig,
@ -984,8 +1018,10 @@ export const migrateIncorrectDynamicBindingPathLists = (
migratedDsl.dynamicBindingPathList = dynamicBindingPathList;
if (currentDSL.children) {
migratedDsl.children = currentDSL.children.map(
migrateIncorrectDynamicBindingPathLists,
migratedDsl.children = await Promise.all(
currentDSL.children.map(async (value) =>
migrateIncorrectDynamicBindingPathLists(value),
),
);
}

View File

@ -938,85 +938,82 @@ describe("Test all the migrations are running", () => {
afterAll(() => {
jest.clearAllMocks();
});
migrations.forEach((migration: Migration) => {
/**
* Generates mock fucntion for each migration function.
* Mocks the implementation
*/
const version = migration.version ?? 0;
test("assert migration functions being called when migrate dsl has been called ", async () => {
migrations.forEach((migration: Migration) => {
/**
* Generates mock fucntion for each migration function.
* Mocks the implementation
*/
const version = migration.version ?? 0;
mockFnObj[version] = [];
mockFnObj[version] = [];
migration.functionLookup.forEach((lookup) => {
const { functionName, moduleObj } = lookup;
if (moduleObj) {
mockFnObj[version].push({
spyOnFunc: jest
.spyOn(moduleObj, functionName)
.mockImplementation((dsl: any) => {
/**
* We need to delete the children property on the first migration(calculateDynamicHeight),
* to avoid the recursion in the second migration(updateContainers)
*/
dsl && delete dsl.children;
return {
version: dsl?.version,
validationFuncName: functionName,
};
}),
});
}
});
});
// Runs all the migrations
DSLMigrations.migrateDSL(originalDSLForDSLMigrations as unknown as DSLWidget);
migrations.forEach((item: any, testIdx: number) => {
const { functionLookup, version } = item;
const dslVersion = version ?? 0;
functionLookup.forEach(
(lookup: { moduleObj: any; functionName: string }, index: number) => {
migration.functionLookup.forEach((lookup) => {
const { functionName, moduleObj } = lookup;
if (moduleObj) {
const mockObj = mockFnObj[dslVersion][index].spyOnFunc;
const calls = mockObj.mock?.calls;
const results = mockObj.mock?.results;
const resultsLastIdx = mockObj.mock.results.length - 1;
mockFnObj[version].push({
spyOnFunc: jest
.spyOn(moduleObj, functionName)
.mockImplementation((dsl: any) => {
/**
* We need to delete the children property on the first migration(calculateDynamicHeight),
* to avoid the recursion in the second migration(updateContainers)
*/
dsl && delete dsl.children;
describe(`Test ${testIdx}:`, () => {
test(`Has ${functionName} function executed?`, () => {
// Check if the migration function is called
expect(results[resultsLastIdx].value.validationFuncName).toEqual(
functionName,
);
});
// Check if the migration function is called with the current DSL version
calls.forEach((args: any) => {
test(`Does ${functionName} executes with DSL version: ${version}?`, () => {
if (args[0]?.version === version) {
expect(args[0]?.version).toEqual(version);
}
});
test(`For ${functionName}, is the ${args[0]?.version} registerd in tests?`, () => {
expect(
Object.keys(mockFnObj).includes(
args[0]?.version.toString() ?? "0",
),
).toBe(true);
});
});
return {
version: dsl?.version,
validationFuncName: functionName,
};
}),
});
}
},
);
});
});
});
// Runs all the migrations
await DSLMigrations.migrateDSL(
originalDSLForDSLMigrations as unknown as DSLWidget,
);
migrations.forEach((item: any) => {
const { functionLookup, version } = item;
const dslVersion = version ?? 0;
functionLookup.forEach(
(lookup: { moduleObj: any; functionName: string }, index: number) => {
const { functionName, moduleObj } = lookup;
if (moduleObj) {
const mockObj = mockFnObj[dslVersion][index].spyOnFunc;
const calls = mockObj.mock?.calls;
const results = mockObj.mock?.results;
const resultsLastIdx = mockObj.mock.results.length - 1;
// Check if the migration function is called
expect(results[resultsLastIdx].value.validationFuncName).toEqual(
functionName,
);
// Check if the migration function is called with the current DSL version
calls.forEach((args: any) => {
// Does functionName executes with the correct DSL version number
if (args[0]?.version === version) {
expect(args[0]?.version).toEqual(version);
}
// For a functionName is the correct DSL version registed in test cases
expect(
Object.keys(mockFnObj).includes(
args[0]?.version.toString() ?? "0",
),
).toBe(true);
});
}
},
);
});
});
test("Check the migration count matches the lates page version", () => {
expect(migrations.length).toEqual(DSLMigrations.LATEST_DSL_VERSION);
});

View File

@ -5,7 +5,7 @@ import type { DSLWidget } from "../types";
const ASSETS_CDN_URL = "https://assets.appsmith.com";
describe("correctly migrate dsl", () => {
it("migrateDSL for private widget", () => {
it("migrateDSL for private widget", async () => {
const currentVersion = 49; // before adding privateWidgets to all List widgets
const nextVersion = LATEST_DSL_VERSION; // It runs Two Migrations, Always Update as migration increases
@ -1229,12 +1229,12 @@ describe("correctly migrate dsl", () => {
isLoading: false,
};
const actualNextDsl = migrateDSL(currentDSL);
const actualNextDsl = await migrateDSL(currentDSL);
expect(actualNextDsl).toEqual(expectedNextDSL);
});
it("migrateDSL for theming v1", () => {
it("migrateDSL for theming v1", async () => {
const currentVersion = 53;
const nextVersion = LATEST_DSL_VERSION;
const currentDSL: DSLWidget = {
@ -2452,7 +2452,7 @@ describe("correctly migrate dsl", () => {
isLoading: false,
};
const actualNextDsl = migrateDSL(currentDSL);
const actualNextDsl = await migrateDSL(currentDSL);
expect(actualNextDsl).toEqual(expectedNextDSL);
});
@ -3096,7 +3096,7 @@ describe("correctly migrate dsl", () => {
expect(actualNextDSL).toEqual(expectedNextDSL);
});
it("correctly migrates currentIndex/currentRow properties for validations in table view", () => {
it("correctly migrates currentIndex/currentRow properties for validations in table view", async () => {
const currentVersion = 78;
const currentDSL: DSLWidget = {
bottomRow: 740,
@ -3171,7 +3171,7 @@ describe("correctly migrate dsl", () => {
},
],
};
const nextDSL = migrateDSL(currentDSL);
const nextDSL = await migrateDSL(currentDSL);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const validations = (nextDSL.children || [])[0].primaryColumns.column1

View File

@ -8,9 +8,9 @@ export default class DSLController extends BaseController {
super();
}
migrateDSL(req: Request, res: Response) {
async migrateDSL(req: Request, res: Response) {
try {
const latestDSL = migrateDSLToLatest(req.body);
const latestDSL = await migrateDSLToLatest(req.body);
super.sendResponse(res, latestDSL);
} catch (err) {

View File

@ -1,6 +1,7 @@
import DSLController from "@controllers/Dsl/DslController";
import { Validator } from "@middlewares/Validator";
import express from "express";
import type { Response, Request } from "express";
const router = express.Router();
const dslController = new DSLController();
@ -12,6 +13,11 @@ router.get(
dslController.getLatestDSLVersion,
);
router.post("/migrate", validator.validateRequest, dslController.migrateDSL);
router.post(
"/migrate",
validator.validateRequest,
async (req: Request, res: Response) =>
await dslController.migrateDSL(req, res),
);
export default router;

View File

@ -1,7 +1,7 @@
import { LATEST_DSL_VERSION, migrateDSL } from "@shared/dsl";
export function migrateDSLToLatest(currentDsl) {
const latestDSL = migrateDSL(currentDsl);
export async function migrateDSLToLatest(currentDsl) {
const latestDSL = await migrateDSL(currentDsl);
return latestDSL;
}

View File

@ -47,6 +47,8 @@ export interface PageLayoutsRequest {
}
export interface FetchPageResponseData {
isDefault?: boolean;
isHidden?: boolean;
id: string;
baseId: string;
name: string;

View File

@ -193,14 +193,15 @@ export function* refreshTheApp() {
}
}
export const getCanvasWidgetsPayload = (
export const getCanvasWidgetsPayload = async (
pageResponse: FetchPageResponse,
dslTransformer?: (dsl: DSLWidget) => DSLWidget,
): UpdateCanvasPayload => {
const extractedDSL = extractCurrentDSL({
): Promise<UpdateCanvasPayload> => {
const currentDSL = await extractCurrentDSL({
dslTransformer,
response: pageResponse,
}).dsl;
});
const extractedDSL = currentDSL.dsl;
const flattenedDSL = flattenDSL(extractedDSL);
const pageWidgetId = MAIN_CONTAINER_WIDGET_ID;
@ -249,10 +250,9 @@ export function* handleFetchedPage({
// Wait for widget config to be loaded before we can generate the canvas payload
yield call(waitForWidgetConfigBuild);
// Get Canvas payload
const canvasWidgetsPayload = getCanvasWidgetsPayload(
fetchPageResponse,
dslTransformer,
);
const canvasWidgetsPayload: UpdateCanvasPayload =
yield getCanvasWidgetsPayload(fetchPageResponse, dslTransformer);
// Update the canvas
yield put(initCanvasLayout(canvasWidgetsPayload));
@ -329,7 +329,8 @@ export function* updateCanvasLayout(response: FetchPageResponse) {
// Wait for widget config to load before we can get the canvas payload
yield call(waitForWidgetConfigBuild);
// Get Canvas payload
const canvasWidgetsPayload = getCanvasWidgetsPayload(response);
const canvasWidgetsPayload: UpdateCanvasPayload =
yield getCanvasWidgetsPayload(response);
// resize main canvas
resizePublishedMainCanvasToLowestWidget(canvasWidgetsPayload.widgets);
@ -688,9 +689,11 @@ export function* createNewPageFromEntity(
// So, the client premptively uses the default page DSL
// The default page DSL is used and modified using the layout system
// specific dslTransformer
const currentDSL: { dsl: DSLWidget; layoutId: string | undefined } =
yield extractCurrentDSL({ dslTransformer });
const defaultPageLayouts = [
{
dsl: extractCurrentDSL({ dslTransformer }).dsl,
dsl: currentDSL.dsl,
layoutOnLoadActions: [],
},
];
@ -754,14 +757,17 @@ export function* createPageSaga(action: ReduxAction<CreatePageActionPayload>) {
// Add this to the page DSLs for entity explorer
// The dslTransformer may not be necessary for the entity explorer
// However, we still transform for consistency.
const currentDSL: { dsl: DSLWidget; layoutId: string | undefined } =
yield extractCurrentDSL({
dslTransformer,
response,
});
yield put({
type: ReduxActionTypes.FETCH_PAGE_DSL_SUCCESS,
payload: {
pageId: response.data.id,
dsl: extractCurrentDSL({
dslTransformer,
response,
}).dsl,
dsl: currentDSL.dsl,
layoutId: response.data.layouts[0].id,
},
});
@ -879,7 +885,7 @@ export function* clonePageSaga(
// We're not sending the `dslTransformer` to the `extractCurrentDSL` function
// as this is a clone operation, and any layout system specific
// updates to the DSL would have already been performed in the original page
const { dsl, layoutId } = extractCurrentDSL({
const { dsl, layoutId } = yield extractCurrentDSL({
response,
});
@ -1169,7 +1175,7 @@ export function* fetchPageDSLSaga(
// between Auto Layout and Fixed layout systems, this means that
// particularly for these two layout systems the dslTransformer may be necessary
// unless we're no longer running any conversions
const { dsl, layoutId } = extractCurrentDSL({
const { dsl, layoutId } = yield extractCurrentDSL({
dslTransformer,
response: fetchPageResponse,
});

View File

@ -17,6 +17,7 @@ import {
} from "@blueprintjs/core/lib/esm/common/classes";
import { importSvg } from "@appsmith/ads-old";
import type { IconName } from "@blueprintjs/core";
import log from "loglevel";
// This export must be named "IconSize" to match the exports of @blueprintjs/core/lib/esm/components/icon
export enum IconSize {
@ -29,17 +30,21 @@ type IconMapType = Record<
Record<IconSize, () => Promise<typeof import("*.svg")>>
>;
// Create a variable to cache the imported module
// Cache for lazy-loaded svg imports
let cachedSvgImportsMap: IconMapType | null = null;
// Function to lazily load the file once
const loadSvgImportsMapOnce = async () => {
if (!cachedSvgImportsMap) {
const { default: svgImportsMap } = await import(
"components/designSystems/blueprintjs/icon/svgImportsMap"
);
try {
const { default: svgImportsMap } = await import(
"components/designSystems/blueprintjs/icon/svgImportsMap"
);
cachedSvgImportsMap = svgImportsMap; // Cache the module for future use
cachedSvgImportsMap = svgImportsMap; // Cache the module for future use
} catch (e) {
log.error("Error loading SvgImportsMap", e);
}
}
return cachedSvgImportsMap;
@ -70,7 +75,7 @@ function Icon(props: IconProps) {
// Load the cached svgImportsMap once
const svgImportsMap = await loadSvgImportsMapOnce();
if (typeof icon === "string" && icon in svgImportsMap) {
if (svgImportsMap && typeof icon === "string" && icon in svgImportsMap) {
const SvgIcon = await importSvg(svgImportsMap[icon][pixelGridSize]);
setSvgIcon(() => SvgIcon); // Set the component as lazy-loaded

View File

@ -53,7 +53,7 @@ describe("Canvas selection test cases", () => {
jest.useRealTimers();
});
it("Should select using canvas draw", () => {
it("Should select using canvas draw", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -94,10 +94,13 @@ describe("Canvas selection test cases", () => {
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let selectionCanvas: any = component.queryByTestId(
let selectionCanvas: any = await component.findByTestId(
`canvas-selection-${MAIN_CONTAINER_WIDGET_ID}`,
undefined,
{ timeout: 3000 },
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -121,7 +124,7 @@ describe("Canvas selection test cases", () => {
expect(selectionCanvas.style.zIndex).toBe("");
});
it("Should select all elements using canvas from top to bottom", () => {
it("Should select all elements using canvas from top to bottom", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -166,8 +169,10 @@ describe("Canvas selection test cases", () => {
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const selectionDiv: any = component.queryByTestId(
const selectionDiv: any = await component.findByTestId(
`div-selection-${MAIN_CONTAINER_WIDGET_ID}`,
undefined,
{ timeout: 3000 },
);
fireEvent(
@ -221,7 +226,7 @@ describe("Canvas selection test cases", () => {
);
});
it("Should allow draw to select using cmd + draw in Container component", () => {
it("Should allow draw to select using cmd + draw in Container component", async () => {
const containerId = generateReactKey();
const canvasId = generateReactKey();
// TODO: Fix this the next time the file is edited
@ -273,8 +278,10 @@ describe("Canvas selection test cases", () => {
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let selectionCanvas: any = component.queryByTestId(
let selectionCanvas: any = await component.findByTestId(
`canvas-selection-${canvasId}`,
undefined,
{ timeout: 3000 },
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -300,7 +307,7 @@ describe("Canvas selection test cases", () => {
expect(selectionCanvas.style.zIndex).toBe("");
});
it("Should not allow draw to select using cmd + draw in drop disabled Canvas component", () => {
it("Should not allow draw to select using cmd + draw in drop disabled Canvas component", async () => {
const containerId = generateReactKey();
const canvasId = generateReactKey();
// TODO: Fix this the next time the file is edited
@ -341,14 +348,27 @@ describe("Canvas selection test cases", () => {
<Canvas canvasWidth={dsl.rightColumn} widgetsStructure={dsl} />
</MockPageDSL>,
);
let selectionCanvas;
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const selectionCanvas: any = component.queryByTestId(`canvas-${canvasId}`);
try {
// We actually want to assert the canvas component could not be found,
// if the canvas component could not be found after timeout findByTestId will throw an error
// In that case we set the component to be null
selectionCanvas = await component.findByTestId(
`canvas-${canvasId}`,
undefined,
{ timeout: 3000 },
);
} catch (e) {
selectionCanvas = null;
}
expect(selectionCanvas).toBeNull();
});
it("Should select all elements inside a CONTAINER using draw on canvas from top to bottom", () => {
it("Should select all elements inside a CONTAINER using draw on canvas from top to bottom", async () => {
const containerId = "containerWidget";
const canvasId = "canvasWidget";
// TODO: Fix this the next time the file is edited
@ -426,8 +446,10 @@ describe("Canvas selection test cases", () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const selectionDiv: any = component.queryByTestId(
const selectionDiv: any = await component.findByTestId(
`div-selection-${canvasId}`,
undefined,
{ timeout: 3000 },
);
fireEvent(
@ -479,7 +501,7 @@ describe("Canvas selection test cases", () => {
);
});
it("Draw to select from outside of canvas(editor) ", () => {
it("Draw to select from outside of canvas(editor) ", async () => {
const mockGetIsFetchingPage = jest.spyOn(utilities, "getIsFetchingPage");
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -525,7 +547,11 @@ describe("Canvas selection test cases", () => {
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const widgetEditor: any = component.queryByTestId("t--widgets-editor");
const widgetEditor: any = await component.findByTestId(
"t--widgets-editor",
undefined,
{ timeout: 3000 },
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let selectionCanvas: any = component.queryByTestId(

View File

@ -72,7 +72,7 @@ describe("Entity Explorer tests", () => {
);
});
it("Should render Widgets tree in entity explorer", () => {
it("Should render Widgets tree in entity explorer", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([{ type: "TABS_WIDGET" }]);
@ -88,9 +88,13 @@ describe("Entity Explorer tests", () => {
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const widgetsTree: any = component.queryByText("Widgets", {
selector: "div.t--entity-name",
});
const widgetsTree: Element = await component.findByText(
"Widgets",
{
selector: "div.t--entity-name",
},
{ timeout: 3000 },
);
act(() => {
fireEvent.click(widgetsTree);
@ -111,7 +115,7 @@ describe("Entity Explorer tests", () => {
spyWidgetSelection.mockClear();
});
it("Select widget on entity explorer", () => {
it("Select widget on entity explorer", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -128,8 +132,11 @@ describe("Entity Explorer tests", () => {
</MockPageDSL>,
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const tabsWidget: any = component.queryByText(children[0].widgetName);
const tabsWidget: Element = await component.findByText(
children[0].widgetName,
undefined,
{ timeout: 3000 },
);
act(() => {
fireEvent.click(tabsWidget);
@ -144,7 +151,7 @@ describe("Entity Explorer tests", () => {
);
});
it("CMD + click Multi Select widget on entity explorer", () => {
it("CMD + click Multi Select widget on entity explorer", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -166,8 +173,11 @@ describe("Entity Explorer tests", () => {
</MockPageDSL>,
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const checkBox: any = component.queryByText(children[0].widgetName);
const checkBox: Element = await component.findByText(
children[0].widgetName,
undefined,
{ timeout: 3000 },
);
act(() => {
fireEvent.click(checkBox);
@ -198,7 +208,7 @@ describe("Entity Explorer tests", () => {
);
});
it("Shift + Click Multi Select widget on entity explorer", () => {
it("Shift + Click Multi Select widget on entity explorer", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -211,8 +221,7 @@ describe("Entity Explorer tests", () => {
{ type: "BUTTON_WIDGET", parentId: "0", widgetId: "buttonWidgetId" },
]);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const dsl: any = widgetCanvasFactory.build({
const dsl = widgetCanvasFactory.build({
children,
});
const component = render(
@ -223,7 +232,11 @@ describe("Entity Explorer tests", () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const checkboxWidget: any = component.queryByText(children[0].widgetName);
const checkboxWidget: any = await component.findByText(
children[0].widgetName,
undefined,
{ timeout: 3000 },
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const buttonWidget: any = component.queryByText(children[2].widgetName);
@ -255,7 +268,7 @@ describe("Entity Explorer tests", () => {
);
});
it("Shift + Click Deselect Non Siblings", () => {
it("Shift + Click Deselect Non Siblings", async () => {
const containerId = "containerWidgetId";
const canvasId = "canvasWidgetId";
// TODO: Fix this the next time the file is edited
@ -311,9 +324,10 @@ describe("Entity Explorer tests", () => {
</MockPageDSL>,
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const containerWidget: any = component.queryByText(
const containerWidget: Element = await component.findByText(
containerChildren[0].widgetName,
undefined,
{ timeout: 3000 },
);
act(() => {

View File

@ -55,9 +55,9 @@ describe("Canvas Hot Keys", () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function UpdatedEditor({ dsl }: any) {
useMockDsl(dsl);
const hasLoaded = useMockDsl(dsl);
return <IDE />;
return hasLoaded ? <IDE /> : null;
}
// These need to be at the top to avoid imports not being mocked. ideally should be in setup.ts but will override for all other tests
@ -140,7 +140,7 @@ describe("Canvas Hot Keys", () => {
</MemoryRouter>,
{ initialState: store.getState(), sagasToRun: sagasToRunForTests },
);
const canvasWidgets = component.queryAllByTestId("test-widget");
const canvasWidgets = await component.findAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(2);
act(() => {
@ -291,7 +291,7 @@ describe("Cut/Copy/Paste hotkey", () => {
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const artBoard: any = component.queryByTestId("t--canvas-artboard");
const artBoard: any = await component.findByTestId("t--canvas-artboard");
// deselect all other widgets
fireEvent.click(artBoard);
@ -389,7 +389,7 @@ describe("Cut/Copy/Paste hotkey", () => {
);
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const artBoard: any = component.queryByTestId("t--canvas-artboard");
const artBoard: any = await component.findByTestId("t--canvas-artboard");
// deselect all other widgets
fireEvent.click(artBoard);
@ -434,7 +434,7 @@ describe("Cut/Copy/Paste hotkey", () => {
});
describe("Undo/Redo hotkey", () => {
it("should dispatch undo Action on cmd + z", () => {
it("should dispatch undo Action on cmd + z", async () => {
const dispatchSpy = jest.spyOn(store, "dispatch");
const component = render(
<MockPageDSL>
@ -449,6 +449,9 @@ describe("Undo/Redo hotkey", () => {
</MockPageDSL>,
);
// wait for the dom to settle down by waitng for the canvas to be loaded
await component.findByTestId("t--canvas-artboard");
dispatchSpy.mockClear();
act(() => {
@ -462,10 +465,11 @@ describe("Undo/Redo hotkey", () => {
);
});
expect(dispatchSpy).toBeCalledTimes(1);
expect(dispatchSpy).toBeCalledWith(undoAction());
await waitFor(() => {
expect(dispatchSpy).toBeCalledWith(undoAction());
});
});
it("should dispatch redo Action on cmd + shift + z", () => {
it("should dispatch redo Action on cmd + shift + z", async () => {
const dispatchSpy = jest.spyOn(store, "dispatch");
const component = render(
<MockPageDSL>
@ -480,6 +484,9 @@ describe("Undo/Redo hotkey", () => {
</MockPageDSL>,
);
// wait for the dom to settle down by waitng for the canvas to be loaded
await component.findByTestId("t--canvas-artboard");
dispatchSpy.mockClear();
act(() => {
@ -496,7 +503,7 @@ describe("Undo/Redo hotkey", () => {
expect(dispatchSpy).toBeCalledTimes(1);
expect(dispatchSpy).toBeCalledWith(redoAction());
});
it("should dispatch redo Action on ctrl + y", () => {
it("should dispatch redo Action on ctrl + y", async () => {
const dispatchSpy = jest.spyOn(store, "dispatch");
const component = render(
<MockPageDSL>
@ -511,6 +518,9 @@ describe("Undo/Redo hotkey", () => {
</MockPageDSL>,
);
// wait for the dom to settle down by waitng for the canvas to be loaded
await component.findByTestId("t--canvas-artboard");
dispatchSpy.mockClear();
act(() => {

View File

@ -154,7 +154,7 @@ describe("Drag and Drop widgets into Main container", () => {
}));
});
it("Drag to move widgets", () => {
it("Drag to move widgets", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -190,7 +190,8 @@ describe("Drag and Drop widgets into Main container", () => {
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
const canvasWidgets = await component.findAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(1);
// TODO: Fix this the next time the file is edited
@ -275,7 +276,7 @@ describe("Drag and Drop widgets into Main container", () => {
expect(finalPositions.top).not.toEqual(initPositions.top);
});
it("When widgets are moved out of main container bounds move them back to previous position", () => {
it("When widgets are moved out of main container bounds move them back to previous position", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -310,7 +311,7 @@ describe("Drag and Drop widgets into Main container", () => {
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
const canvasWidgets = await component.findAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(1);
// TODO: Fix this the next time the file is edited
@ -499,7 +500,7 @@ describe("Drag and Drop widgets into Main container", () => {
// expect(finalPositions.top).toEqual(initPositions.top);
// });
it("When widgets are out of bottom most bounds of parent canvas, canvas has to expand", () => {
it("When widgets are out of bottom most bounds of parent canvas, canvas has to expand", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([
@ -544,7 +545,7 @@ describe("Drag and Drop widgets into Main container", () => {
const propPane = component.queryByTestId("t--propertypane");
expect(propPane).toBeNull();
const canvasWidgets = component.queryAllByTestId("test-widget");
const canvasWidgets = await component.findAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(2);
@ -639,7 +640,7 @@ describe("Drag and Drop widgets into Main container", () => {
);
});
it("Drag and Drop widget into an empty canvas", () => {
it("Drag and Drop widget into an empty canvas", async () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren([]);
@ -675,7 +676,7 @@ describe("Drag and Drop widgets into Main container", () => {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const containerButton: any = component.queryAllByText("Container");
const containerButton: any = await component.findAllByText("Container");
act(() => {
fireEvent.dragStart(containerButton[0]);
@ -733,7 +734,7 @@ describe("Drag and Drop widgets into Main container", () => {
expect(newlyAddedCanvas.length).toBe(1);
});
it("Disallow drag if widget not focused", () => {
it("Disallow drag if widget not focused", async () => {
const initialState = store.getState() as unknown as Partial<AppState>;
const containerId = generateReactKey();
const canvasId = generateReactKey();
@ -778,6 +779,8 @@ describe("Drag and Drop widgets into Main container", () => {
</MemoryRouter>,
{ initialState, sagasToRun: sagasToRunForTests },
);
// wait for the dom to settle down by waitng for the widget to be loaded
const canvasWidgets = await component.findAllByTestId("test-widget");
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -790,8 +793,6 @@ describe("Drag and Drop widgets into Main container", () => {
".t--draggable-containerwidget",
);
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(1);
const initWidgetPosition = {
@ -894,7 +895,7 @@ describe("Drag in a nested container", () => {
}));
});
it("container drags when focused on", () => {
it("container drags when focused on", async () => {
mockGetIsFetchingPage.mockImplementation(() => false);
const component = renderNestedComponent();
@ -903,6 +904,8 @@ describe("Drag in a nested container", () => {
.spyOn(uiSelectors, "getSelectedWidgets")
.mockReturnValue(["container-id"]);
const canvasWidgets = await component.findAllByTestId("test-widget");
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const containerWidget: any = component.container.querySelector(
@ -914,8 +917,6 @@ describe("Drag in a nested container", () => {
".t--draggable-containerwidget",
);
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(3);
const initContainerWidgetPosition = {
@ -975,7 +976,7 @@ describe("Drag in a nested container", () => {
);
});
it("nested widget drags when focused on", () => {
it("nested widget drags when focused on", async () => {
mockGetIsFetchingPage.mockImplementation(() => false);
const component = renderNestedComponent();
@ -984,6 +985,8 @@ describe("Drag in a nested container", () => {
.spyOn(uiSelectors, "getSelectedWidgets")
.mockReturnValue(["text-widget"]);
const canvasWidgets = await component.findAllByTestId("test-widget");
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const textWidget: any = component.container.querySelector(
@ -995,8 +998,6 @@ describe("Drag in a nested container", () => {
".t--draggable-textwidget",
);
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(3);
const initTextWidgetPosition = {
@ -1054,10 +1055,11 @@ describe("Drag in a nested container", () => {
expect(finalTextWidgetPositions).not.toStrictEqual(initTextWidgetPosition);
});
it("does not let disabledWidget drag and parent widget position stays same", () => {
it("does not let disabledWidget drag and parent widget position stays same", async () => {
mockGetIsFetchingPage.mockImplementation(() => false);
const component = renderNestedComponent();
const canvasWidgets = await component.findAllByTestId("test-widget");
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -1090,8 +1092,6 @@ describe("Drag in a nested container", () => {
top: inputWidget.style.top,
};
const canvasWidgets = component.queryAllByTestId("test-widget");
expect(canvasWidgets.length).toBe(3);
act(() => {

View File

@ -95,7 +95,7 @@ describe("IDE URL rendering: UI", () => {
const url =
`/app/applicationSlug/pageSlug-${pageId}/edit/widgets/` + widgetID;
const { getByTestId } = render(
const component = render(
<Route path={BUILDER_PATH}>
<UpdatedEditor dsl={dsl} />
</Route>,
@ -106,8 +106,11 @@ describe("IDE URL rendering: UI", () => {
},
);
// wait for the dom to settle down by waitng for the canvas to be loaded
await component.findByTestId("t--canvas-artboard");
// check for list UI
getByTestId(`t--entity-item-${children[0].widgetName}`);
component.getByTestId(`t--entity-item-${children[0].widgetName}`);
});
it("Canvas: Check tabs rendering in side by side mode", () => {

View File

@ -44,13 +44,13 @@ const defaultDSL = defaultTemplate;
* @param fetchPageResponse The response from the fetchPage API Call
* @returns The updated DSL and the layoutId
*/
export const extractCurrentDSL = ({
export const extractCurrentDSL = async ({
dslTransformer,
response,
}: {
dslTransformer?: (dsl: DSLWidget) => DSLWidget;
response?: FetchPageResponse;
}): { dsl: DSLWidget; layoutId: string | undefined } => {
}): Promise<{ dsl: DSLWidget; layoutId: string | undefined }> => {
// If fetch page response doesn't exist
// It means we are creating a new page
const newPage = !response;
@ -62,10 +62,10 @@ export const extractCurrentDSL = ({
let dsl = currentDSL as DSLWidget;
// Run all the migrations on this DSL
dsl = migrateDSL(
dsl = (await migrateDSL(
currentDSL as ContainerWidgetProps<WidgetProps>,
newPage,
) as DSLWidget;
)) as DSLWidget;
// If this DSL is meant to be transformed
// then the dslTransformer would have been passed by the caller

View File

@ -13,7 +13,7 @@ import {
import { sagasToRunForTests } from "test/sagas";
import { MockApplication } from "test/testCommon";
import { UpdateAppViewer, UpdatedEditor } from "test/testMockedWidgets";
import { render } from "test/testUtils";
import { render, waitFor } from "test/testUtils";
import { generateReactKey } from "widgets/WidgetUtils";
const pageId = "0123456789abcdef00000000";
@ -110,6 +110,8 @@ describe("ContainerWidget tests", () => {
</MemoryRouter>,
{ initialState: appState, sagasToRun: sagasToRunForTests },
);
expect(spyUseCanvasDragging).toHaveBeenCalled();
await waitFor(() => {
expect(spyUseCanvasDragging).toHaveBeenCalled();
});
});
});

View File

@ -49,7 +49,7 @@ describe("Tabs widget functional cases", () => {
expect(tab2).toBeDefined();
});
it("Should render components inside tabs by default", () => {
it("Should render components inside tabs by default", async () => {
const tab1Children = buildChildren([
{ type: "SWITCH_WIDGET", label: "Tab1 Switch" },
{ type: "CHECKBOX_WIDGET", label: "Tab1 Checkbox" },
@ -74,6 +74,10 @@ describe("Tabs widget functional cases", () => {
<Canvas canvasWidth={dsl.rightColumn} widgetsStructure={dsl} />
</MockPageDSL>,
);
// wait for the dom to settle down by waitng for the canvas to be loaded
await component.findByTestId("t--canvas-artboard");
const tab1 = component.queryByText("Tab 1");
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -4,12 +4,12 @@ import type { DSLWidget } from "WidgetProvider/constants";
import defaultTemplate from "templates/default";
import { WidgetTypeFactories } from "./Widgets/WidgetTypeFactories";
const defaultMainContainer: DSLWidget = {
...(defaultTemplate as any),
...(defaultTemplate as unknown as DSLWidget),
canExtend: true,
renderMode: "PAGE",
version: 1,
isLoading: false,
};
} as DSLWidget;
export const mainContainerFactory = makeFactory({ ...defaultMainContainer });
export const widgetCanvasFactory = makeFactory(mainContainerFactory.build());
@ -18,18 +18,22 @@ const buildChild = (child: Partial<WidgetProps>): WidgetProps => {
...child,
});
};
export const buildChildren = (children: Partial<WidgetProps>[]) => {
try {
return children.map((child) => {
return buildChild(child);
});
} catch (error) {
// eslint-disable-next-line no-console
console.error("Check if child widget data provided");
}
};
export const buildDslWithChildren = (childData: Partial<WidgetProps>[]) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const children: any = buildChildren(childData);
return widgetCanvasFactory.build({
children,
});

View File

@ -12,13 +12,16 @@ import type { WidgetEntity } from "ee/entities/DataTree/types";
import urlBuilder from "ee/entities/URLRedirect/URLAssembly";
import type { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsStructureReducer";
import type { Page } from "entities/Page";
import { useEffect, useState } from "react";
import type { FetchPageResponse } from "api/PageApi";
const pageId = "0123456789abcdef00000000";
export const useMockDsl = (dsl: any, mode?: APP_MODE) => {
export const useMockDsl = (dsl: unknown, mode?: APP_MODE) => {
const dispatch = useDispatch();
dispatch(setAppMode(mode || APP_MODE.EDIT));
const mockResp: any = {
const [hasLoaded, setHasLoaded] = useState(false);
const mockResp = {
data: {
id: pageId,
pageId: pageId,
@ -42,52 +45,81 @@ export const useMockDsl = (dsl: any, mode?: APP_MODE) => {
"delete:pages",
],
},
};
const canvasWidgetsPayload = getCanvasWidgetsPayload(mockResp);
dispatch({
type: ReduxActionTypes.FETCH_PAGE_DSLS_SUCCESS,
payload: [
{
pageId: mockResp.data.id,
dsl: extractCurrentDSL({ response: mockResp }).dsl,
},
],
});
const pages: Page[] = [
{
pageName: mockResp.data.name,
pageId: mockResp.data.id,
basePageId: mockResp.data.id,
isDefault: mockResp.data.isDefault,
isHidden: !!mockResp.data.isHidden,
slug: mockResp.data.slug,
userPermissions: [
"read:pages",
"manage:pages",
"create:pageActions",
"delete:pages",
],
},
];
dispatch({
type: ReduxActionTypes.FETCH_PAGE_LIST_SUCCESS,
payload: {
pages,
applicationId: mockResp.data.applicationId,
},
});
dispatch({
type: "UPDATE_LAYOUT",
payload: { widgets: canvasWidgetsPayload.widgets },
});
} as unknown as FetchPageResponse;
dispatch(updateCurrentPage(mockResp.data.id));
useEffect(function loadScripts() {
const loadMigrationScripts = async () => {
const canvasWidgetsPayloadD = await getCanvasWidgetsPayload(mockResp);
const currentDSL = await extractCurrentDSL({
response: mockResp,
});
const currentDsl = currentDSL.dsl;
const canvasWidgetsPayload = canvasWidgetsPayloadD.widgets;
dispatch(setAppMode(mode || APP_MODE.EDIT));
dispatch({
type: ReduxActionTypes.FETCH_PAGE_DSLS_SUCCESS,
payload: [
{
pageId: mockResp.data.id,
dsl: currentDsl,
},
],
});
const pages = [
{
pageName: mockResp.data.name,
pageId: mockResp.data.id,
basePageId: mockResp.data.id,
isDefault: mockResp.data.isDefault,
isHidden: !!mockResp.data.isHidden,
slug: mockResp.data.slug,
userPermissions: [
"read:pages",
"manage:pages",
"create:pageActions",
"delete:pages",
],
},
] as unknown as Page[];
dispatch({
type: ReduxActionTypes.FETCH_PAGE_LIST_SUCCESS,
payload: {
pages,
applicationId: mockResp.data.applicationId,
},
});
dispatch({
type: "UPDATE_LAYOUT",
payload: { widgets: canvasWidgetsPayload },
});
dispatch(updateCurrentPage(mockResp.data.id));
setHasLoaded(true);
};
loadMigrationScripts();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return hasLoaded;
};
export function MockPageDSL({ children, dsl }: any) {
export function MockPageDSL({
children,
dsl,
}: {
children: JSX.Element;
dsl?: unknown;
}) {
editorInitializer();
useMockDsl(dsl);
return children;
const hasLoaded = useMockDsl(dsl);
return hasLoaded ? children : null;
}
const getChildWidgets = (
@ -123,7 +155,7 @@ export const mockCreateCanvasWidget = (
canvasWidget: FlattenedWidgetProps,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
evaluatedWidget: WidgetEntity,
): any => {
) => {
return { ...canvasWidget };
};
@ -141,17 +173,21 @@ export const syntheticTestMouseEvent = (
optionsToAdd = {},
) => {
const options = Object.entries(optionsToAdd);
options.forEach(([key, value]) => {
Object.defineProperty(event, key, { get: () => value });
});
return event;
};
export function MockApplication({ children }: any) {
export function MockApplication({ children }: { children: JSX.Element }) {
editorInitializer();
const dispatch = useDispatch();
dispatch(initEditorAction({ basePageId: pageId, mode: APP_MODE.EDIT }));
const mockResp: any = {
const mockResp = {
workspaceId: "workspace_id",
pages: [
{
@ -176,6 +212,7 @@ export function MockApplication({ children }: any) {
slug: "app-name",
applicationVersion: 2,
};
urlBuilder.updateURLParams(
{
baseApplicationId: mockResp.baseId,
@ -212,6 +249,7 @@ export function MockApplication({ children }: any) {
],
},
});
return children;
}
@ -225,7 +263,8 @@ export function dispatchTestKeyboardEventWithCode(
meta = false,
) {
const event = document.createEvent("KeyboardEvent");
(event as any).initKeyboardEvent(
event.initKeyboardEvent(
eventType,
true,
true,

View File

@ -9,14 +9,17 @@ import { useMockDsl } from "./testCommon";
export function MockCanvas() {
const canvasWidgetsStructure = useSelector(getCanvasWidgetsStructure);
return <Canvas canvasWidth={0} widgetsStructure={canvasWidgetsStructure} />;
}
export function UpdateAppViewer({ dsl }: any) {
useMockDsl(dsl, APP_MODE.PUBLISHED);
return <AppViewerPageContainer />;
export function UpdateAppViewer({ dsl }: { dsl: unknown }) {
const hasLoaded = useMockDsl(dsl, APP_MODE.PUBLISHED);
return hasLoaded ? <AppViewerPageContainer /> : null;
}
export function UpdatedEditor({ dsl }: any) {
useMockDsl(dsl, APP_MODE.EDIT);
return <IDE />;
export function UpdatedEditor({ dsl }: { dsl: unknown }) {
const hasLoaded = useMockDsl(dsl, APP_MODE.EDIT);
return hasLoaded ? <IDE /> : null;
}