blob: 2ad4d7dc8678455f70c910ada80981c5af7adaa6 [file] [log] [blame]
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
goog.provide('goog.ui.editor.AbstractDialogTest');
goog.setTestOnly('goog.ui.editor.AbstractDialogTest');
goog.require('goog.dom');
goog.require('goog.dom.DomHelper');
goog.require('goog.dom.classlist');
goog.require('goog.events.Event');
goog.require('goog.events.EventHandler');
goog.require('goog.events.KeyCodes');
goog.require('goog.testing.MockControl');
goog.require('goog.testing.events');
goog.require('goog.testing.jsunit');
goog.require('goog.testing.mockmatchers.ArgumentMatcher');
goog.require('goog.ui.editor.AbstractDialog');
goog.require('goog.userAgent');
function shouldRunTests() {
// Test disabled in IE7 due to flakiness. See b/4269021.
return !(goog.userAgent.IE && goog.userAgent.isVersionOrHigher('7'));
}
var dialog;
var builder;
var mockCtrl;
var mockAfterHideHandler;
var mockOkHandler;
var mockCancelHandler;
var mockCustomButtonHandler;
var CUSTOM_EVENT = 'customEvent';
var CUSTOM_BUTTON_ID = 'customButton';
function setUp() {
mockCtrl = new goog.testing.MockControl();
mockAfterHideHandler = mockCtrl.createLooseMock(goog.events.EventHandler);
mockOkHandler = mockCtrl.createLooseMock(goog.events.EventHandler);
mockCancelHandler = mockCtrl.createLooseMock(goog.events.EventHandler);
mockCustomButtonHandler = mockCtrl.createLooseMock(goog.events.EventHandler);
}
function tearDown() {
if (dialog) {
mockAfterHideHandler.$setIgnoreUnexpectedCalls(true);
dialog.dispose();
}
}
/**
* Sets up the mock event handler to expect an AFTER_HIDE event.
*/
function expectAfterHide() {
mockAfterHideHandler.handleEvent(
new goog.testing.mockmatchers.ArgumentMatcher(function(arg) {
return arg.type ==
goog.ui.editor.AbstractDialog.EventType.AFTER_HIDE;
}));
}
/**
* Sets up the mock event handler to expect an OK event.
*/
function expectOk() {
mockOkHandler.handleEvent(new goog.testing.mockmatchers.ArgumentMatcher(
function(arg) {
return arg.type == goog.ui.editor.AbstractDialog.EventType.OK;
}));
}
/**
* Sets up the mock event handler to expect an OK event and to call
* preventDefault when handling it.
*/
function expectOkPreventDefault() {
expectOk();
mockOkHandler.$does(function(e) {
e.preventDefault();
});
}
/**
* Sets up the mock event handler to expect an OK event and to return false
* when handling it.
*/
function expectOkReturnFalse() {
expectOk();
mockOkHandler.$returns(false);
}
/**
* Sets up the mock event handler to expect a CANCEL event.
*/
function expectCancel() {
mockCancelHandler.handleEvent(new goog.testing.mockmatchers.ArgumentMatcher(
function(arg) {
return arg.type == goog.ui.editor.AbstractDialog.EventType.CANCEL;
}));
}
/**
* Sets up the mock event handler to expect a custom button event.
*/
function expectCustomButton() {
mockCustomButtonHandler.handleEvent(
new goog.testing.mockmatchers.ArgumentMatcher(function(arg) {
return arg.type == CUSTOM_EVENT;
}));
}
/**
* Helper to create the dialog being tested in each test. Since NewDialog is
* abstract, needs to add a concrete version of any abstract methods. Also
* creates up the global builder variable which should be set up after the call
* to this method.
* @return {goog.ui.editor.AbstractDialog} The dialog.
*/
function createTestDialog() {
var dialog = new goog.ui.editor.AbstractDialog(new goog.dom.DomHelper());
builder = new goog.ui.editor.AbstractDialog.Builder(dialog);
dialog.createDialogControl = function() {
return builder.build();
};
dialog.createOkEvent = function(e) {
return new goog.events.Event(goog.ui.editor.AbstractDialog.EventType.OK);
};
dialog.addEventListener(goog.ui.editor.AbstractDialog.EventType.AFTER_HIDE,
mockAfterHideHandler);
dialog.addEventListener(goog.ui.editor.AbstractDialog.EventType.OK,
mockOkHandler);
dialog.addEventListener(goog.ui.editor.AbstractDialog.EventType.CANCEL,
mockCancelHandler);
dialog.addEventListener(CUSTOM_EVENT, mockCustomButtonHandler);
return dialog;
}
/**
* Asserts that the given dialog is open.
* @param {string} msg Message to be printed in case of failure.
* @param {goog.ui.editor.AbstractDialog} dialog Dialog to be tested.
*/
function assertOpen(msg, dialog) {
assertTrue(msg + ' [AbstractDialog.isOpen()]', dialog && dialog.isOpen());
}
/**
* Asserts that the given dialog is closed.
* @param {string} msg Message to be printed in case of failure.
* @param {goog.ui.editor.AbstractDialog} dialog Dialog to be tested.
*/
function assertNotOpen(msg, dialog) {
assertFalse(msg + ' [AbstractDialog.isOpen()]', dialog && dialog.isOpen());
}
/**
* Tests that if you create a dialog and hide it without having shown it, no
* errors occur.
*/
function testCreateAndHide() {
dialog = createTestDialog();
mockCtrl.$replayAll();
assertNotOpen('Dialog should not be open after creation', dialog);
dialog.hide();
assertNotOpen('Dialog should not be open after hide()', dialog);
mockCtrl.$verifyAll(); // Verifies AFTER_HIDE was not dispatched.
}
/**
* Tests that when you show and hide a dialog the flags indicating open are
* correct and the AFTER_HIDE event is dispatched (and no errors happen).
*/
function testShowAndHide() {
dialog = createTestDialog();
expectAfterHide(dialog);
mockCtrl.$replayAll();
assertNotOpen('Dialog should not be open before show()', dialog);
dialog.show();
assertOpen('Dialog should be open after show()', dialog);
dialog.hide();
assertNotOpen('Dialog should not be open after hide()', dialog);
mockCtrl.$verifyAll(); // Verifies AFTER_HIDE was dispatched.
}
/**
* Tests that when you show and dispose a dialog (without hiding it first) the
* flags indicating open are correct and the AFTER_HIDE event is dispatched (and
* no errors happen).
*/
function testShowAndDispose() {
dialog = createTestDialog();
expectAfterHide(dialog);
mockCtrl.$replayAll();
assertNotOpen('Dialog should not be open before show()', dialog);
dialog.show();
assertOpen('Dialog should be open after show()', dialog);
dialog.dispose();
assertNotOpen('Dialog should not be open after dispose()', dialog);
mockCtrl.$verifyAll(); // Verifies AFTER_HIDE was dispatched.
}
/**
* Tests that when you dispose a dialog (without ever showing it first) the
* flags indicating open are correct and the AFTER_HIDE event is never
* dispatched (and no errors happen).
*/
function testDisposeWithoutShow() {
dialog = createTestDialog();
mockCtrl.$replayAll();
assertNotOpen('Dialog should not be open before dispose()', dialog);
dialog.dispose();
assertNotOpen('Dialog should not be open after dispose()', dialog);
mockCtrl.$verifyAll(); // Verifies AFTER_HIDE was NOT dispatched.
}
/**
* Tests that labels set in the builder can be found in the resulting dialog's
* HTML.
*/
function testBasicLayout() {
dialog = createTestDialog();
mockCtrl.$replayAll();
// create some dialog content
var content = goog.dom.createDom('div', null, 'The Content');
builder.setTitle('The Title')
.setContent(content)
.addOkButton('The OK Button')
.addCancelButton()
.addButton('The Apply Button', goog.nullFunction)
.addClassName('myClassName');
dialog.show();
var dialogElem = dialog.dialogInternal_.getElement();
var html = dialogElem.innerHTML;
// TODO(user): This is really insufficient. If the title and content
// were swapped this test would still pass!
assertContains('Dialog html should contain title', '>The Title<', html);
assertContains('Dialog html should contain content', '>The Content<', html);
assertContains('Dialog html should contain custom OK button label',
'>The OK Button<',
html);
assertContains('Dialog html should contain default Cancel button label',
'>Cancel<',
html);
assertContains('Dialog html should contain custom button label',
'>The Apply Button<',
html);
assertTrue('Dialog should have default Closure class',
goog.dom.classlist.contains(dialogElem, 'modal-dialog'));
assertTrue('Dialog should have our custom class',
goog.dom.classlist.contains(dialogElem, 'myClassName'));
mockCtrl.$verifyAll();
}
/**
* Tests that clicking the OK button dispatches the OK event and closes the
* dialog (dispatching the AFTER_HIDE event too).
*/
function testOk() {
dialog = createTestDialog();
expectOk(dialog);
expectAfterHide(dialog);
mockCtrl.$replayAll();
dialog.show();
goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
assertNotOpen('Dialog should not be open after clicking OK', dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that hitting the enter key dispatches the OK event and closes the
* dialog (dispatching the AFTER_HIDE event too).
*/
function testEnter() {
dialog = createTestDialog();
expectOk(dialog);
expectAfterHide(dialog);
mockCtrl.$replayAll();
dialog.show();
goog.testing.events.fireKeySequence(dialog.dialogInternal_.getElement(),
goog.events.KeyCodes.ENTER);
assertNotOpen('Dialog should not be open after hitting enter', dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that clicking the Cancel button dispatches the CANCEL event and closes
* the dialog (dispatching the AFTER_HIDE event too).
*/
function testCancel() {
dialog = createTestDialog();
expectCancel(dialog);
expectAfterHide(dialog);
mockCtrl.$replayAll();
builder.addCancelButton('My Cancel Button');
dialog.show();
goog.testing.events.fireClickSequence(dialog.getCancelButtonElement());
assertNotOpen('Dialog should not be open after clicking Cancel', dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that hitting the escape key dispatches the CANCEL event and closes
* the dialog (dispatching the AFTER_HIDE event too).
*/
function testEscape() {
dialog = createTestDialog();
expectCancel(dialog);
expectAfterHide(dialog);
mockCtrl.$replayAll();
dialog.show();
goog.testing.events.fireKeySequence(dialog.dialogInternal_.getElement(),
goog.events.KeyCodes.ESC);
assertNotOpen('Dialog should not be open after hitting escape', dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that clicking the custom button dispatches the custom event and closes
* the dialog (dispatching the AFTER_HIDE event too).
*/
function testCustomButton() {
dialog = createTestDialog();
expectCustomButton(dialog);
expectAfterHide(dialog);
mockCtrl.$replayAll();
builder.addButton('My Custom Button',
function() {
dialog.dispatchEvent(CUSTOM_EVENT);
},
CUSTOM_BUTTON_ID);
dialog.show();
goog.testing.events.fireClickSequence(
dialog.getButtonElement(CUSTOM_BUTTON_ID));
assertNotOpen('Dialog should not be open after clicking custom button',
dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that if the OK handler calls preventDefault, the dialog doesn't close.
*/
function testOkPreventDefault() {
dialog = createTestDialog();
expectOkPreventDefault(dialog);
mockCtrl.$replayAll();
dialog.show();
goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
assertOpen('Dialog should not be closed because preventDefault was called',
dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that if the OK handler returns false, the dialog doesn't close.
*/
function testOkReturnFalse() {
dialog = createTestDialog();
expectOkReturnFalse(dialog);
mockCtrl.$replayAll();
dialog.show();
goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
assertOpen('Dialog should not be closed because handler returned false',
dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that if creating the OK event fails, no event is dispatched and the
* dialog doesn't close.
*/
function testCreateOkEventFail() {
dialog = createTestDialog();
dialog.createOkEvent = function() { // Override our mock createOkEvent.
return null;
};
mockCtrl.$replayAll();
dialog.show();
goog.testing.events.fireClickSequence(dialog.getOkButtonElement());
assertOpen('Dialog should not be closed because OK event creation failed',
dialog);
mockCtrl.$verifyAll(); // Verifies that no event was dispatched.
}
/**
* Tests that processOkAndClose() dispatches the OK event and closes the
* dialog (dispatching the AFTER_HIDE event too).
*/
function testProcessOkAndClose() {
dialog = createTestDialog();
expectOk(dialog);
expectAfterHide(dialog);
mockCtrl.$replayAll();
dialog.show();
dialog.processOkAndClose();
assertNotOpen('Dialog should not be open after processOkAndClose()', dialog);
mockCtrl.$verifyAll();
}
/**
* Tests that if the OK handler triggered by processOkAndClose calls
* preventDefault, the dialog doesn't close (in the old implementation this
* failed due to not great design, so this is sort of a regression test).
*/
function testProcessOkAndClosePreventDefault() {
dialog = createTestDialog();
expectOkPreventDefault(dialog);
mockCtrl.$replayAll();
dialog.show();
dialog.processOkAndClose();
assertOpen('Dialog should not be closed because preventDefault was called',
dialog);
mockCtrl.$verifyAll();
}