Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 168 additions & 72 deletions src/dialog/tests/unit/Dialog.ts
Original file line number Diff line number Diff line change
@@ -1,114 +1,210 @@
import * as registerSuite from 'intern!object';
import * as assert from 'intern/chai!assert';
import { VNode } from '@dojo/interfaces/vdom';
import Dialog from '../../Dialog';
import * as sinon from 'sinon';

import { v } from '@dojo/widget-core/d';
import { assignChildProperties, compareProperty, replaceChild } from '@dojo/test-extras/support/d';
import harness, { Harness } from '@dojo/test-extras/harness';

import Dialog, { DialogProperties } from '../../Dialog';
import * as css from '../../styles/dialog.m.css';
import * as iconCss from '../../../common/styles/icons.m.css';
import * as animations from '../../../common/styles/animations.m.css';

const compareId = compareProperty((value: any) => {
return typeof value === 'string';
});

const expectedCloseButton = function(widget: any) {
return v('button', {
classes: widget.classes(css.close),
onclick: widget.listener
}, [
'close dialog',
v('i', {
classes: widget.classes(iconCss.icon, iconCss.closeIcon),
role: 'presentation',
'aria-hidden': 'true'
})
]);
};

const expected = function(widget: any, open = false, closeable = false, children: any[] = []) {
return v('div', { classes: widget.classes(css.root) }, open ? [
v('div', {
classes: widget.classes(css.underlay),
enterAnimation: animations.fadeIn,
exitAnimation: animations.fadeOut,
key: 'underlay',
onclick: widget.listener
}),
v('div', {
'aria-labelledby': compareId,
classes: widget.classes(css.main),
enterAnimation: animations.fadeIn,
exitAnimation: animations.fadeOut,
key: 'main',
role: 'dialog'
}, [
v('div', {
classes: widget.classes(css.title),
key: 'title'
}, [
v('div', { id: <any> compareId }, [ '' ]),
closeable ? expectedCloseButton(widget) : null
]),
v('div', {
classes: widget.classes(css.content),
key: 'content'
}, children)
])
] : []);
};

let widget: Harness<DialogProperties, typeof Dialog>;

