diff --git a/app/client/jest.config.js b/app/client/jest.config.js index fee6632cf0..fa67b59307 100644 --- a/app/client/jest.config.js +++ b/app/client/jest.config.js @@ -1,14 +1,15 @@ module.exports = { roots: ["/src"], transform: { - "^.+\\.(ts|tsx)$": "ts-jest", + "^.+\\.(png|js|ts|tsx)$": "ts-jest", }, testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"], moduleDirectories: ["node_modules", "src"], - transformIgnorePatterns: ["/node_modules/(?!codemirror)"], + transformIgnorePatterns: ["/node_modules/(?!codemirror|react-dnd|dnd-core|@babel)"], moduleNameMapper: { "\\.(css|less)$": "/test/__mocks__/styleMock.js", "\\.svg$": "/test/__mocks__/svgMock.js", + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/test/__mocks__/fileMock.js", }, }; diff --git a/app/client/package.json b/app/client/package.json index 9b7cd05f65..54d6b7f8bb 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -158,6 +158,8 @@ "@storybook/addons": "^5.3.19", "@storybook/preset-create-react-app": "^3.1.4", "@storybook/react": "^5.3.19", + "@testing-library/jest-dom": "^5.11.4", + "@testing-library/react": "^11.0.4", "@types/codemirror": "^0.0.96", "@types/downloadjs": "^1.4.2", "@types/jest": "^24.0.22", @@ -165,6 +167,7 @@ "@types/react-select": "^3.0.5", "@types/react-tabs": "^2.3.1", "@types/redux-form": "^8.1.9", + "@types/redux-mock-store": "^1.0.2", "@types/styled-system": "^5.1.9", "@types/tern": "0.22.0", "@types/toposort": "^2.0.3", @@ -192,6 +195,7 @@ "react-test-renderer": "^16.11.0", "redux-devtools": "^3.5.0", "redux-devtools-extension": "^2.13.8", + "redux-mock-store": "^1.5.4", "source-map-explorer": "^2.4.2", "storybook-addon-designs": "^5.4.0", "ts-jest": "^24.3.0", diff --git a/app/client/src/components/designSystems/appsmith/ImageComponent.tsx b/app/client/src/components/designSystems/appsmith/ImageComponent.tsx index af7151e191..b05a024cad 100644 --- a/app/client/src/components/designSystems/appsmith/ImageComponent.tsx +++ b/app/client/src/components/designSystems/appsmith/ImageComponent.tsx @@ -48,6 +48,7 @@ class ImageComponent extends React.Component< className={this.props.isLoading ? "bp3-skeleton" : ""} imageError={this.state.imageError} {...this.props} + data-testid="styledImage" > ({ + useDrag: jest.fn().mockReturnValue([{ isDragging: false }, jest.fn()]), +})); + +describe("", () => { + const initialState = { + ui: { + widgetDragResize: { + selectedWidget: "", + }, + propertyPane: { + isVisible: true, + widgetId: "Widget1", + }, + }, + entities: { canvasWidgets: {} }, + }; + + function renderImageWidget(props: Partial = {}) { + const defaultProps: ImageWidgetProps = { + image: "", + defaultImage: "", + widgetId: "Widget1", + type: "IMAGE_WIDGET", + widgetName: "Image1", + parentId: "Container1", + renderMode: "CANVAS", + parentColumnSpace: 2, + parentRowSpace: 3, + leftColumn: 2, + rightColumn: 3, + topRow: 1, + bottomRow: 3, + isLoading: false, + imageShape: "RECTANGLE", + onClick: "", + }; + // Mock store to bypass the error of react-redux + const store = configureStore()(initialState); + return render( + + + + + , + ); + } + + const yellow = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="; + const red = + " iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg== "; + + test("should be empty when image and defaultImage both are empty.", async () => { + const { queryByTestId } = renderImageWidget({ + image: "", + defaultImage: "", + }); + + expect(queryByTestId("styledImage")).toHaveStyle( + `background-image: url("")`, + ); + }); + + test("should display image when image and defaultImage both are present.", async () => { + const props = { image: yellow, defaultImage: red }; + const { queryByTestId } = renderImageWidget(props); + + expect(queryByTestId("styledImage")).toHaveStyle( + `background-image: url(${props.image})`, + ); + }); + + test("should display image when image is present and defaultImage is absent.", async () => { + const props = { image: yellow, defaultImage: undefined }; + const { queryByTestId } = renderImageWidget(props); + + expect(queryByTestId("styledImage")).toHaveStyle( + `background-image: url(${props.image})`, + ); + }); + + test("should display defaultImage when image is absent and defaultImage is present.", async () => { + const props = { image: "", defaultImage: red }; + const { container, queryByTestId } = renderImageWidget(props); + + // Fire onError event manually to update the background-image. + const imageElement = container.querySelector("img") as Element; + expect(imageElement).toBeInTheDocument(); + fireEvent(imageElement, new Event("error")); + + expect(queryByTestId("styledImage")).toHaveStyle( + `background-image: url(${props.defaultImage})`, + ); + }); + + test("should display defaultImage when image is given a var with no value and defaultImage is present.", async () => { + const dynamicProperty = undefined; + const props = { image: dynamicProperty, defaultImage: red }; + const { container, queryByTestId } = renderImageWidget(props); + + // Fire onError event manually to update the background-image. + // For src as `undefined`, the browser doesn't trigger the onError event automatically. + const imageElement = container.querySelector("img") as Element; + expect(imageElement).toBeInTheDocument(); + fireEvent(imageElement, new Event("error")); + + expect(queryByTestId("styledImage")).toHaveStyle( + `background-image: url(${props.defaultImage})`, + ); + }); +}); diff --git a/app/client/src/widgets/ImageWidget.tsx b/app/client/src/widgets/ImageWidget.tsx index 9b76dbc333..edaf220782 100644 --- a/app/client/src/widgets/ImageWidget.tsx +++ b/app/client/src/widgets/ImageWidget.tsx @@ -33,7 +33,7 @@ class ImageWidget extends BaseWidget { return (