-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
298 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 171 additions & 0 deletions
171
via/static/scripts/video_player/components/test/ToastMessages-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import { mount } from 'enzyme'; | ||
|
||
import { delay } from '../../../test-util/wait'; | ||
import ToastMessages from '../ToastMessages'; | ||
|
||
describe('ToastMessages', () => { | ||
const toastMessages = [ | ||
{ | ||
id: '1', | ||
type: 'success', | ||
message: 'Hello world', | ||
}, | ||
{ | ||
id: '2', | ||
type: 'success', | ||
message: 'Foobar', | ||
}, | ||
{ | ||
id: '3', | ||
type: 'error', | ||
message: 'Something failed', | ||
}, | ||
]; | ||
let fakeOnMessageDismiss; | ||
|
||
beforeEach(() => { | ||
fakeOnMessageDismiss = sinon.stub(); | ||
}); | ||
|
||
function createToastMessages(toastMessages, setTimeout) { | ||
const container = document.createElement('div'); | ||
document.body.appendChild(container); | ||
|
||
return mount( | ||
<ToastMessages | ||
messages={toastMessages} | ||
onMessageDismiss={fakeOnMessageDismiss} | ||
setTimeout_={setTimeout} | ||
/>, | ||
{ attachTo: container } | ||
); | ||
} | ||
|
||
function triggerAnimationEnd(wrapper, index, direction = 'out') { | ||
wrapper | ||
.find('BaseToastMessageTransition') | ||
.at(index) | ||
.props() | ||
.onTransitionEnd(direction); | ||
wrapper.update(); | ||
} | ||
|
||
it('renders a list of toast messages', () => { | ||
const wrapper = createToastMessages(toastMessages); | ||
assert.equal(wrapper.find('ToastMessageItem').length, toastMessages.length); | ||
}); | ||
|
||
toastMessages.forEach((message, index) => { | ||
it('dismisses messages when clicked', () => { | ||
const wrapper = createToastMessages(toastMessages); | ||
|
||
wrapper.find('Callout').at(index).props().onClick(); | ||
// onMessageDismiss is not immediately called. Transition has to finish | ||
assert.notCalled(fakeOnMessageDismiss); | ||
|
||
// Once dismiss animation has finished, onMessageDismiss is called | ||
triggerAnimationEnd(wrapper, index); | ||
assert.calledWith(fakeOnMessageDismiss, message.id); | ||
}); | ||
}); | ||
|
||
it('dismisses messages automatically unless instructed otherwise', () => { | ||
const messages = [ | ||
...toastMessages, | ||
{ | ||
id: 'foo', | ||
type: 'success', | ||
message: 'Not to be dismissed', | ||
autoDismiss: false, | ||
}, | ||
]; | ||
const wrapper = createToastMessages( | ||
messages, | ||
// Fake internal setTimeout, to immediately call its callback | ||
callback => callback() | ||
); | ||
|
||
// Trigger "in" animation for all messages, which will schedule dismiss for | ||
// appropriate messages | ||
messages.forEach((_, index) => { | ||
triggerAnimationEnd(wrapper, index, 'in'); | ||
}); | ||
|
||
// Trigger "out" animation on components which "direction" prop is currently | ||
// "out". That means they were scheduled for dismiss | ||
wrapper | ||
.find('BaseToastMessageTransition') | ||
.forEach((transitionComponent, index) => { | ||
if (transitionComponent.prop('direction') === 'out') { | ||
triggerAnimationEnd(wrapper, index); | ||
} | ||
}); | ||
|
||
// Only one toast message will remain, as it was marked as `autoDismiss: false` | ||
assert.equal(fakeOnMessageDismiss.callCount, 3); | ||
}); | ||
|
||
it('schedules dismiss only once per message', async () => { | ||
const wrapper = createToastMessages( | ||
toastMessages, | ||
// Fake a setTimeout which is fast enough to not make the test too slow, | ||
// but allows to check that subsequent schedules of the same message are ignored | ||
callback => setTimeout(callback, 50) | ||
); | ||
const scheduleFirstMessageDismiss = () => | ||
triggerAnimationEnd(wrapper, 0, 'in'); | ||
|
||
scheduleFirstMessageDismiss(); | ||
scheduleFirstMessageDismiss(); | ||
scheduleFirstMessageDismiss(); | ||
|
||
// Wait for the first scheduled timeout | ||
await delay(60); | ||
|
||
// Once dismiss animation has finished, onMessageDismiss is called | ||
triggerAnimationEnd(wrapper, 0); | ||
assert.equal(fakeOnMessageDismiss.callCount, 1); | ||
}); | ||
|
||
['slide-in-from-right', 'fade-in', 'fade-out'].forEach(animationName => { | ||
it('invokes onTransitionEnd when proper animation is dispatched', () => { | ||
const wrapper = createToastMessages(toastMessages, callback => | ||
callback() | ||
); | ||
const animationContainer = wrapper | ||
.find('[data-testid="animation-container"]') | ||
.first(); | ||
|
||
// Trigger "in" animation for all messages, which will schedule dismiss | ||
toastMessages.forEach((_, index) => { | ||
triggerAnimationEnd(wrapper, index, 'in'); | ||
}); | ||
|
||
animationContainer | ||
.getDOMNode() | ||
.dispatchEvent(new AnimationEvent('animationend', { animationName })); | ||
|
||
assert.called(fakeOnMessageDismiss); | ||
}); | ||
}); | ||
|
||
it('does not invoke onTransitionEnd for irrelevant animations', () => { | ||
const wrapper = createToastMessages(toastMessages, callback => callback()); | ||
const animationContainer = wrapper | ||
.find('[data-testid="animation-container"]') | ||
.first(); | ||
|
||
// Trigger "in" animation for all messages, which will schedule dismiss | ||
toastMessages.forEach((_, index) => { | ||
triggerAnimationEnd(wrapper, index, 'in'); | ||
}); | ||
|
||
animationContainer | ||
.getDOMNode() | ||
.dispatchEvent( | ||
new AnimationEvent('animationend', { animationName: 'invalid' }) | ||
); | ||
|
||
assert.notCalled(fakeOnMessageDismiss); | ||
}); | ||
}); |
87 changes: 87 additions & 0 deletions
87
via/static/scripts/video_player/hooks/test/use-toast-messages-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { mount } from 'enzyme'; | ||
|
||
import { useToastMessages } from '../use-toast-messages'; | ||
|
||
describe('useToastMessages', () => { | ||
function FakeToastMessagesContainer() { | ||
const { toastMessages, appendToastMessage, dismissToastMessage } = | ||
useToastMessages(); | ||
|
||
return ( | ||
<div> | ||
{!toastMessages.length && ( | ||
<span data-testid="no-toast-messages"> | ||
There are no toast messages | ||
</span> | ||
)} | ||
{toastMessages.map(({ message }, index) => ( | ||
<span key={`${message}_${index}`} className="toast-message"> | ||
{message} | ||
</span> | ||
))} | ||
<button | ||
data-testid="append-button" | ||
onClick={() => | ||
appendToastMessage({ | ||
type: 'success', | ||
message: 'Toast message', | ||
}) | ||
} | ||
> | ||
Append | ||
</button> | ||
<button | ||
data-testid="dismiss-button" | ||
onClick={() => | ||
toastMessages.length && dismissToastMessage(toastMessages[0].id) | ||
} | ||
> | ||
Dismiss | ||
</button> | ||
</div> | ||
); | ||
} | ||
|
||
function createFakeToastMessages() { | ||
return mount(<FakeToastMessagesContainer />); | ||
} | ||
|
||
it('has no toast messages at first', () => { | ||
const wrapper = createFakeToastMessages(); | ||
|
||
assert.isTrue(wrapper.exists('[data-testid="no-toast-messages"]')); | ||
assert.isFalse(wrapper.exists('.toast-message')); | ||
}); | ||
|
||
it('can append toast messages', () => { | ||
const wrapper = createFakeToastMessages(); | ||
const appendButton = wrapper.find('[data-testid="append-button"]'); | ||
|
||
appendButton.simulate('click'); | ||
appendButton.simulate('click'); | ||
appendButton.simulate('click'); | ||
|
||
assert.isFalse(wrapper.exists('[data-testid="no-toast-messages"]')); | ||
assert.equal(3, wrapper.find('.toast-message').length); | ||
}); | ||
|
||
it('can dismiss toast messages', () => { | ||
const wrapper = createFakeToastMessages(); | ||
const appendButton = wrapper.find('[data-testid="append-button"]'); | ||
const dismissButton = wrapper.find('[data-testid="dismiss-button"]'); | ||
|
||
// Append five messages | ||
appendButton.simulate('click'); | ||
appendButton.simulate('click'); | ||
appendButton.simulate('click'); | ||
appendButton.simulate('click'); | ||
appendButton.simulate('click'); | ||
assert.equal(5, wrapper.find('.toast-message').length); | ||
|
||
// Dismiss three | ||
dismissButton.simulate('click'); | ||
dismissButton.simulate('click'); | ||
dismissButton.simulate('click'); | ||
assert.equal(2, wrapper.find('.toast-message').length); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.