chore: add redux test plan dependency and add jest test case for pageSaga (#32714)

## Description
- Add the dependency `redux-saga-test-plan` to help assert the effects
of sagas
- Add test cases for setupPageSaga and setupPublishedPageSaga to assert
if the pageWithMigratedDsl is passed in the payload of fetchPage and
fetchPublishedPage actions respectively.

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  -->
> [!CAUTION]
> 🔴 🔴 🔴 Some tests have failed.
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/8734262909>
> Commit: 9b08d3f48628ac378b2086c30b603c413d8ab7ad
> Cypress dashboard: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8734262909&attempt=1&selectiontype=test&testsstatus=failed&specsstatus=fail"
target="_blank"> Click here!</a>
> The following are new failures, please fix them before merging the PR:
<ol>
>
<li>cypress/e2e/Regression/ClientSide/EmbedSettings/EmbedSettings_spec.js
>
<li>cypress/e2e/Regression/ClientSide/Fork/ForkAppWithMultipleDS_Spec.ts
> <li>cypress/e2e/Regression/ClientSide/Git/GitImport/GitImport_spec.js
>
<li>cypress/e2e/Regression/ClientSide/OtherUIFeatures/UpdateApplication_spec.js
>
<li>cypress/e2e/Regression/ClientSide/Widgets/RTE/RichTextEditor_2_spec.js
>
<li>cypress/e2e/Regression/ClientSide/Workspace/Workspace_validation_spec.js
>
<li>cypress/e2e/Regression/ServerSide/AppLevelImport/AppImportwithDS_Spec.ts
> <li>cypress/e2e/Regression/ServerSide/OnLoadTests/JSOnLoad2_Spec.ts
</ol>
> To know the list of identified flaky tests - <a
href="https://internal.appsmith.com/app/cypress-dashboard/identified-flaky-tests-65890b3c81d7400d08fa9ee3?branch=master"
target="_blank">Refer here</a>

<!-- end of auto-generated comment: Cypress test results  -->





















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


- **Tests**
- Enhanced testing for initialization processes to include more
comprehensive data scenarios in `initSagas.test.ts`.
- Added test cases for `setupPageSaga` and `setupPublishedPageSaga`
functions in `PageSaga.test.ts`.
- **Chores**
- Added `redux-saga-test-plan` for improved testing capabilities in
development.
- **Documentation**
- Updated test descriptions for `initSagas.test.ts` and
`PageSaga.test.ts` to reflect recent changes and additions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Diljit 2024-04-18 14:17:51 +05:30 committed by GitHub
parent 0a9f9b9043
commit 3c1c30fa2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 413 additions and 57 deletions

View File

@ -360,6 +360,7 @@
"redux-devtools": "^3.5.0",
"redux-devtools-extension": "^2.13.8",
"redux-mock-store": "^1.5.4",
"redux-saga-test-plan": "^4.0.6",
"ts-jest": "27.0.0",
"ts-jest-mock-import-meta": "^0.12.0",
"ts-loader": "^9.4.1",

View File

@ -0,0 +1,71 @@
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { testSaga } from "redux-saga-test-plan";
import { setupPageSaga, setupPublishedPageSaga } from "../PageSagas";
import mockResponse from "./mockConsolidatedApiResponse.json";
import type { FetchPageRequest, FetchPageResponse } from "api/PageApi";
import { fetchPage, fetchPublishedPage } from "actions/pageActions";
describe("ce/PageSaga", () => {
it("should put setupPageSaga with pageWithMigratedDsl", () => {
const action: ReduxAction<FetchPageRequest> = {
type: ReduxActionTypes.SETUP_PAGE_INIT,
payload: {
id: "pageId",
pageWithMigratedDsl: mockResponse.data
.pageWithMigratedDsl as FetchPageResponse,
},
};
testSaga(setupPageSaga, action)
.next()
.put(
fetchPage(
action.payload.id,
action.payload.isFirstLoad,
action.payload.pageWithMigratedDsl,
),
)
.next()
.take(ReduxActionTypes.FETCH_PAGE_SUCCESS)
.next()
.put({ type: ReduxActionTypes.SETUP_PAGE_SUCCESS })
.next()
.isDone();
});
it("should put setupPublishedPageSaga with pageWithMigratedDsl", () => {
const action: ReduxAction<{
pageId: string;
bustCache: boolean;
firstLoad: boolean;
pageWithMigratedDsl?: FetchPageResponse;
}> = {
type: ReduxActionTypes.SETUP_PAGE_INIT,
payload: {
pageId: "pageId",
pageWithMigratedDsl: mockResponse.data
.pageWithMigratedDsl as FetchPageResponse,
bustCache: false,
firstLoad: true,
},
};
testSaga(setupPublishedPageSaga, action)
.next()
.put(
fetchPublishedPage(
action.payload.pageId,
action.payload.bustCache,
action.payload.firstLoad,
action.payload.pageWithMigratedDsl,
),
)
.next()
.take(ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS)
.next()
.put({ type: ReduxActionTypes.SETUP_PUBLISHED_PAGE_SUCCESS })
.next()
.isDone();
});
});

View File

@ -0,0 +1,123 @@
{
"responseMeta": {
"status": 200,
"success": true
},
"data": {
"pageWithMigratedDsl": {
"responseMeta": {
"status": 200,
"success": true
},
"data": {
"id": "661c28791c2412092c170119",
"name": "Page1",
"slug": "page1",
"applicationId": "661c28791c2412092c170116",
"layouts": [
{
"dsl": {
"widgetName": "MainContainer",
"backgroundColor": "none",
"rightColumn": 4896,
"snapColumns": 64,
"detachFromLayout": true,
"widgetId": "0",
"topRow": 0,
"bottomRow": 380,
"containerStyle": "none",
"snapRows": 124,
"parentRowSpace": 1,
"type": "CANVAS_WIDGET",
"canExtend": true,
"version": 89,
"minHeight": 1292,
"dynamicTriggerPathList": [],
"parentColumnSpace": 1,
"dynamicBindingPathList": [],
"leftColumn": 0,
"children": [
{
"needsErrorInfo": false,
"mobileBottomRow": 12,
"widgetName": "Text1",
"displayName": "Text",
"iconSVG": "/static/media/icon.a55b701a2ae86aa2c6718ecb7b4083f0.svg",
"searchTags": ["typography", "paragraph", "label"],
"topRow": 8,
"bottomRow": 12,
"parentRowSpace": 10,
"type": "TEXT_WIDGET",
"hideCard": false,
"mobileRightColumn": 15,
"animateLoading": true,
"overflow": "NONE",
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
"parentColumnSpace": 16.390625,
"dynamicTriggerPathList": [],
"leftColumn": 0,
"dynamicBindingPathList": [
{
"key": "truncateButtonColor"
},
{
"key": "fontFamily"
},
{
"key": "borderRadius"
}
],
"shouldTruncate": false,
"truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}",
"text": "",
"key": "bz2lkn7wbc",
"isDeprecated": false,
"rightColumn": 15,
"thumbnailSVG": "/static/media/thumbnail.0c129b82c9b3e4cd4920563b289659ab.svg",
"textAlign": "LEFT",
"dynamicHeight": "AUTO_HEIGHT",
"widgetId": "xv30fhgoz3",
"minWidth": 450,
"isVisible": true,
"fontStyle": "BOLD",
"textColor": "#231F20",
"version": 1,
"parentId": "0",
"tags": ["Suggested", "Content"],
"renderMode": "CANVAS",
"isLoading": false,
"mobileTopRow": 8,
"responsiveBehavior": "fill",
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"mobileLeftColumn": 0,
"maxDynamicHeight": 9000,
"fontSize": "1rem",
"minDynamicHeight": 4
}
]
},
"layoutOnLoadActions": [],
"layoutOnLoadActionErrors": [],
"layoutActions": [],
"id": "661c28791c2412092c170117",
"userPermissions": []
}
],
"userPermissions": [
"create:moduleInstancesInPage",
"read:pages",
"manage:pages",
"create:pageActions",
"delete:pages"
],
"lastUpdatedTime": 1713194519,
"defaultResources": {
"applicationId": "661c28791c2412092c170116",
"pageId": "661c28791c2412092c170119"
}
},
"errorDisplay": ""
}
},
"errorDisplay": ""
}

View File

@ -1,74 +1,83 @@
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import {
type ReduxAction,
ReduxActionTypes,
} from "@appsmith/constants/ReduxActionConstants";
import { APP_MODE } from "entities/App";
import type AppEngine from "entities/Engine";
import AppEngineFactory from "entities/Engine/factory";
import { call } from "redux-saga/effects";
import { getInitResponses } from "sagas/InitSagas";
import { startAppEngine } from "sagas/InitSagas";
import type { AppEnginePayload } from "entities/Engine";
import { testSaga } from "redux-saga-test-plan";
import { generateAutoHeightLayoutTreeAction } from "actions/autoHeightActions";
import mockResponse from "./mockConsolidatedApiResponse.json";
jest.mock("../../api/Api", () => ({
__esModule: true,
default: class Api {},
}));
// Mock the entire AppEngineFactory module
jest.mock("entities/Engine/factory", () => ({
__esModule: true,
default: class AppEngineFactory {
static create = jest.fn();
},
}));
describe("tests the sagas in initSagas", () => {
const action: ReduxAction<AppEnginePayload> = {
type: ReduxActionTypes.INITIALIZE_EDITOR,
payload: {
mode: APP_MODE.EDIT,
pageId: "pageId",
applicationId: "applicationId",
},
};
it("tests the order of execute in startAppEngine", () => {
const action = {
type: ReduxActionTypes.INITIALIZE_EDITOR,
payload: {
applicationId: "appId",
pageId: "pageId",
mode: APP_MODE.EDIT,
},
const engine = {
startPerformanceTracking: jest.fn(),
setupEngine: jest.fn(),
loadAppData: jest.fn().mockResolvedValue({
applicationId: action.payload.applicationId,
toLoadPageId: action.payload.pageId,
}),
loadAppURL: jest.fn(),
loadAppEntities: jest.fn(),
loadGit: jest.fn(),
completeChore: jest.fn(),
stopPerformanceTracking: jest.fn(),
};
const gen = startAppEngine(action);
const engine: AppEngine = AppEngineFactory.create(
APP_MODE.EDIT,
APP_MODE.EDIT,
);
expect(JSON.stringify(gen.next().value)).toStrictEqual(
JSON.stringify(call(engine.setupEngine, action.payload)),
);
expect(gen.next().value).toStrictEqual(
call(getInitResponses, action.payload),
);
const someInitResponse = {
pages: { responseMeta: {}, data: {}, code: "232" },
} as any;
(AppEngineFactory.create as jest.Mock).mockReturnValue(engine);
expect(JSON.stringify(gen.next(someInitResponse).value)).toStrictEqual(
JSON.stringify(
call(engine.loadAppData, action.payload, someInitResponse),
),
);
expect(
JSON.stringify(
gen.next({
applicationId: action.payload.applicationId,
toLoadPageId: action.payload.pageId,
} as any).value,
),
).toStrictEqual(
JSON.stringify(
call(engine.loadAppURL, action.payload.pageId, action.payload.pageId),
),
);
expect(JSON.stringify(gen.next().value)).toStrictEqual(
JSON.stringify(
call(
engine.loadAppEntities,
action.payload.pageId,
action.payload.applicationId,
someInitResponse,
),
),
);
expect(JSON.stringify(gen.next().value)).toStrictEqual(
JSON.stringify(call(engine.loadGit, action.payload.applicationId)),
);
expect(JSON.stringify(gen.next().value)).toStrictEqual(
JSON.stringify(call(engine.completeChore)),
);
testSaga(startAppEngine, action)
.next()
.call(engine.setupEngine, action.payload)
.next()
.call(getInitResponses, { ...action.payload })
.next(mockResponse.data)
.call(engine.loadAppData, action.payload, mockResponse.data)
.next({
applicationId: action.payload.applicationId,
toLoadPageId: action.payload.pageId,
})
.call(engine.loadAppURL, action.payload.pageId, action.payload.pageId)
.next()
.call(
engine.loadAppEntities,
action.payload.pageId,
action.payload.applicationId,
mockResponse.data,
)
.next()
.call(engine.loadGit, action.payload.applicationId)
.next()
.call(engine.completeChore)
.next()
.put(generateAutoHeightLayoutTreeAction(true, false))
.next()
.isDone();
});
});

View File

@ -0,0 +1,122 @@
{
"responseMeta": {
"status": 200,
"success": true
},
"data": {
"pageWithMigratedDsl": {
"responseMeta": {
"status": 200,
"success": true
},
"data": {
"id": "661c28791c2412092c170119",
"name": "Page1",
"slug": "page1",
"applicationId": "661c28791c2412092c170116",
"layouts": [
{
"dsl": {
"widgetName": "MainContainer",
"backgroundColor": "none",
"rightColumn": 4896,
"snapColumns": 64,
"detachFromLayout": true,
"widgetId": "0",
"topRow": 0,
"bottomRow": 380,
"containerStyle": "none",
"snapRows": 124,
"parentRowSpace": 1,
"type": "CANVAS_WIDGET",
"canExtend": true,
"version": 89,
"minHeight": 1292,
"dynamicTriggerPathList": [],
"parentColumnSpace": 1,
"dynamicBindingPathList": [],
"leftColumn": 0,
"children": [
{
"needsErrorInfo": false,
"mobileBottomRow": 12,
"widgetName": "Text1",
"displayName": "Text",
"iconSVG": "/static/media/icon.a55b701a2ae86aa2c6718ecb7b4083f0.svg",
"searchTags": ["typography", "paragraph", "label"],
"topRow": 8,
"bottomRow": 12,
"parentRowSpace": 10,
"type": "TEXT_WIDGET",
"hideCard": false,
"mobileRightColumn": 15,
"animateLoading": true,
"overflow": "NONE",
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
"parentColumnSpace": 16.390625,
"dynamicTriggerPathList": [],
"leftColumn": 0,
"dynamicBindingPathList": [
{
"key": "truncateButtonColor"
},
{
"key": "fontFamily"
},
{
"key": "borderRadius"
}
],
"shouldTruncate": false,
"truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}",
"text": "",
"key": "bz2lkn7wbc",
"isDeprecated": false,
"rightColumn": 15,
"thumbnailSVG": "/static/media/thumbnail.0c129b82c9b3e4cd4920563b289659ab.svg",
"textAlign": "LEFT",
"dynamicHeight": "AUTO_HEIGHT",
"widgetId": "xv30fhgoz3",
"minWidth": 450,
"isVisible": true,
"fontStyle": "BOLD",
"textColor": "#231F20",
"version": 1,
"parentId": "0",
"tags": ["Suggested", "Content"],
"renderMode": "CANVAS",
"isLoading": false,
"mobileTopRow": 8,
"responsiveBehavior": "fill",
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"mobileLeftColumn": 0,
"maxDynamicHeight": 9000,
"fontSize": "1rem",
"minDynamicHeight": 4
}
]
},
"layoutOnLoadActions": [],
"layoutOnLoadActionErrors": [],
"id": "661c28791c2412092c170117",
"userPermissions": []
}
],
"userPermissions": [
"create:moduleInstancesInPage",
"read:pages",
"manage:pages",
"create:pageActions",
"delete:pages"
],
"lastUpdatedTime": 1713194519,
"defaultResources": {
"applicationId": "661c28791c2412092c170116",
"pageId": "661c28791c2412092c170119"
}
},
"errorDisplay": ""
}
},
"errorDisplay": ""
}

View File

@ -13395,6 +13395,7 @@ __metadata:
redux-form: ^8.2.6
redux-mock-store: ^1.5.4
redux-saga: ^1.1.3
redux-saga-test-plan: ^4.0.6
remixicon-react: ^1.0.0
reselect: ^4.0.0
sass: ^1.70.0
@ -20055,6 +20056,13 @@ __metadata:
languageName: node
linkType: hard
"fsm-iterator@npm:^1.1.0":
version: 1.1.0
resolution: "fsm-iterator@npm:1.1.0"
checksum: ca35f89a6607df2542711faac62b4b9fdd1c90887bd7fbb0ed106d0d658a92376e996bdfc6db605665e25a63c510e5ea5986d054e3836becf95696ee928b0f6b
languageName: node
linkType: hard
"fsu@npm:^1.1.1":
version: 1.1.1
resolution: "fsu@npm:1.1.1"
@ -24138,6 +24146,13 @@ __metadata:
languageName: node
linkType: hard
"lodash.ismatch@npm:^4.4.0":
version: 4.4.0
resolution: "lodash.ismatch@npm:4.4.0"
checksum: a393917578842705c7fc1a30fb80613d1ac42d20b67eb26a2a6004d6d61ee90b419f9eb320508ddcd608e328d91eeaa2651411727eaa9a12534ed6ccb02fc705
languageName: node
linkType: hard
"lodash.isobject@npm:^3.0.2":
version: 3.0.2
resolution: "lodash.isobject@npm:3.0.2"
@ -30086,6 +30101,21 @@ __metadata:
languageName: node
linkType: hard
"redux-saga-test-plan@npm:^4.0.6":
version: 4.0.6
resolution: "redux-saga-test-plan@npm:4.0.6"
dependencies:
fsm-iterator: ^1.1.0
lodash.isequal: ^4.5.0
lodash.ismatch: ^4.4.0
peerDependencies:
"@redux-saga/is": ^1.0.1
"@redux-saga/symbols": ^1.0.1
redux-saga: ^1.0.1
checksum: a3220210a42a51271c0dc8740ceaacf5cd0aa84cf46b986d5839a89133de00954940e5dde80145e1b4c69d7c0d61b9578d86da8776d2c0b5151dc498bc595685
languageName: node
linkType: hard
"redux-saga@npm:^1.1.3":
version: 1.1.3
resolution: "redux-saga@npm:1.1.3"