Project import generated by Copybara.
GitOrigin-RevId: 63746295f1a5ab5a619056791995793d65529e62
diff --git a/node_modules/dialog-polyfill/suite.js b/node_modules/dialog-polyfill/suite.js
new file mode 100644
index 0000000..943f17d
--- /dev/null
+++ b/node_modules/dialog-polyfill/suite.js
@@ -0,0 +1,790 @@
+/*
+ * Copyright 2015 Google Inc. 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.
+ */
+
+
+void function() {
+
+ /**
+ * Asserts that the displayed dialog is in the center of the screen.
+ *
+ * @param {HTMLDialogElement?} opt_dialog to check, or test default
+ */
+ function checkDialogCenter(opt_dialog) {
+ var d = opt_dialog || dialog;
+ var expectedTop = (window.innerHeight - d.offsetHeight) / 2;
+ var expectedLeft = (window.innerWidth - d.offsetWidth) / 2;
+ var rect = d.getBoundingClientRect();
+ assert.closeTo(rect.top, expectedTop, 1, 'top should be nearby');
+ assert.closeTo(rect.left, expectedLeft, 1, 'left should be nearby');
+ }
+
+ /**
+ * Creates a fake KeyboardEvent.
+ *
+ * @param {number} keyCode to press
+ * @param {string?} opt_type to use, default keydown
+ * @return {!Event} event
+ */
+ function createKeyboardEvent(keyCode, opt_type) {
+ var ev = document.createEvent('Events');
+ ev.initEvent(opt_type || 'keydown', true, true);
+ ev.keyCode = keyCode;
+ ev.which = keyCode;
+ return ev;
+ }
+
+ /**
+ * Cleans up any passed DOM elements.
+ *
+ * @param {!Element} el to clean up
+ * @return {!Element} the same element, for chaining
+ */
+ var cleanup = (function() {
+ var e = [];
+ teardown(function() {
+ e.forEach(function(el) {
+ try {
+ el.close(); // try to close dialogs
+ } catch (e) {}
+ el.parentElement && el.parentElement.removeChild(el);
+ });
+ e = [];
+ });
+
+ return function(el) {
+ e.push(el);
+ return el;
+ };
+ })();
+
+ /**
+ * Creates a dialog for testing that will be cleaned up later.
+ *
+ * @param {string?} opt_content to be used as innerHTML
+ */
+ function createDialog(opt_content) {
+ var dialog = document.createElement('dialog');
+ dialog.innerHTML = opt_content || 'Dialog #' + (cleanup.length);
+ document.body.appendChild(dialog);
+ if (window.location.search == '?force') {
+ dialogPolyfill.forceRegisterDialog(dialog);
+ } else {
+ dialogPolyfill.registerDialog(dialog);
+ }
+ return cleanup(dialog);
+ }
+
+ var dialog; // global dialog for all tests
+ setup(function() {
+ dialog = createDialog('Default Dialog');
+ });
+
+ suite('basic', function() {
+ test('show and close', function() {
+ assert.isFalse(dialog.hasAttribute('open'));
+ dialog.show();
+ assert.isTrue(dialog.hasAttribute('open'));
+ assert.isTrue(dialog.open);
+
+ var returnValue = 1234;
+ dialog.close(returnValue);
+ assert.isFalse(dialog.hasAttribute('open'));
+ assert.equal(dialog.returnValue, returnValue);
+
+ dialog.show();
+ dialog.close();
+ assert.isFalse(dialog.open);
+ assert.equal(dialog.returnValue, returnValue);
+ });
+ test('open property', function() {
+ assert.isFalse(dialog.hasAttribute('open'));
+ dialog.show();
+ assert.isTrue(dialog.hasAttribute('open'));
+ assert.isTrue(dialog.open);
+
+ dialog.open = false;
+ assert.isFalse(dialog.open);
+ assert.isFalse(dialog.hasAttribute('open'),
+ 'open property should clear attribute');
+ assert.throws(dialog.close);
+
+ var overlay = document.querySelector('._dialog_overlay');
+ assert.isNull(overlay);
+ });
+ test('show/showModal interaction', function() {
+ assert.isFalse(dialog.hasAttribute('open'));
+ dialog.show();
+
+ // If the native dialog is being tested, show/showModal are not already
+ // bound, so wrap them in helper methods for throws/doesNotThrow.
+ var show = function() { dialog.show(); };
+ var showModal = function() { dialog.showModal(); };
+
+ assert.doesNotThrow(show);
+ assert.throws(showModal);
+
+ dialog.open = false;
+ assert.doesNotThrow(showModal);
+ assert.doesNotThrow(show); // show after showModal does nothing
+ assert.throws(showModal);
+ // TODO: check dialog is still modal
+
+ assert.isTrue(dialog.open);
+ });
+ test('setAttribute reflects property', function() {
+ dialog.setAttribute('open', '');
+ assert.isTrue(dialog.open, 'attribute opens dialog');
+ });
+ test('changing open to dummy value is ignored', function() {
+ dialog.showModal();
+
+ dialog.setAttribute('open', 'dummy, ignored');
+ assert.isTrue(dialog.open, 'dialog open with dummy open value');
+
+ var overlay = document.querySelector('._dialog_overlay');
+ assert(overlay, 'dialog is still modal');
+ });
+ test('show/showModal outside document', function() {
+ dialog.open = false;
+ dialog.parentNode.removeChild(dialog);
+
+ assert.throws(function() { dialog.showModal(); });
+
+ assert.doesNotThrow(function() { dialog.show(); });
+ assert.isTrue(dialog.open, 'can open non-modal outside document');
+ assert.isFalse(document.body.contains(dialog));
+ });
+ test('has a11y property', function() {
+ assert.equal(dialog.getAttribute('role'), 'dialog', 'role should be dialog');
+ });
+ });
+
+ suite('DOM', function() {
+ setup(function(done) {
+ // DOM tests wait for modal to settle, so MutationOberver doesn't coalesce attr changes
+ dialog.showModal();
+ window.setTimeout(done, 0);
+ });
+ test('DOM direct removal', function(done) {
+ assert.isTrue(dialog.open);
+ assert.isNotNull(document.querySelector('.backdrop'));
+
+ var parentNode = dialog.parentNode;
+ parentNode.removeChild(dialog);
+
+ // DOMNodeRemoved defers its task a frame (since it occurs before removal, not after). This
+ // doesn't effect MutationObserver, just delays the test a frame.
+ window.setTimeout(function() {
+ assert.isNull(document.querySelector('.backdrop'), 'dialog removal should clear modal');
+
+ assert.isTrue(dialog.open, 'removed dialog should still be open');
+ parentNode.appendChild(dialog);
+
+ assert.isTrue(dialog.open, 're-added dialog should still be open');
+ assert.isNull(document.querySelector('.backdrop'), 're-add dialog should not be modal');
+
+ done();
+ }, 0);
+ });
+ test('DOM removal inside other element', function(done) {
+ var div = cleanup(document.createElement('div'));
+ document.body.appendChild(div);
+ div.appendChild(dialog);
+
+ document.body.removeChild(div);
+
+ window.setTimeout(function() {
+ assert.isNull(document.querySelector('.backdrop'), 'dialog removal should clear modal');
+ assert.isTrue(dialog.open, 'removed dialog should still be open');
+ done();
+ }, 0);
+ });
+ test('DOM instant remove/add', function(done) {
+ var div = cleanup(document.createElement('div'));
+ document.body.appendChild(div);
+ dialog.parentNode.removeChild(dialog);
+ div.appendChild(dialog);
+
+ window.setTimeout(function() {
+ assert.isNull(document.querySelector('.backdrop'), 'backdrop should disappear');
+ assert.isTrue(dialog.open);
+ done();
+ }, 0);
+ });
+ });
+
+ suite('position', function() {
+ test('non-modal is not centered', function() {
+ var el = cleanup(document.createElement('div'));
+ dialog.parentNode.insertBefore(el, dialog);
+ var testRect = el.getBoundingClientRect();
+
+ dialog.show();
+ var rect = dialog.getBoundingClientRect();
+
+ assert.equal(rect.top, testRect.top, 'dialog should not be centered');
+ });
+ test('default modal centering', function() {
+ dialog.showModal();
+ checkDialogCenter();
+ assert.ok(dialog.style.top, 'expected top to be set');
+ dialog.close();
+ assert.notOk(dialog.style.top, 'expected top to be cleared');
+ });
+ test('modal respects static position', function() {
+ dialog.style.top = '10px';
+ dialog.showModal();
+
+ var rect = dialog.getBoundingClientRect();
+ assert.equal(rect.top, 10);
+ });
+ test('modal recentering', function() {
+ var pX = document.body.scrollLeft;
+ var pY = document.body.scrollTop;
+ var big = cleanup(document.createElement('div'));
+ big.style.height = '200vh'; // 2x view height
+ document.body.appendChild(big);
+
+ try {
+ var scrollValue = 200; // don't use incredibly large values
+ dialog.showModal();
+ dialog.close();
+
+ window.scrollTo(0, scrollValue);
+ dialog.showModal();
+ checkDialogCenter(); // must be centered, even after scroll
+ var rectAtScroll = dialog.getBoundingClientRect();
+
+ // after scroll, we aren't recentered, check offset
+ window.scrollTo(0, 0);
+ var rect = dialog.getBoundingClientRect();
+ assert.closeTo(rectAtScroll.top + scrollValue, rect.top, 1);
+ } finally {
+ window.scrollTo(pX, pY);
+ }
+ });
+ test('clamped to top of page', function() {
+ var big = cleanup(document.createElement('div'));
+ big.style.height = '200vh'; // 2x view height
+ document.body.appendChild(big);
+ document.documentElement.scrollTop = document.documentElement.scrollHeight / 2;
+
+ dialog.style.height = document.documentElement.scrollHeight + 200 + 'px';
+ dialog.showModal();
+
+ var visibleRect = dialog.getBoundingClientRect();
+ assert.equal(visibleRect.top, 0, 'large dialog should be visible at top of page');
+
+ var style = window.getComputedStyle(dialog);
+ assert.equal(style.top, document.documentElement.scrollTop + 'px',
+ 'large dialog should be absolutely positioned at scroll top');
+ });
+ });
+
+ suite('backdrop', function() {
+ test('backdrop div on modal', function() {
+ dialog.showModal();
+ var foundBackdrop = document.querySelector('.backdrop');
+ assert.isNotNull(foundBackdrop);
+
+ var sibling = dialog.nextElementSibling;
+ assert.strictEqual(foundBackdrop, sibling);
+ });
+ test('no backdrop on non-modal', function() {
+ dialog.show();
+ assert.isNull(document.querySelector('.backdrop'));
+ dialog.close();
+ });
+ test('backdrop click appears as dialog', function() {
+ dialog.showModal();
+ var backdrop = dialog.nextElementSibling;
+
+ var clickFired = 0;
+ var helper = function(ev) {
+ assert.equal(ev.target, dialog);
+ ++clickFired;
+ };
+
+ dialog.addEventListener('click', helper)
+ backdrop.click();
+ assert.equal(clickFired, 1);
+ });
+ test('backdrop click focuses dialog', function() {
+ dialog.showModal();
+ dialog.tabIndex = 0;
+
+ var input = document.createElement('input');
+ input.type = 'text';
+ dialog.appendChild(input);
+
+ // TODO: It would be nice to check `input` instead here, but there's no more reliable ways
+ // to emulate a browser tab event (Firefox, Chrome etc have made it a security violation).
+
+ var backdrop = dialog.nextElementSibling;
+ backdrop.click();
+ assert.equal(document.activeElement, dialog);
+ });
+ });
+
+ suite('form focus', function() {
+ test('non-modal inside modal is focusable', function() {
+ var sub = createDialog();
+ dialog.appendChild(sub);
+
+ var input = document.createElement('input');
+ input.type = 'text';
+ sub.appendChild(input);
+
+ dialog.showModal();
+ sub.show();
+
+ input.focus();
+ assert.equal(input, document.activeElement);
+ });
+ test('clear focus when nothing focusable in modal', function() {
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ document.body.appendChild(input);
+ input.focus();
+
+ var previous = document.activeElement;
+ dialog.showModal();
+ assert.notEqual(previous, document.activeElement);
+ });
+ test('default focus on modal', function() {
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ dialog.appendChild(input);
+
+ var anotherInput = cleanup(document.createElement('input'));
+ anotherInput.type = 'text';
+ dialog.appendChild(anotherInput);
+
+ dialog.showModal();
+ assert.equal(document.activeElement, input);
+ });
+ test('default focus on non-modal', function() {
+ var div = cleanup(document.createElement('div'));
+ div.tabIndex = 4;
+ dialog.appendChild(div);
+
+ dialog.show();
+ assert.equal(document.activeElement, div);
+ });
+ test('autofocus element chosen', function() {
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ dialog.appendChild(input);
+
+ var inputAF = cleanup(document.createElement('input'));
+ inputAF.type = 'text';
+ inputAF.autofocus = true;
+ dialog.appendChild(inputAF);
+
+ dialog.showModal();
+ assert.equal(document.activeElement, inputAF);
+ });
+ test('child modal dialog', function() {
+ dialog.showModal();
+
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ dialog.appendChild(input);
+ input.focus();
+ assert.equal(document.activeElement, input);
+
+ // NOTE: This is a single sub-test, but all the above tests could be run
+ // again in a sub-context (i.e., dialog within dialog).
+ var child = createDialog();
+ child.showModal();
+ assert.notEqual(document.activeElement, input,
+ 'additional modal dialog should clear parent focus');
+
+ child.close();
+ assert.notEqual(document.activeElement, input,
+ 'parent focus should not be restored');
+ });
+ test('don\'t scroll anything into focus', function() {
+ // https://github.com/GoogleChrome/dialog-polyfill/issues/119
+
+ var div = cleanup(document.createElement('div'));
+ document.body.appendChild(div);
+
+ var inner = document.createElement('div');
+ inner.style.height = '10000px';
+ div.appendChild(inner);
+
+ div.appendChild(dialog);
+
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ dialog.appendChild(input);
+
+ var prev = document.documentElement.scrollTop;
+ dialog.showModal();
+ assert.equal(document.documentElement.scrollTop, prev);
+ });
+ });
+
+ suite('top layer / inert', function() {
+ test('background focus allowed on non-modal', function() {
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ document.body.appendChild(input);
+ input.focus();
+
+ dialog.show();
+ assert.notEqual(document.activeElement, input,
+ 'non-modal dialog should clear focus, even with no dialog content');
+
+ document.body.focus();
+ input.focus();
+ assert.equal(document.activeElement, input,
+ 'non-modal should allow background focus');
+ });
+ test('modal disallows background focus', function() {
+ var input = cleanup(document.createElement('input'));
+ input.type = 'text';
+ document.body.appendChild(input);
+
+ dialog.showModal();
+ input.focus();
+
+ if (!document.hasFocus()) {
+ // Browsers won't trigger a focus event if they're not in the
+ // foreground, so we can't intercept it. However, they'll fire one when
+ // restored, before a user can get to any incorrectly focused element.
+ console.warn('background focus test requires document focus');
+ document.documentElement.focus();
+ }
+ assert.notEqual(document.activeElement, input,
+ 'modal should disallow background focus');
+ });
+ test('overlay is a sibling of topmost dialog', function() {
+ var stacking = cleanup(document.createElement('div'));
+ stacking.style.opacity = 0.8; // creates stacking context
+ document.body.appendChild(stacking);
+ stacking.appendChild(dialog);
+ dialog.showModal();
+
+ var overlay = document.querySelector('._dialog_overlay');
+ assert.isNotNull(overlay);
+ assert.equal(overlay.parentNode, dialog.parentNode);
+ });
+ test('overlay is between topmost and remaining dialogs', function() {
+ dialog.showModal();
+
+ var other = cleanup(createDialog());
+ document.body.appendChild(other);
+ other.showModal();
+
+ var overlay = document.querySelector('._dialog_overlay');
+ assert.isNotNull(overlay);
+ assert.equal(overlay.parentNode, other.parentNode);
+
+ assert.isAbove(+other.style.zIndex, +overlay.style.zIndex, 'top-most dialog above overlay');
+ assert.isAbove(+overlay.style.zIndex, +dialog.style.zIndex, 'overlay above other dialogs');
+ });
+ });
+
+ suite('events', function() {
+ test('close event', function() {
+ var closeFired = 0;
+ dialog.addEventListener('close', function() {
+ ++closeFired;
+ });
+
+ dialog.show();
+ assert.equal(closeFired, 0);
+
+ dialog.close();
+ assert.equal(closeFired, 1);
+
+ assert.throws(dialog.close); // can't close already closed dialog
+ assert.equal(closeFired, 1);
+
+ dialog.showModal();
+ dialog.close();
+ assert.equal(closeFired, 2);
+ });
+ test('cancel event', function() {
+ dialog.showModal();
+ dialog.dispatchEvent(createKeyboardEvent(27));
+ assert.isFalse(dialog.open, 'esc should close modal');
+
+ var cancelFired = 0;
+ dialog.addEventListener('cancel', function() {
+ ++cancelFired;
+ });
+ dialog.showModal();
+ dialog.dispatchEvent(createKeyboardEvent(27));
+ assert.equal(cancelFired, 1, 'expected cancel to be fired');
+ assert.isFalse(dialog.open), 'esc should close modal again';
+
+ // Sanity-check that non-modals aren't effected.
+ dialog.show();
+ dialog.dispatchEvent(createKeyboardEvent(27));
+ assert.isTrue(dialog.open, 'esc should only close modal dialog');
+ assert.equal(cancelFired, 1);
+ });
+ test('overlay click is prevented', function() {
+ dialog.showModal();
+
+ var overlay = document.querySelector('._dialog_overlay');
+ assert.isNotNull(overlay);
+
+ var helper = function(ev) {
+ throw Error('body should not be clicked');
+ };
+ try {
+ document.body.addEventListener('click', helper);
+ overlay.click();
+ } finally {
+ document.body.removeEventListener('click', helper);
+ }
+ });
+ });
+
+ suite('form', function() {
+ test('method attribute is translated to property', function() {
+ var form = document.createElement('form');
+ form.method = 'dialog';
+ assert.equal(form.method, 'dialog');
+
+ form.method = 'PoSt';
+ assert.equal(form.method, 'post');
+ assert.equal(form.getAttribute('method'), 'PoSt');
+ });
+ test('dialog method input', function() {
+ var value = 'ExpectedValue' + Math.random();
+
+ var form = document.createElement('form');
+ try {
+ form.method = 'dialog';
+ } catch (e) {
+ // Setting the method directly throws an exception in <=IE9.
+ form.setAttribute('method', 'dialog');
+ }
+ dialog.appendChild(form);
+
+ var input = document.createElement('input');
+ input.type = 'submit';
+ input.value = value;
+ form.appendChild(input);
+
+ var closeCount = 0;
+ dialog.addEventListener('close', function() {
+ ++closeCount;
+ });
+
+ dialog.show();
+ input.focus(); // emulate user focus action
+ input.click();
+
+ assert.isFalse(dialog.open);
+ assert.equal(dialog.returnValue, value);
+ assert.equal(closeCount, 1);
+ });
+ test('dialog with button preventDefault does not trigger submit', function() {
+ var form = document.createElement('form');
+ form.setAttribute('method', 'dialog');
+ dialog.appendChild(form);
+
+ var button = document.createElement('button');
+ button.value = 'does not matter';
+ form.appendChild(button);
+ button.addEventListener('click', function(ev) {
+ ev.preventDefault();
+ });
+
+ dialog.showModal();
+ button.click();
+
+ assert.isTrue(dialog.open, 'dialog should remain open');
+ assert.equal(dialog.returnValue, '');
+ });
+ test('dialog programmatic submit does not change returnValue', function() {
+ var form = document.createElement('form');
+ form.setAttribute('method', 'dialog');
+
+ dialog.returnValue = 'manually set'; // set before appending
+ dialog.appendChild(form);
+
+ dialog.showModal();
+ form.submit();
+ assert.isFalse(dialog.open);
+
+ assert.equal(dialog.returnValue, 'manually set', 'returnValue should not change');
+ });
+ test('dialog method button', function() {
+ var value = 'ExpectedValue' + Math.random();
+
+ var form = document.createElement('form');
+ form.setAttribute('method', 'dialog');
+ dialog.appendChild(form);
+
+ var button = document.createElement('button');
+ button.value = value;
+ form.appendChild(button);
+
+ dialog.showModal();
+ button.focus(); // emulate user focus action
+ button.click();
+
+ assert.isFalse(dialog.open);
+ assert.equal(dialog.returnValue, value);
+
+ // Clear button value, confirm textContent is not used as value.
+ button.value = 'blah blah';
+ button.removeAttribute('value');
+ button.textContent = value;
+ dialog.show();
+ button.focus(); // emulate user focus action
+ button.click();
+
+ assert.equal(dialog.returnValue, button.value,
+ 'don\'t take button textContent as value');
+ });
+ test('boring form inside dialog', function() {
+ var form = document.createElement('form');
+ dialog.appendChild(form); // don't specify method
+ form.addEventListener('submit', function(ev) {
+ ev.preventDefault();
+ });
+
+ var button = document.createElement('button');
+ button.value = 'Moot';
+ form.appendChild(button);
+
+ dialog.showModal();
+ button.focus(); // emulate user focus action
+ button.click();
+
+ assert.isTrue(dialog.open, 'non-dialog form should not close dialog')
+ assert(!dialog.returnValue);
+ });
+ test('type="image" submitter', function() {
+ var form = document.createElement('form');
+ form.setAttribute('method', 'dialog');
+ dialog.appendChild(form);
+ dialog.show();
+
+ var image = document.createElement('input');
+ image.type = 'image';
+ image.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
+ image.setAttribute('value', 'image should not accept value');
+ form.appendChild(image);
+ image.click();
+
+ assert.notEqual(image.getAttribute('value'), dialog.returnValue);
+ assert.equal(dialog.returnValue, '0,0');
+ });
+ test('form submitter across dialogs', function() {
+ var form1 = document.createElement('form');
+ form1.setAttribute('method', 'dialog');
+ dialog.appendChild(form1);
+
+ var button1 = document.createElement('button');
+ button1.value = 'from form1: first value';
+ form1.appendChild(button1);
+ dialog.showModal();
+
+ var dialog2 = createDialog();
+ dialog2.returnValue = 'dialog2 default close value';
+ var form2 = document.createElement('form');
+ form2.setAttribute('method', 'dialog');
+ dialog2.appendChild(form2);
+ dialog2.showModal();
+
+ button1.click();
+ assert.isFalse(dialog.open);
+
+ // nb. this never fires 'submit' so the .returnValue can't be wrong: is there another way
+ // to submit a form that doesn't involve a click (enter implicitly 'clicks') or submit?
+ form2.submit();
+ assert.isFalse(dialog2.open);
+
+ assert.equal(dialog2.returnValue, 'dialog2 default close value',
+ 'second dialog shouldn\'t reuse formSubmitter');
+ });
+ });
+
+ suite('order', function() {
+ test('non-modal unchanged', function() {
+ var one = createDialog();
+ var two = createDialog();
+
+ one.style.zIndex = 100;
+ two.style.zIndex = 200;
+ one.show();
+ two.show();
+
+ assert.equal(window.getComputedStyle(one).zIndex, 100);
+ assert.equal(window.getComputedStyle(two).zIndex, 200);
+
+ two.close();
+ assert.equal(window.getComputedStyle(two).zIndex, 200);
+ });
+ test('modal stacking order', function() {
+ dialog.showModal();
+
+ // Create incorrectly-named dialogs: front has a lower z-index, and back
+ // has a higher z-index.
+ var front = createDialog();
+ var back = createDialog();
+ front.style.zIndex = 100;
+ back.style.zIndex = 200;
+
+ // Show back first, then front. Thus we expect back to be behind front.
+ back.showModal();
+ front.showModal();
+
+ var zf = +window.getComputedStyle(front).zIndex;
+ var zb = +window.getComputedStyle(back).zIndex;
+ assert.isAbove(zf, zb, 'showModal order dictates z-index');
+
+ var backBackdrop = back.nextElementSibling;
+ var zbb = +window.getComputedStyle(backBackdrop).zIndex;
+ assert.equal(backBackdrop.className, 'backdrop');
+ assert.isBelow(zbb, zb, 'backdrop below dialog');
+
+ var frontBackdrop = front.nextElementSibling;
+ var zfb = +window.getComputedStyle(frontBackdrop).zIndex
+ assert.equal(frontBackdrop.className, 'backdrop');
+ assert.isBelow(zfb, zf,' backdrop below dialog');
+
+ assert.isAbove(zfb, zb, 'front backdrop is above back dialog');
+
+ front.close();
+ assert.notOk(front.style.zIndex, 'modal close should clear zindex');
+ });
+ });
+
+ suite('press tab key', function() {
+ test('tab key', function() {
+ var dialog = createDialog();
+ dialog.showModal();
+
+ document.documentElement.dispatchEvent(createKeyboardEvent(9));
+
+ var ev = document.createEvent('Events');
+ ev.initEvent('focus', true, true);
+ document.documentElement.dispatchEvent(ev);
+
+ dialog.close();
+ });
+ });
+}();