chore: add unit test suites for partial export modal (#30260)
## Description
Added unit tests for the `EntityCheckboxSelector`,
`JSObjectsNQueriesExport`, `PartialExportModal`, and `WidgetsExport`
components to ensure proper rendering and interaction handling.
Refactor
Updated the WidgetsExport and `PartialExportModal` components with
additional props for improved testability.
**Sub component test suites**
` <WidgetsExport />
`
✓ renders the component with correct props
✓ handles "Select All" checkbox click
✓ handles "Select All" and widget click
✓ handles widget checkbox click
` <JSObjectsNQueriesExport />`
✓ renders the component with correct props
✓ toggles the query list when datasource is clicked
` <EntityCheckboxSelector />`
✓ renders the component with correct props
✓ checks the selected checkbox
✓ handles checkbox click
✓ handles checkbox uncheck
**Main Component Suite**
` <PartialExportModal />`
✓ renders the component with correct props
✓ resets JS objects after an item has been clicked
✓ resets Databases after an item has been clicked
✓ resets Queries after an item has been clicked
✓ resets Custom libraries after an item has been clicked
✓ resets Widgets after an item has been clicked
✓ triggers onExportClick with correct action and payload
#### PR fixes following issue(s)
Fixes #30028
#### Type of change
> Please delete options that are not relevant.
- New feature (non-breaking change which adds functionality)
## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [ ] Manual
- [ ] JUnit
- [x] Jest
- [ ] Cypress
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag
#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Tests**
- Added unit tests for the `EntityCheckboxSelector`,
`JSObjectsNQueriesExport`, `PartialExportModal`, and `WidgetsExport`
components to ensure proper rendering and interaction handling.
- **Refactor**
- Updated the `WidgetsExport` and `PartialExportModal` components with
additional props for improved testability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
891d766030
commit
4bd46aee2b
|
|
@ -0,0 +1,41 @@
|
|||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import EntityCheckboxSelector from "./EntityCheckboxSelector";
|
||||
|
||||
describe("<EntityCheckboxSelector />", () => {
|
||||
const baseProps = {
|
||||
entities: [
|
||||
{ id: "1", name: "Entity1" },
|
||||
{ id: "2", name: "Entity2" },
|
||||
],
|
||||
onEntityChecked: jest.fn(),
|
||||
selectedIds: ["1"],
|
||||
};
|
||||
|
||||
it("renders the component with correct props", () => {
|
||||
render(<EntityCheckboxSelector {...baseProps} />);
|
||||
expect(screen.getByText("Entity1")).toBeInTheDocument();
|
||||
expect(screen.getByText("Entity2")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("checks the selected checkbox", () => {
|
||||
render(<EntityCheckboxSelector {...baseProps} />);
|
||||
const entityCheckbox = screen.getByLabelText("Entity1");
|
||||
expect(entityCheckbox).toBeChecked();
|
||||
});
|
||||
|
||||
it("handles checkbox click", () => {
|
||||
render(<EntityCheckboxSelector {...baseProps} />);
|
||||
const entityCheckbox = screen.getByLabelText("Entity2");
|
||||
fireEvent.click(entityCheckbox);
|
||||
expect(baseProps.onEntityChecked).toHaveBeenCalledWith("2", true);
|
||||
});
|
||||
|
||||
it("handles checkbox uncheck", () => {
|
||||
render(<EntityCheckboxSelector {...baseProps} />);
|
||||
const entityCheckbox = screen.getByLabelText("Entity1");
|
||||
fireEvent.click(entityCheckbox);
|
||||
expect(baseProps.onEntityChecked).toHaveBeenCalledWith("1", false);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import JSObjectsNQueriesExport from "./JSObjectsNQueriesExport";
|
||||
import { lightTheme } from "selectors/themeSelectors";
|
||||
import { mockAppDSProps, mockDataBaseProps } from "./unitTestUtils";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
|
||||
jest.mock("react-redux", () => {
|
||||
const originalModule = jest.requireActual("react-redux");
|
||||
return {
|
||||
...originalModule,
|
||||
useDispatch: () => jest.fn(),
|
||||
useSelector: () => jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const baseProps = {
|
||||
appDS: mockAppDSProps,
|
||||
data: mockDataBaseProps,
|
||||
selectedQueries: [],
|
||||
updateSelectedQueries: jest.fn(),
|
||||
};
|
||||
|
||||
const BaseComponentRender = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<JSObjectsNQueriesExport {...baseProps} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
describe("<JSObjectsNQueriesExport />", () => {
|
||||
it("renders the component with correct props", () => {
|
||||
render(<BaseComponentRender />);
|
||||
const moviesDatabase = screen.getByText("Movies");
|
||||
expect(moviesDatabase).toBeInTheDocument();
|
||||
const usersDatabase = screen.getByText("users");
|
||||
expect(usersDatabase).toBeInTheDocument();
|
||||
const moviesQuery = screen.getByText("Query1");
|
||||
expect(moviesQuery).toBeInTheDocument();
|
||||
const usersQuery = screen.getByText("getUsers");
|
||||
expect(usersQuery).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("toggles the query list when datasource is clicked", () => {
|
||||
render(<BaseComponentRender />);
|
||||
const moviesDatasource = screen.getByText("Movies");
|
||||
fireEvent.click(moviesDatasource);
|
||||
expect(screen.getByText("Query1")).not.toBeVisible();
|
||||
fireEvent.click(moviesDatasource);
|
||||
expect(screen.getByText("Query1")).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
import React from "react";
|
||||
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import PartialExportModal from "./index";
|
||||
import { lightTheme } from "selectors/themeSelectors";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
import configureStore from "redux-mock-store";
|
||||
import { Provider } from "react-redux";
|
||||
import { defaultAppState } from "./unitTestUtils";
|
||||
import {
|
||||
PARTIAL_IMPORT_EXPORT,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
|
||||
interface TestEntityResetProps {
|
||||
entityTitle: string;
|
||||
entityItemTitle: string;
|
||||
}
|
||||
|
||||
const mockStore = configureStore([]);
|
||||
|
||||
jest.mock("pages/Editor/Explorer/Widgets/WidgetIcon", () => ({
|
||||
__esModule: true,
|
||||
default: () => <div />,
|
||||
}));
|
||||
|
||||
describe("<PartialExportModal />", () => {
|
||||
let store: any;
|
||||
|
||||
beforeEach(() => {
|
||||
store = mockStore(defaultAppState);
|
||||
});
|
||||
|
||||
const BaseComponentRender = () => (
|
||||
<Provider store={store}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<PartialExportModal handleModalClose={() => jest.fn()} isModalOpen />
|
||||
</ThemeProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const testEntityReset = (props: TestEntityResetProps) => {
|
||||
const entityResetTestId = `t--partial-export-modal-reset-${props.entityTitle}`;
|
||||
const entity = screen.getByText(props.entityTitle);
|
||||
const entityItem = screen.getByLabelText(props.entityItemTitle);
|
||||
const exportButton = screen.getByTestId("t-partial-export-entities-btn");
|
||||
|
||||
expect(screen.queryByTestId(entityResetTestId)).not.toBeInTheDocument();
|
||||
fireEvent.click(entity);
|
||||
fireEvent.click(entityItem);
|
||||
expect(screen.getByTestId(entityResetTestId)).toBeInTheDocument();
|
||||
expect(exportButton).not.toBeDisabled();
|
||||
fireEvent.click(screen.getByTestId(entityResetTestId));
|
||||
expect(screen.getByLabelText(props.entityItemTitle)).not.toBeChecked();
|
||||
expect(screen.queryByTestId(entityResetTestId)).not.toBeInTheDocument();
|
||||
expect(exportButton).toBeDisabled();
|
||||
};
|
||||
|
||||
it("renders the component with correct props", () => {
|
||||
render(<BaseComponentRender />);
|
||||
const pageList = defaultAppState.entities.pageList;
|
||||
const currentPageName = pageList.pages.find(
|
||||
(page: any) => page.pageId === pageList.currentPageId,
|
||||
)?.pageName;
|
||||
expect(screen.getByText(`Export - ${currentPageName}`)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.modalSubHeading),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.sections.jsObjects),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.sections.databases),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.sections.queries),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.sections.customLibs),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.sections.widgets),
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect;
|
||||
expect(
|
||||
screen.getByText(createMessage(PARTIAL_IMPORT_EXPORT.export.cta)),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByTestId("t-partial-export-entities-btn")).toBeDisabled();
|
||||
});
|
||||
|
||||
it("resets JS objects after an item has been clicked", () => {
|
||||
render(<BaseComponentRender />);
|
||||
testEntityReset({
|
||||
entityTitle: createMessage(
|
||||
PARTIAL_IMPORT_EXPORT.export.sections.jsObjects,
|
||||
),
|
||||
entityItemTitle: "JSObject1",
|
||||
});
|
||||
});
|
||||
|
||||
it("resets Databases after an item has been clicked", () => {
|
||||
render(<BaseComponentRender />);
|
||||
testEntityReset({
|
||||
entityTitle: createMessage(
|
||||
PARTIAL_IMPORT_EXPORT.export.sections.databases,
|
||||
),
|
||||
entityItemTitle: "Movies",
|
||||
});
|
||||
});
|
||||
|
||||
it("resets Queries after an item has been clicked", () => {
|
||||
render(<BaseComponentRender />);
|
||||
testEntityReset({
|
||||
entityTitle: createMessage(PARTIAL_IMPORT_EXPORT.export.sections.queries),
|
||||
entityItemTitle: "Query1",
|
||||
});
|
||||
});
|
||||
|
||||
it("resets Custom libraries after an item has been clicked", () => {
|
||||
render(<BaseComponentRender />);
|
||||
testEntityReset({
|
||||
entityTitle: createMessage(
|
||||
PARTIAL_IMPORT_EXPORT.export.sections.customLibs,
|
||||
),
|
||||
entityItemTitle: "jspdf",
|
||||
});
|
||||
});
|
||||
|
||||
it("resets Widgets after an item has been clicked", () => {
|
||||
render(<BaseComponentRender />);
|
||||
testEntityReset({
|
||||
entityTitle: createMessage(PARTIAL_IMPORT_EXPORT.export.sections.widgets),
|
||||
entityItemTitle: "txt_userFullName",
|
||||
});
|
||||
});
|
||||
|
||||
it("triggers onExportClick with correct action and payload", async () => {
|
||||
render(<BaseComponentRender />);
|
||||
const exportButton = screen.getByTestId("t-partial-export-entities-btn");
|
||||
const jsObjectsEntity = screen.getByText(
|
||||
createMessage(PARTIAL_IMPORT_EXPORT.export.sections.jsObjects),
|
||||
);
|
||||
const jsObjectsEntityItem = screen.getByLabelText(
|
||||
defaultAppState.entities.jsActions[0].config.name,
|
||||
);
|
||||
const jsObjectsEntityItemId =
|
||||
defaultAppState.entities.jsActions[0].config.id;
|
||||
|
||||
fireEvent.click(jsObjectsEntity);
|
||||
fireEvent.click(jsObjectsEntityItem);
|
||||
fireEvent.click(exportButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(store.getActions()).toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
type: ReduxActionTypes.PARTIAL_EXPORT_INIT,
|
||||
payload: {
|
||||
jsObjects: [jsObjectsEntityItemId],
|
||||
datasources: [],
|
||||
customJSLibs: [],
|
||||
widgets: [],
|
||||
queries: [],
|
||||
},
|
||||
},
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import WidgetsExport from "./WidgetsExport";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
import { lightTheme } from "selectors/themeSelectors";
|
||||
import {
|
||||
getAllWidgetIds,
|
||||
mockTblUserInfoWidgetId,
|
||||
mockWidgetsProps,
|
||||
} from "./unitTestUtils";
|
||||
|
||||
jest.mock("pages/Editor/Explorer/Widgets/WidgetIcon", () => ({
|
||||
__esModule: true,
|
||||
default: () => <div />,
|
||||
}));
|
||||
|
||||
describe("<WidgetsExport />", () => {
|
||||
const baseProps = {
|
||||
selectAllchecked: false,
|
||||
selectedWidgetIds: [],
|
||||
updateSelectAllChecked: jest.fn(),
|
||||
updateSelectedWidgets: jest.fn(),
|
||||
};
|
||||
|
||||
const BaseComponentRender = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<WidgetsExport {...baseProps} widgets={mockWidgetsProps} />
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
it("renders the component with correct props", () => {
|
||||
render(<BaseComponentRender />);
|
||||
expect(screen.getByText("Select All")).toBeInTheDocument();
|
||||
expect(screen.getByText("tbl_userInfo")).toBeInTheDocument();
|
||||
expect(screen.getByText("txt_pageTitle")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles "Select All" checkbox click', () => {
|
||||
render(<BaseComponentRender />);
|
||||
const widgetIds = getAllWidgetIds(mockWidgetsProps);
|
||||
const selectAllCheckbox = screen.getByTestId(
|
||||
"t--partial-export-modal-widget-select-all",
|
||||
);
|
||||
fireEvent.click(selectAllCheckbox!);
|
||||
expect(baseProps.updateSelectAllChecked).toHaveBeenCalledWith(true);
|
||||
expect(baseProps.updateSelectedWidgets).toHaveBeenCalledWith(
|
||||
widgetIds.slice(1),
|
||||
);
|
||||
});
|
||||
|
||||
it('handles "Select All" and widget click', () => {
|
||||
render(<BaseComponentRender />);
|
||||
const widgetIds = getAllWidgetIds(mockWidgetsProps);
|
||||
const selectAllCheckbox = screen.getByTestId(
|
||||
"t--partial-export-modal-widget-select-all",
|
||||
);
|
||||
const widgetCheckbox = screen.getByTestId(
|
||||
`t--partial-export-modal-widget-select-${mockTblUserInfoWidgetId}`,
|
||||
);
|
||||
fireEvent.click(selectAllCheckbox!);
|
||||
expect(baseProps.updateSelectAllChecked).toHaveBeenCalledWith(true);
|
||||
expect(baseProps.updateSelectedWidgets).toHaveBeenCalledWith(
|
||||
widgetIds.slice(1),
|
||||
);
|
||||
fireEvent.click(widgetCheckbox);
|
||||
expect(selectAllCheckbox).not.toBeChecked();
|
||||
expect(widgetCheckbox).not.toBeChecked();
|
||||
});
|
||||
|
||||
it("handles widget checkbox click", () => {
|
||||
render(<WidgetsExport {...baseProps} widgets={mockWidgetsProps} />);
|
||||
const widgetCheckbox = screen.getByTestId(
|
||||
`t--partial-export-modal-widget-select-${mockTblUserInfoWidgetId}`,
|
||||
);
|
||||
fireEvent.click(widgetCheckbox);
|
||||
expect(baseProps.updateSelectedWidgets).toHaveBeenCalledWith([
|
||||
mockTblUserInfoWidgetId,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
@ -80,9 +80,13 @@ function WidgetSelector({
|
|||
) {
|
||||
const isSelected = selectedWidgetIds.includes(widget.widgetId);
|
||||
return (
|
||||
<div style={{ marginLeft: level > 0 ? level + 8 : level }}>
|
||||
<div
|
||||
key={widget.widgetId}
|
||||
style={{ marginLeft: level > 0 ? level + 8 : level }}
|
||||
>
|
||||
<CheckboxContainer>
|
||||
<Checkbox
|
||||
data-testid={`t--partial-export-modal-widget-select-${widget.widgetId}`}
|
||||
isDisabled={isParentSelected}
|
||||
isSelected={isSelected}
|
||||
onChange={(checked) => toggleNode(widget, checked)}
|
||||
|
|
@ -113,6 +117,7 @@ function WidgetSelector({
|
|||
<CheckboxWrapper>
|
||||
<Checkbox
|
||||
className="mb-4"
|
||||
data-testid="t--partial-export-modal-widget-select-all"
|
||||
isSelected={selectAllchecked}
|
||||
onChange={handleSelectAllClick}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ const PartiaExportModel = ({ handleModalClose, isModalOpen }: Props) => {
|
|||
<ScrollableSection>
|
||||
{entities.map(
|
||||
({ content, icon, onResetClick, shouldShowReset, title }) => (
|
||||
<>
|
||||
<React.Fragment key={title}>
|
||||
<Collapsible className="mt-4" key={title}>
|
||||
<CollapsibleHeader>
|
||||
<div className="w-full flex justify-between">
|
||||
|
|
@ -291,6 +291,7 @@ const PartiaExportModel = ({ handleModalClose, isModalOpen }: Props) => {
|
|||
{shouldShowReset && (
|
||||
<Button
|
||||
className="mr-2"
|
||||
data-testid={`t--partial-export-modal-reset-${title}`}
|
||||
endIcon="restart-line"
|
||||
kind="tertiary"
|
||||
onClick={onResetClick}
|
||||
|
|
@ -304,12 +305,13 @@ const PartiaExportModel = ({ handleModalClose, isModalOpen }: Props) => {
|
|||
<CollapsibleContent>{content}</CollapsibleContent>
|
||||
</Collapsible>
|
||||
<Bar />
|
||||
</>
|
||||
</React.Fragment>
|
||||
),
|
||||
)}
|
||||
</ScrollableSection>
|
||||
<ModalFooter>
|
||||
<Button
|
||||
data-testid="t-partial-export-entities-btn"
|
||||
isDisabled={disableExportCTA}
|
||||
isLoading={partialImportExportLoadingState.isExporting}
|
||||
onClick={onExportClick}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user