registerSuite({
name: 'Dialog',

'Should construct dialog with passed properties'() {
const dialog = new Dialog();
dialog.__setProperties__({
key: 'foo',
modal: true,
beforeEach() {
widget = harness(Dialog);
},

afterEach() {
widget.destroy();
},

'default properties'() {
widget.expectRender(expected(widget), 'closed dialog renders correctly');

widget.setProperties({
open: true,
title: 'dialog',
underlay: true,
closeable: false
});
widget.expectRender(expected(widget, true), 'open dialog renders correctly');
},

'custom properties'() {
// force an initial render so all classes are present
widget.setProperties({
open: true
});
widget.getRender();

// set tested properties
widget.setProperties({
closeable: true,
closeText: 'foo',
role: 'dialog'
enterAnimation: 'fooAnimation',
exitAnimation: 'barAnimation',
open: true,
role: 'alertdialog',
title: 'foo',
underlay: true
});

let expectedVdom = expected(widget, true, true);
assignChildProperties(expectedVdom, '0', {
classes: widget.classes(css.underlayVisible, css.underlay) // do this here so the class is present in future renders
});
expectedVdom = expected(widget, true, true);
replaceChild(expectedVdom, '1,0,1,0', 'foo');
replaceChild(expectedVdom, '1,0,0,0', 'foo');
assignChildProperties(expectedVdom, '0', {
classes: widget.classes(css.underlayVisible, css.underlay)
});
assignChildProperties(expectedVdom, '1', {
enterAnimation: 'fooAnimation',
exitAnimation: 'barAnimation',
role: 'alertdialog'
});

assert.strictEqual(dialog.properties.key, 'foo');
assert.isTrue(dialog.properties.modal);
assert.isTrue(dialog.properties.open);
assert.strictEqual(dialog.properties.title, 'dialog');
assert.isTrue(dialog.properties.underlay);
assert.isTrue(dialog.properties.closeable);
assert.strictEqual(dialog.properties.closeText, 'foo');
assert.strictEqual(dialog.properties.role, 'dialog');
widget.expectRender(expectedVdom);
},

'Render correct children'() {
const dialog = new Dialog();
dialog.__setProperties__({
enterAnimation: 'enter',
exitAnimation: 'exit',
role: 'dialog',
closeText: 'foo'
});
let vnode = <VNode> dialog.__render__();
assert.strictEqual(vnode.vnodeSelector, 'div', 'tagname should be div');
assert.property(vnode.properties!.classes!, css.root);
assert.lengthOf(vnode.children, 0);
children() {
const testChildren = [
v('p', [ 'Lorem ipsum dolor sit amet' ]),
v('a', { href: '#foo' }, [ 'foo' ])
];

dialog.__setProperties__({
open: true,
underlay: true,
role: 'dialog'
widget.setProperties({
open: true
});
vnode = <VNode> dialog.__render__();
assert.lengthOf(vnode.children, 2);
widget.setChildren(testChildren);

const expectedVdom = expected(widget, true, true, testChildren);
widget.expectRender(expectedVdom);
},

onRequestClose() {
const dialog = new Dialog();
dialog.__setProperties__({
const onRequestClose = sinon.stub();

widget.setProperties({
closeable: true,
open: true,
onRequestClose: () => {
dialog.__setProperties__({ open: false });
}
onRequestClose
});
widget.sendEvent('click', {
selector: `.${css.close}`
});
(<any> dialog)._onCloseClick();
assert.isTrue(onRequestClose.calledOnce, 'onRequestClose handler called when close button is clicked');

assert.isFalse(dialog.properties.open, 'onRequestClose should be called when close button is clicked');
widget.setProperties({
closeable: false,
open: true,
onRequestClose
});
widget.getRender();
widget.sendEvent('click', {
selector: `.${css.underlay}`
});
assert.isTrue(onRequestClose.calledOnce, 'onRequestClose handler not called when closeable is false');
},

onOpen() {
let called = false;
const onOpen = sinon.stub();

const dialog = new Dialog();
dialog.__setProperties__({
widget.setProperties({
open: true,
onOpen: () => {
called = true;
}
onOpen
});
<VNode> dialog.__render__();
widget.getRender();
assert.isTrue(onOpen.calledOnce, 'onOpen handler called when open is initially set to true');

assert.isTrue(called, 'onOpen should be called');
widget.setProperties({
closeable: true,
open: true,
onOpen
});
widget.getRender();
assert.isTrue(onOpen.calledOnce, 'onOpen handler not called if dialog was previously open');
},

modal() {
const dialog = new Dialog();
dialog.__setProperties__({
const onRequestClose = sinon.stub();

widget.setProperties({
open: true,
modal: true,
onRequestClose: () => {
dialog.__setProperties__({ open: false });
}
onRequestClose
});
(<any> dialog)._onUnderlayClick();

assert.isTrue(dialog.properties.open, 'dialog should stay open when underlay is clicked and modal is true');

dialog.__setProperties__({ modal: false });
(<any> dialog)._onUnderlayClick();

assert.isUndefined(dialog.properties.open, 'dialog should close if underlay is clicked and modal is false');
},
widget.sendEvent('click', {
selector: `.${css.underlay}`
});
assert.isFalse(onRequestClose.called, 'onRequestClose should not be called when the underlay is clicked and modal is true');

closeable() {
const dialog = new Dialog();
dialog.__setProperties__({
closeable: false,
widget.setProperties({
open: true,
title: 'foo'
modal: false,
onRequestClose
});
<VNode> dialog.__render__();
(<any> dialog)._onCloseClick();
widget.getRender();

assert.isTrue(dialog.properties.open, 'dialog should not close if closeable is false');
widget.sendEvent('click', {
selector: `.${css.underlay}`
});
assert.isTrue(onRequestClose.called, 'onRequestClose is called when the underlay is clicked and modal is false');
}
});