Skip to content

Commit

Permalink
Merge pull request #47 from almond-bongbong/feature/upgrade-module
Browse files Browse the repository at this point in the history
Feature/upgrade module
  • Loading branch information
almond-bongbong authored May 26, 2023
2 parents 731b3c9 + ce97193 commit 09c1665
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 144 deletions.
35 changes: 18 additions & 17 deletions __tests__/create-toast.test.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
import { clearToasts, createToast } from '../src';
import { createToast } from '../src';
import { ToastPosition } from '../src/lib/constants';
import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import { act, screen, waitForElementToBeRemoved } from '@testing-library/react';

const EXIT_ANIMATION_DURATION = 310;

describe('createToast', () => {
afterEach(() => {
clearToasts();
});

it('allows creating custom toast instances with specified classNames and overriding className', () => {
it('allows creating custom toast instances with specified classNames and overriding className', async () => {
const TOAST_TEXT = 'Hello Message';
const TOAST_CLASSNAME = 'my-toast';
const myToast = createToast({
className: TOAST_CLASSNAME,
});
myToast(TOAST_TEXT);
await act(() => myToast(TOAST_TEXT));

const toastElement = screen.getByText(TOAST_TEXT);
expect(toastElement.parentElement).toHaveClass(TOAST_CLASSNAME);

const TOAST_TEXT_2 = 'Hello Message 2';
const TOAST_CLASSNAME_2 = 'my-toast-2';
myToast(TOAST_TEXT_2, { className: TOAST_CLASSNAME_2 });
await act(() => myToast(TOAST_TEXT_2, { className: TOAST_CLASSNAME_2 }));

const overridenClassnameToastElement = screen.getByText(TOAST_TEXT_2);
expect(overridenClassnameToastElement.parentElement).toHaveClass(
Expand All @@ -36,7 +32,7 @@ describe('createToast', () => {
const myToast = createToast({
duration: DURATION,
});
myToast(TOAST_TEXT);
await act(() => myToast(TOAST_TEXT));

const toastElement = screen.getByText(TOAST_TEXT);
await waitForElementToBeRemoved(toastElement, {
Expand All @@ -45,28 +41,28 @@ describe('createToast', () => {

const TOAST_TEXT_2 = 'message for duration 2';
const DURATION_2 = 500;
myToast(TOAST_TEXT_2, { duration: DURATION_2 });
await act(() => myToast(TOAST_TEXT_2, { duration: DURATION_2 }));

const toastElement2 = screen.getByText(TOAST_TEXT_2);
await waitForElementToBeRemoved(toastElement2, {
timeout: DURATION_2 + EXIT_ANIMATION_DURATION,
});
});

it('allows creating custom toast instances with specified positions and overriding position', () => {
it('allows creating custom toast instances with specified positions and overriding position', async () => {
const TOAST_TEXT = 'message for position';
const POSITION = ToastPosition.TOP_LEFT;
const myToast = createToast({
position: POSITION,
});
myToast(TOAST_TEXT);
await act(() => myToast(TOAST_TEXT));

const toastElement = screen.getByText(TOAST_TEXT);
expect(toastElement.parentElement?.parentElement).toHaveClass(POSITION);

const TOAST_TEXT_2 = 'message for position 2';
const POSITION_2 = ToastPosition.BOTTOM_RIGHT;
myToast(TOAST_TEXT_2, { position: POSITION_2 });
await act(() => myToast(TOAST_TEXT_2, { position: POSITION_2 }));

const overridenPositionToastElement = screen.getByText(TOAST_TEXT_2);
expect(
Expand All @@ -80,15 +76,20 @@ describe('createToast', () => {
clickClosable: true,
});
const onCloseStart = jest.fn();
myToast(TOAST_TEXT, { onCloseStart });
await act(() => myToast(TOAST_TEXT, { onCloseStart }));

const toastElement = screen.getByText(TOAST_TEXT);
toastElement.click();
await act(() => toastElement.click());
expect(onCloseStart).toHaveBeenCalled();

const TOAST_TEXT_2 = 'message for clickClosable 2';
const onCloseStart2 = jest.fn();
myToast(TOAST_TEXT_2, { clickClosable: false, onCloseStart: onCloseStart2 });
await act(() =>
myToast(TOAST_TEXT_2, {
clickClosable: false,
onCloseStart: onCloseStart2,
}),
);

const overridenClickClosableToastElement = screen.getByText(TOAST_TEXT_2);
overridenClickClosableToastElement.click();
Expand Down
65 changes: 35 additions & 30 deletions __tests__/toast.test.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
import React from 'react';
import {
act,
render,
screen,
waitFor,
waitForElementToBeRemoved,
} from '@testing-library/react';
import toast, { clearToasts } from '../src';
import toast from '../src';

const EXIT_ANIMATION_DURATION = 310;

describe('toast', () => {
afterEach(() => {
clearToasts();
});

it('renders a toast when the show button is clicked', () => {
it('renders a toast when the show button is clicked', async () => {
const TOAST_TEXT = 'Hello Message';
render(
<button type="button" onClick={() => toast(TOAST_TEXT)}>
show
</button>,
);

const button = screen.getByText('show');
button.click();
await act(() => button.click());

screen.getByText(TOAST_TEXT);
});

it('displays the toast for the specified duration and then removes it', async () => {
const TOAST_TEXT = 'message for duration';
const DURATION = 500;
toast(TOAST_TEXT, DURATION);
await act(() => toast(TOAST_TEXT, DURATION));

const toastElement = screen.getByText(TOAST_TEXT);
await waitForElementToBeRemoved(toastElement, {
Expand All @@ -39,10 +38,10 @@ describe('toast', () => {

it('renders toast with infinite duration until manually closed', async () => {
const TOAST_TEXT = 'message for infinity duration';
const infiniteToast = toast(TOAST_TEXT, Infinity);
const infiniteToast = await act(() => toast(TOAST_TEXT, Infinity));

const toastElement = screen.getByText(TOAST_TEXT);
infiniteToast.close();
await act(() => infiniteToast.close());
await waitForElementToBeRemoved(toastElement, {
timeout: EXIT_ANIMATION_DURATION,
});
Expand All @@ -51,45 +50,49 @@ describe('toast', () => {
it('renders and removes toast based on specified duration in options', async () => {
const TOAST_TEXT = 'message for duration with options';
const DURATION = 500;
toast(TOAST_TEXT, { duration: DURATION });
await act(() => toast(TOAST_TEXT, { duration: DURATION }));

const toastElement = screen.getByText(TOAST_TEXT);
await waitForElementToBeRemoved(toastElement, {
timeout: DURATION + EXIT_ANIMATION_DURATION,
});
});

it('applies custom className to toast container', () => {
it('applies custom className to toast container', async () => {
const TOAST_TEXT = 'message for classname';
const CLASSNAME = 'test-classname';
toast(TOAST_TEXT, { className: CLASSNAME });
await act(() => toast(TOAST_TEXT, { className: CLASSNAME }));

const toastDOM = screen.getByText(TOAST_TEXT);
expect(toastDOM.parentElement).toHaveClass(CLASSNAME);
});

it('closes the toast when clickClosable is true and toast is clicked', async () => {
const TOAST_TEXT = 'message for closeable';
toast(TOAST_TEXT, { clickClosable: true });
await act(() => toast(TOAST_TEXT, { clickClosable: true }));

const toastDOM = screen.getByText(TOAST_TEXT);
toastDOM.click();
await act(() => toastDOM.click());

await waitForElementToBeRemoved(toastDOM, {
timeout: EXIT_ANIMATION_DURATION,
});
});

it('renders toast with specified position', () => {
it('renders toast with specified position', async () => {
const TOAST_TEXT = 'message for top-center';
toast(TOAST_TEXT, { position: 'top-center' });
await act(() => toast(TOAST_TEXT, { position: 'top-center' }));
const toastDOM1 = screen.getByText(TOAST_TEXT);

expect(toastDOM1.closest('.toast-list')).toHaveClass('top-center');
});

it('limits visible toasts based on maxVisibleToasts', async () => {
const TOAST_TEXT = 'message for maxVisibleToasts';
toast(TOAST_TEXT);
toast(TOAST_TEXT, { maxVisibleToasts: 1 });
await act(() => {
toast(TOAST_TEXT);
toast(TOAST_TEXT, { maxVisibleToasts: 1 });
});

await waitFor(
() => {
Expand All @@ -102,33 +105,35 @@ describe('toast', () => {
);
});

it('renders custom toast content with render prop', () => {
it('renders custom toast content with render prop', async () => {
const TOAST_TEXT = 'message for custom render';
const render = () => <div className="custom-class">custom render</div>;
toast(TOAST_TEXT, { render });
await act(() => toast(TOAST_TEXT, { render }));

const toastDOM = screen.getByText('custom render');
expect(toastDOM).toHaveClass('custom-class');
});

it('triggers onClick event when toast is clicked', () => {
it('triggers onClick event when toast is clicked', async () => {
const TOAST_TEXT = 'message for click';
const onClick = jest.fn();
toast(TOAST_TEXT, { clickable: true, onClick });
await act(() => toast(TOAST_TEXT, { clickable: true, onClick }));

const toastDOM = screen.getByText(TOAST_TEXT);
toastDOM.click();
await act(() => toastDOM.click());
expect(onClick).toHaveBeenCalled();
});

it('calls onCloseStart and onClose when toast is clicked with clickClosable set to true', async () => {
const TOAST_TEXT = 'message for onClose';
const onCloseStart = jest.fn();
const onClose = jest.fn();
toast(TOAST_TEXT, { onCloseStart, onClose, clickClosable: true });
await act(() =>
toast(TOAST_TEXT, { onCloseStart, onClose, clickClosable: true }),
);

const toastDOM = screen.getByText(TOAST_TEXT);
toastDOM.click();
await act(() => toastDOM.click());
expect(onCloseStart).toHaveBeenCalled();
await waitFor(() => expect(onClose).toHaveBeenCalled());
});
Expand All @@ -137,7 +142,7 @@ describe('toast', () => {
const TOAST_TEXT = 'message for updateDuration';
const DURATION = Infinity;
const NEW_DURATION = 500;
const toastInstance = toast(TOAST_TEXT, DURATION);
const toastInstance = await act(() => toast(TOAST_TEXT, DURATION));

toastInstance.updateDuration(NEW_DURATION);
const toastElement = screen.getByText(TOAST_TEXT);
Expand All @@ -147,13 +152,13 @@ describe('toast', () => {
});
});

it('updates the content of the displayed toast', () => {
it('updates the content of the displayed toast', async () => {
const TOAST_TEXT = 'message for updateContent';
const NEW_TOAST_TEXT = 'new message for updateContent';
const toastInstance = toast(TOAST_TEXT);
const toastInstance = await act(() => toast(TOAST_TEXT));
const toastElement = screen.getByText(TOAST_TEXT);

toastInstance.update(NEW_TOAST_TEXT);
await act(() => toastInstance.update(NEW_TOAST_TEXT));
expect(toastElement).toHaveTextContent(NEW_TOAST_TEXT);
});
});
6 changes: 3 additions & 3 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
},
"dependencies": {
"prism-react-renderer": "^2.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "link:../node_modules/react",
"react-dom": "link:../node_modules/react-dom",
"react-router-dom": "^6.11.1",
"react-simple-toasts": "file:.."
"react-simple-toasts": "link:.."
},
"devDependencies": {
"@types/react": "^18.0.28",
Expand Down
1 change: 1 addition & 0 deletions example/src/page/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './theme';
Empty file.
40 changes: 40 additions & 0 deletions example/src/page/theme/theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import CommonHighlighter from '../../component/common-highlighter';
import Button from '../../component/button';
import toast from 'react-simple-toasts';
import 'react-simple-toasts/dist/theme/dark.css';

function Theme() {
return (
<div>
<h2>Theme</h2>
<p>
react-simple-toasts has a default theme, but you can customize it by
passing a theme object to the toast function.
</p>
<br />
<Button onClick={() => {
toast('Hello, World!', { duration: Infinity, theme: 'dark' });
}}>
Light theme
</Button>
<br />
<br />
<CommonHighlighter>{`import toast from 'react-simple-toasts';
export default function App() {
return (
<button onClick={() => toast('Hello, World!', { theme: 'light' })}>
Show Toast
</button>
);
}`}</CommonHighlighter>

<section>
<h3></h3>
</section>
</div>
);
}

export default Theme;
Loading

0 comments on commit 09c1665

Please sign in to comment.