diff --git a/app/client/packages/dsl/src/migrate/index.ts b/app/client/packages/dsl/src/migrate/index.ts index 811a6059cc5..738e4ac3e1c 100644 --- a/app/client/packages/dsl/src/migrate/index.ts +++ b/app/client/packages/dsl/src/migrate/index.ts @@ -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 => { 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; } }; diff --git a/app/client/packages/dsl/src/migrate/migrations/012-migrate-incorrect-dynamic-binding-path-lists.ts b/app/client/packages/dsl/src/migrate/migrations/012-migrate-incorrect-dynamic-binding-path-lists.ts index bc3d32aa949..9b9effd865d 100644 --- a/app/client/packages/dsl/src/migrate/migrations/012-migrate-incorrect-dynamic-binding-path-lists.ts +++ b/app/client/packages/dsl/src/migrate/migrations/012-migrate-incorrect-dynamic-binding-path-lists.ts @@ -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; + +/* + 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); + } + } -const getWidgetPropertyPaneContentConfig = (type: string): readonly any[] => { + return cachedWidgetConfigs; +}; + +const getWidgetPropertyPaneContentConfig = async ( + type: string, +): Promise => { + 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 => { + 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 => { + 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 => { + 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 => { +): Promise => { 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), + ), ); } diff --git a/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts b/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts index ae865ac739e..76b4294ab87 100644 --- a/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts +++ b/app/client/packages/dsl/src/migrate/tests/DSLMigration.test.ts @@ -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; + 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; + 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, - }; - }), - }); - } + return { + version: dsl?.version, + validationFuncName: functionName, + }; + }), + }); + } + }); }); - }); - // Runs all the migrations - DSLMigrations.migrateDSL(originalDSLForDSLMigrations as unknown as DSLWidget); + // Runs all the migrations + await DSLMigrations.migrateDSL( + originalDSLForDSLMigrations as unknown as DSLWidget, + ); - migrations.forEach((item: any, testIdx: number) => { - const { functionLookup, version } = item; - const dslVersion = version ?? 0; + 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; + 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; - - describe(`Test ${testIdx}:`, () => { - test(`Has ${functionName} function executed?`, () => { - // Check if the migration function is called - expect(results[resultsLastIdx].value.validationFuncName).toEqual( - functionName, - ); - }); + 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) => { - 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); - }); + // 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); }); diff --git a/app/client/packages/dsl/src/migrate/tests/DSLMigrationsUtils.test.ts b/app/client/packages/dsl/src/migrate/tests/DSLMigrationsUtils.test.ts index 5bd449a9c59..f79394c90c9 100644 --- a/app/client/packages/dsl/src/migrate/tests/DSLMigrationsUtils.test.ts +++ b/app/client/packages/dsl/src/migrate/tests/DSLMigrationsUtils.test.ts @@ -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 diff --git a/app/client/packages/rts/src/controllers/Dsl/DslController.ts b/app/client/packages/rts/src/controllers/Dsl/DslController.ts index 6bfc0f5e7f4..7f0f062d475 100644 --- a/app/client/packages/rts/src/controllers/Dsl/DslController.ts +++ b/app/client/packages/rts/src/controllers/Dsl/DslController.ts @@ -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) { diff --git a/app/client/packages/rts/src/routes/dsl_routes.ts b/app/client/packages/rts/src/routes/dsl_routes.ts index ada447ac975..d53c9ea6bcf 100644 --- a/app/client/packages/rts/src/routes/dsl_routes.ts +++ b/app/client/packages/rts/src/routes/dsl_routes.ts @@ -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; diff --git a/app/client/packages/rts/src/services/DslService.ts b/app/client/packages/rts/src/services/DslService.ts index 0af89b3c6e2..fc06ffc25f8 100644 --- a/app/client/packages/rts/src/services/DslService.ts +++ b/app/client/packages/rts/src/services/DslService.ts @@ -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; } diff --git a/app/client/src/api/PageApi.tsx b/app/client/src/api/PageApi.tsx index 11b9a914324..9071a854e56 100644 --- a/app/client/src/api/PageApi.tsx +++ b/app/client/src/api/PageApi.tsx @@ -47,6 +47,8 @@ export interface PageLayoutsRequest { } export interface FetchPageResponseData { + isDefault?: boolean; + isHidden?: boolean; id: string; baseId: string; name: string; diff --git a/app/client/src/ce/sagas/PageSagas.tsx b/app/client/src/ce/sagas/PageSagas.tsx index aeee2a7b60c..d1c8e1e8683 100644 --- a/app/client/src/ce/sagas/PageSagas.tsx +++ b/app/client/src/ce/sagas/PageSagas.tsx @@ -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 => { + 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) { // 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, }); diff --git a/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx b/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx index 5978e1e3192..2456625d6d2 100644 --- a/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx +++ b/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx @@ -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 Promise> >; -// 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" - ); - - cachedSvgImportsMap = svgImportsMap; // Cache the module for future use + try { + const { default: svgImportsMap } = await import( + "components/designSystems/blueprintjs/icon/svgImportsMap" + ); + + 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 diff --git a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.test.tsx b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.test.tsx index c35b0e68536..d19d0c21b56 100644 --- a/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.test.tsx +++ b/app/client/src/layoutSystems/fixedlayout/editor/FixedLayoutCanvasArenas/CanvasSelectionArena.test.tsx @@ -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", () => { , { 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", () => { , ); + + 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( diff --git a/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx b/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx index f5a753df35b..04091582d3c 100644 --- a/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx +++ b/app/client/src/pages/Editor/Explorer/EntityExplorer.test.tsx @@ -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", () => { , ); // 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", () => { , ); // 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", () => { , ); // 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(() => { diff --git a/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.test.tsx b/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.test.tsx index 3d3149b681b..3dac96b0f16 100644 --- a/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.test.tsx +++ b/app/client/src/pages/Editor/GlobalHotKeys/GlobalHotKeys.test.tsx @@ -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 ; + return hasLoaded ? : 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", () => { , { 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( @@ -449,6 +449,9 @@ describe("Undo/Redo hotkey", () => { , ); + // 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( @@ -480,6 +484,9 @@ describe("Undo/Redo hotkey", () => { , ); + // 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( @@ -511,6 +518,9 @@ describe("Undo/Redo hotkey", () => { , ); + // wait for the dom to settle down by waitng for the canvas to be loaded + await component.findByTestId("t--canvas-artboard"); + dispatchSpy.mockClear(); act(() => { diff --git a/app/client/src/pages/Editor/IDE/AppsmithIDE.test.tsx b/app/client/src/pages/Editor/IDE/AppsmithIDE.test.tsx index 6ac8be02c3b..e8256efff8a 100644 --- a/app/client/src/pages/Editor/IDE/AppsmithIDE.test.tsx +++ b/app/client/src/pages/Editor/IDE/AppsmithIDE.test.tsx @@ -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; const containerId = generateReactKey(); const canvasId = generateReactKey(); @@ -778,6 +779,8 @@ describe("Drag and Drop widgets into Main container", () => { , { 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(() => { diff --git a/app/client/src/pages/Editor/IDE/EditorPane/UI/UIRender.test.tsx b/app/client/src/pages/Editor/IDE/EditorPane/UI/UIRender.test.tsx index 5748a9a3f59..2bc26118bd8 100644 --- a/app/client/src/pages/Editor/IDE/EditorPane/UI/UIRender.test.tsx +++ b/app/client/src/pages/Editor/IDE/EditorPane/UI/UIRender.test.tsx @@ -95,7 +95,7 @@ describe("IDE URL rendering: UI", () => { const url = `/app/applicationSlug/pageSlug-${pageId}/edit/widgets/` + widgetID; - const { getByTestId } = render( + const component = render( , @@ -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", () => { diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index ec411e1b708..d7caf868e38 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -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, newPage, - ) as DSLWidget; + )) as DSLWidget; // If this DSL is meant to be transformed // then the dslTransformer would have been passed by the caller diff --git a/app/client/src/widgets/ContainerWidget/widget/index.test.tsx b/app/client/src/widgets/ContainerWidget/widget/index.test.tsx index faf96507c61..3aff3f57fe5 100644 --- a/app/client/src/widgets/ContainerWidget/widget/index.test.tsx +++ b/app/client/src/widgets/ContainerWidget/widget/index.test.tsx @@ -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", () => { , { initialState: appState, sagasToRun: sagasToRunForTests }, ); - expect(spyUseCanvasDragging).toHaveBeenCalled(); + await waitFor(() => { + expect(spyUseCanvasDragging).toHaveBeenCalled(); + }); }); }); diff --git a/app/client/src/widgets/TabsWidget/widget/index.test.tsx b/app/client/src/widgets/TabsWidget/widget/index.test.tsx index e6adddfc5f3..dc87414b1cf 100644 --- a/app/client/src/widgets/TabsWidget/widget/index.test.tsx +++ b/app/client/src/widgets/TabsWidget/widget/index.test.tsx @@ -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", () => { , ); + + // 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 diff --git a/app/client/test/factories/WidgetFactoryUtils.ts b/app/client/test/factories/WidgetFactoryUtils.ts index 262b37bb042..b5d8bdf3c1b 100644 --- a/app/client/test/factories/WidgetFactoryUtils.ts +++ b/app/client/test/factories/WidgetFactoryUtils.ts @@ -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 => { ...child, }); }; + export const buildChildren = (children: Partial[]) => { 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[]) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const children: any = buildChildren(childData); + return widgetCanvasFactory.build({ children, }); diff --git a/app/client/test/testCommon.ts b/app/client/test/testCommon.ts index a1494d6fe9f..ab3fcb9d128 100644 --- a/app/client/test/testCommon.ts +++ b/app/client/test/testCommon.ts @@ -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, diff --git a/app/client/test/testMockedWidgets.tsx b/app/client/test/testMockedWidgets.tsx index d4cd005133f..70795c0a729 100644 --- a/app/client/test/testMockedWidgets.tsx +++ b/app/client/test/testMockedWidgets.tsx @@ -9,14 +9,17 @@ import { useMockDsl } from "./testCommon"; export function MockCanvas() { const canvasWidgetsStructure = useSelector(getCanvasWidgetsStructure); + return ; } -export function UpdateAppViewer({ dsl }: any) { - useMockDsl(dsl, APP_MODE.PUBLISHED); - return ; +export function UpdateAppViewer({ dsl }: { dsl: unknown }) { + const hasLoaded = useMockDsl(dsl, APP_MODE.PUBLISHED); + + return hasLoaded ? : null; } -export function UpdatedEditor({ dsl }: any) { - useMockDsl(dsl, APP_MODE.EDIT); - return ; +export function UpdatedEditor({ dsl }: { dsl: unknown }) { + const hasLoaded = useMockDsl(dsl, APP_MODE.EDIT); + + return hasLoaded ? : null; }