butter-toast
Version:
Smooth toast notifications for react apps
333 lines (281 loc) • 11.7 kB
JavaScript
import React from 'react';
import Toast from './';
import { mount } from 'enzyme';
const toastProps = (extend = {}) => {
return Object.assign({}, {
toast: {
id: 's123',
height: 70,
content: 'example',
timeout: 6000,
},
setHeight: () => null
}, extend);
}
describe('Toast Component', () => {
let wrapper, instance;
describe('componentDidMount', () => {
it('should call `this.open`', (done) => {
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
instance.open = jest.fn();
instance.componentDidMount();
setTimeout(() => {
expect(instance.open).toHaveBeenCalledTimes(1);
done();
});
});
});
describe('componentWillUnmount', () => {
it('should call `this.clearTimeout`', () => {
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
instance.clearTimeout = jest.fn();
instance.componentWillUnmount();
expect(instance.clearTimeout).toHaveBeenCalledTimes(1);
});
});
describe('open', () => {
it('should call `setState` with: `{ isOpen: true }, instance.toastDidOpen`', () => {
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
instance.setState = jest.fn();
instance.open();
expect(instance.setState).toHaveBeenCalledWith({ isOpen: true }, instance.toastDidOpen);
});
});
describe('startTimeout', () => {
const _setTimeout = global.setTimeout;
const _now = global.Date.now;
const now = Date.now();
beforeEach(() => {
global.Date.now = jest.fn(() => now);
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
global.setTimeout = jest.fn((...args) => _setTimeout(...args));
});
afterEach(() => {
global.setTimeout = _setTimeout;
global.Date.now = _now;
});
describe('toast is not sticky', () => {
describe('remaining is set', () => {
it('should call setTimeout with `this.close` and `remaining value`', () => {
instance.remaining = 1500;
instance.startTimeout();
expect(global.setTimeout).toHaveBeenCalledWith(instance.close, 1500);
});
it('should set `this.ends` with now + the new timeout', () => {
instance.remaining = 1000;
instance.startTimeout();
expect(instance.ends).toBe(now + 1000);
});
describe('less than 200 ms remaining', () => {
it('should add 200ms to the remaining value', () => {
instance.remaining = 50;
instance.startTimeout();
expect(global.setTimeout).toHaveBeenCalledWith(instance.close, 250);
});
it('should set `this.ends` with now + the new timeout', () => {
instance.remaining = 50;
instance.startTimeout();
expect(instance.ends).toBe(now + 250);
});
});
});
describe('remaining is not set', () => {
it('should call setTimeout with `this.close` and `timeout value`', () => {
instance.startTimeout();
expect(global.setTimeout).toHaveBeenCalledWith(instance.close, toastProps().toast.timeout);
});
it('should set `this.ends` with now + the new timeout', () => {
instance.startTimeout();
expect(instance.ends).toBe(now + toastProps().toast.timeout);
});
describe('timeout is less than 200ms', () => {
beforeEach(() => {
const toast = toastProps();
toast.toast.timeout = 50;
wrapper = mount(<Toast {...toast}/>);
instance = wrapper.instance();
});
it('should add 200ms to the value', () => {
instance.startTimeout();
expect(global.setTimeout).toHaveBeenCalledWith(instance.close, 250);
});
it('should set `this.ends` with now + the new timeout', () => {
instance.startTimeout();
expect(instance.ends).toBe(now + 250);
});
});
});
it('should call clearTimeout', () => {
instance.clearTimeout = jest.fn();
instance.startTimeout();
expect(instance.clearTimeout).toHaveBeenCalled();
});
it('should clear `this.remaining`', () => {
instance.remaining = 1000;
instance.startTimeout();
expect(instance.remaining).toBe(undefined);
});
});
describe('toast is sticky', () => {
beforeEach(() => {
const toast = toastProps();
toast.toast.sticky = true;
wrapper = mount(<Toast {...toast}/>);
instance = wrapper.instance();
});
test('this.timeout stays unchanged', () => {
const timeout = instance.timeout;
instance.startTimeout();
expect(instance.timeout).toBe(timeout);
});
test('this.ends stays unchanged', () => {
const ends = instance.ends;
instance.startTimeout();
expect(instance.ends).toBe(ends);
});
test('this.remaining stays unchanged', () => {
const remaining = instance.remaining;
instance.startTimeout();
expect(instance.remaining).toBe(remaining);
});
});
describe('toast timeout is `Infinity`', () => {
beforeEach(() => {
const toast = toastProps();
toast.toast.timeout = Infinity;
wrapper = mount(<Toast {...toast}/>);
instance = wrapper.instance();
});
test('this.timeout stays unchanged', () => {
const timeout = instance.timeout;
instance.startTimeout();
expect(instance.timeout).toBe(timeout);
});
test('this.ends stays unchanged', () => {
const ends = instance.ends;
instance.startTimeout();
expect(instance.ends).toBe(ends);
});
test('this.remaining stays unchanged', () => {
const remaining = instance.remaining;
instance.startTimeout();
expect(instance.remaining).toBe(remaining);
});
});
});
describe('clearTimeout', () => {
let _clearTimeout = global.clearTimeout;
beforeEach(() => {
global.clearTimeout = jest.fn((...args) => _clearTimeout(...args));
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
});
afterEach(() => {
global.clearTimeout = _clearTimeout;
});
it('should set remaining to the result of calcRemaining', () => {
instance.calcRemaining = jest.fn(() => 2000);
instance.clearTimeout();
expect(instance.remaining).toBe(2000);
});
it('should call `clearTimeout` with this.timeout', () => {
instance.clearTimeout();
expect(global.clearTimeout).toHaveBeenCalledWith(instance.timeout);
});
});
describe('calcRemaining', () => {
const _now = global.Date.now;
const now = Date.now();
beforeEach(() => {
global.Date.now = jest.fn(() => now);
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
});
afterEach(() => {
global.Date.now = _now;
});
it('should substract Date.now() from end time', () => {
expect(instance.calcRemaining()).toBe(instance.ends - now);
});
});
describe('toastDidOpen', () => {
beforeEach(() => {
wrapper = mount(<Toast {...toastProps({setHeight: jest.fn()})}/>);
instance = wrapper.instance();
instance.startTimeout = jest.fn();
});
it('should setState `shown: true`', (done) => {
instance.toastDidOpen();
setTimeout(() => {
expect(wrapper.state().shown).toEqual(true);
done();
}, 0);
});
it('should call setHeight with `toastId` and tost height', (done) => {
instance.toastDidOpen();
setTimeout(() => {
expect(instance.props.setHeight).toHaveBeenCalledWith(toastProps().toast.id, instance.toastRef.clientHeight);
done();
}, 0);
});
});
describe('render', () => {
beforeEach(() => {
wrapper = mount(<Toast {...toastProps()}/>);
instance = wrapper.instance();
});
describe('pauseOnHover is true', () => {
it('should call `this.clearTimeout` on mouse enter', () => {
instance.clearTimeout = jest.fn();
wrapper.simulate('mouseenter', {});
expect(instance.clearTimeout).toHaveBeenCalledTimes(1);
});
it('should call `this.startTimeout` on mouse leave', () => {
instance.startTimeout = jest.fn();
wrapper.simulate('mouseleave', {});
expect(instance.startTimeout).toHaveBeenCalledTimes(1);
});
});
describe('pauseOnHover is false', () => {
beforeEach(() => {
wrapper = mount(<Toast {...toastProps({pauseOnHover: false})}/>);
instance = wrapper.instance();
});
it('should call `this.clearTimeout` on mouse enter', () => {
instance.clearTimeout = jest.fn();
wrapper.simulate('mouseenter', {});
expect(instance.clearTimeout).toHaveBeenCalledTimes(0);
});
it('should call `this.startTimeout` on mouse leave', () => {
instance.startTimeout = jest.fn();
wrapper.simulate('mouseleave', {});
expect(instance.startTimeout).toHaveBeenCalledTimes(0);
});
});
describe('API', () => {
let toastMock;
beforeEach(() => {
toastMock = jest.fn((props) => <span>example</span>);
const toast = toastProps();
toast.toast.content = toastMock;
wrapper = mount(<Toast {...toast}/>);
instance = wrapper.instance();
});
[
'toastId',
'dismiss',
'onClick',
'calcRemaining',
'trayPosition'
].forEach((prop) => {
it(`should pass down to toast component the ${prop} API prop`, () => {
expect(toastMock.mock.calls[0][0]).toHaveProperty(prop)
});
});
})
});
});