| // 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(); |
| } |