diff --git a/package.json b/package.json index c82737b9c3..57abecce44 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "monday-ui-react-core", - "version": "0.3.59", + "version": "0.3.60", "description": "Official monday.com UI resources for application development in React.js", "main": "dist/main.js", "scripts": { diff --git a/src/components/Toast/Toast.jsx b/src/components/Toast/Toast.jsx index 674fbdda38..10c65b470d 100644 --- a/src/components/Toast/Toast.jsx +++ b/src/components/Toast/Toast.jsx @@ -4,12 +4,14 @@ import PropTypes from "prop-types"; import cx from "classnames"; import { CSSTransition } from "react-transition-group"; import Button from "../Button/Button"; +import ToastLink from "./ToastLink/ToastLink"; +import ToastButton from "./ToastButton/ToastButton"; import Icon from "../Icon/Icon"; import Check from "../Icon/Icons/components/Check"; import Alert from "../Icon/Icons/components/Alert"; import Info from "../Icon/Icons/components/Info"; import CloseSmall from "../Icon/Icons/components/CloseSmall"; -import { TOAST_TYPES } from "./ToastConstants"; +import { TOAST_TYPES, TOAST_ACTION_TYPES } from "./ToastConstants"; import "./Toast.scss"; const defaultIconMap = { @@ -33,7 +35,34 @@ const getIcon = (type, icon) => { /> ) : null; }; -const Toast = ({ open, autoHideDuration, type, icon, hideIcon, action, children, closeable, onClose, className }) => { + +const Toast = ({ + open, + autoHideDuration, + type, + icon, + hideIcon, + action: deprecatedAction, + actions, + children, + closeable, + onClose, + className +}) => { + const toastLinks = useMemo(() => { + return actions + ? actions + .filter(action => action.type === TOAST_ACTION_TYPES.LINK) + .map(({ type, ...otherProps }) => ) + : null; + }, [actions]); + const toastButtons = useMemo(() => { + return actions + ? actions + .filter(action => action.type === TOAST_ACTION_TYPES.BUTTON) + .map(({ type, content, ...otherProps }) => {content} ) + : null; + }, [actions]); const classNames = useMemo(() => cx("monday-style-toast", `monday-style-toast--type-${type}`, className), [type]); const handleClose = useCallback(() => { if (onClose) { @@ -76,8 +105,11 @@ const Toast = ({ open, autoHideDuration, type, icon, hideIcon, action, children, })} > {children} + {toastLinks} - {action &&
{action}
} + {(toastButtons || deprecatedAction) && ( +
{toastButtons || deprecatedAction}
+ )} {closeable && ( + closeToastLink()} @@ -86,9 +84,9 @@ export const Sandbox = () => { closeable={knobs.closeable} autoHideDuration={knobs.autoHideDuration} hideIcon={knobs.hideIcon} + actions={[{ type: Toast.actionTypes.LINK, text: "Lorem ipsum", href: "https://monday.com" }]} > Something Happened - @@ -96,15 +94,17 @@ export const Sandbox = () => { closeToastLinkButton()} - action={Undo 5} type={knobs.type} icon={icon} closeable={knobs.closeable} autoHideDuration={knobs.autoHideDuration} hideIcon={knobs.hideIcon} + actions={[ + { type: Toast.actionTypes.LINK, text: "Lorem ipsum", href: "https://monday.com" }, + { type: Toast.actionTypes.BUTTON, content: "Undo 5" } + ]} > Something Happened - diff --git a/src/components/Toast/__tests__/__snapshots__/toast.jest.js.snap b/src/components/Toast/__tests__/__snapshots__/toast.jest.js.snap new file mode 100644 index 0000000000..f446a72e0a --- /dev/null +++ b/src/components/Toast/__tests__/__snapshots__/toast.jest.js.snap @@ -0,0 +1,367 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Toast tests Snapshot Tests don't renders close button if closeable=false 1`] = ` +
+
+ +
+
+ Something Happened +
+
+`; + +exports[`Toast tests Snapshot Tests renders correctly (renders nothing) with empty props 1`] = `null`; + +exports[`Toast tests Snapshot Tests renders correctly with button 1`] = ` +
+
+ +
+
+ Something Happened +
+
+ +
+ +
+`; + +exports[`Toast tests Snapshot Tests renders correctly with button and link 1`] = ` +
+
+ +
+
+ Something Happened + + + Lorem ipsum + + +
+
+ +
+ +
+`; + +exports[`Toast tests Snapshot Tests renders correctly with link 1`] = ` +
+
+ +
+
+ Something Happened + + + Lorem ipsum + + +
+
+ +
+`; + +exports[`Toast tests Snapshot Tests renders nothing when open is false 1`] = `null`; + +exports[`Toast tests Snapshot Tests renders toast when open is true 1`] = ` +
+
+ +
+
+ Something Happened +
+ +
+`; diff --git a/src/components/Toast/__tests__/toast.jest.js b/src/components/Toast/__tests__/toast.jest.js index 932d972d26..891729ef99 100644 --- a/src/components/Toast/__tests__/toast.jest.js +++ b/src/components/Toast/__tests__/toast.jest.js @@ -2,62 +2,113 @@ import React from "react"; import { fireEvent, render, cleanup } from "@testing-library/react"; import { act } from "@testing-library/react-hooks"; import Toast from "../Toast"; +import renderer from "react-test-renderer"; +import { Checkbox } from "../../Checkbox/Checkbox"; jest.useFakeTimers(); const renderComponent = ({ ...props } = {}, contenct = "") => { return render({contenct}); }; +describe("Toast tests", () => { + describe("Snapshot Tests", () => { + it("renders correctly (renders nothing) with empty props", () => { + const tree = renderer.create().toJSON(); + expect(tree).toMatchSnapshot(); + }); -describe("", () => { - afterEach(() => { - cleanup(); - }); - - it("renders nothing when open=false", () => { - const toast = renderComponent({}, "text"); - expect(toast.queryByText("text")).toBeNull(); - }); - - it("renders toast when open=true", () => { - const toast = renderComponent({ open: true }, "text"); - expect(toast.queryByText("text")).not.toBeNull(); - }); + it("renders nothing when open is false", () => { + const tree = renderer.create(Something Happened).toJSON(); + expect(tree).toMatchSnapshot(); + }); - it("rendres action", () => { - const action =
my action
; - const toast = renderComponent({ open: true, action }, "text"); - expect(toast.queryByText("my action")).not.toBeNull(); - }); + it("renders toast when open is true", () => { + const tree = renderer.create(Something Happened).toJSON(); + expect(tree).toMatchSnapshot(); + }); - it("don't renders close button if closeable=false", () => { - const toast = renderComponent({ open: true, closeable: false }, "text"); - expect(toast.queryByLabelText("close-toast")).toBeNull(); - }); + it("don't renders close button if closeable=false", () => { + const tree = renderer + .create( + + Something Happened + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); - it("calls onClose when click on close button", () => { - const onCloseMock = jest.fn(); - const toast = renderComponent({ - open: true, - onClose: onCloseMock + it("renders correctly with button", () => { + const tree = renderer + .create( + + Something Happened + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); }); - const closeButton = toast.getByLabelText("close-toast"); - act(() => { - fireEvent.click(closeButton); + it("renders correctly with link", () => { + const tree = renderer + .create( + + Something Happened + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); }); - expect(onCloseMock.mock.calls.length).toBe(1); + it("renders correctly with button and link", () => { + const tree = renderer + .create( + + Something Happened + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); }); + describe("Integration Tests", () => { + afterEach(() => { + cleanup(); + }); + + it("calls onClose when click on close button", () => { + const onCloseMock = jest.fn(); + const toast = renderComponent({ + open: true, + onClose: onCloseMock + }); + const closeButton = toast.getByLabelText("close-toast"); + + act(() => { + fireEvent.click(closeButton); + }); + + expect(onCloseMock.mock.calls.length).toBe(1); + }); - it("calls onClose after 1S when autoHideDuration=1000", () => { - const onCloseMock = jest.fn(); - renderComponent({ - onClose: onCloseMock, - autoHideDuration: 1000, - open: true + it("calls onClose after 1S when autoHideDuration=1000", () => { + const onCloseMock = jest.fn(); + renderComponent({ + onClose: onCloseMock, + autoHideDuration: 1000, + open: true + }); + jest.advanceTimersByTime(1000); + expect(onCloseMock.mock.calls.length).toBe(1); }); - jest.advanceTimersByTime(1000); - expect(onCloseMock.mock.calls.length).toBe(1); }); });