Bug 1440358 - Part 1 - Add unit tests for PanelMultiView. r=Gijs

MozReview-Commit-ID: 3WM2Skrg3QV

--HG--
extra : rebase_source : 10a8080363a1c17013e249947314671389d04613
This commit is contained in:
Paolo Amadini 2018-02-26 13:45:09 +00:00
Родитель 53d37c96a7
Коммит 4d3254c032
2 изменённых файлов: 344 добавлений и 0 удалений

Просмотреть файл

@ -164,3 +164,7 @@ subsuite = clipboard
[browser_sidebar_toggle.js]
[browser_remote_tabs_button.js]
[browser_widget_animation.js]
# Unit tests for the PanelMultiView module. These are independent from
# CustomizableUI, but are located here together with the module they're testing.
[browser_PanelMultiView.js]

Просмотреть файл

@ -0,0 +1,340 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Unit tests for the PanelMultiView module.
*/
ChromeUtils.import("resource:///modules/PanelMultiView.jsm");
const PANELS_COUNT = 2;
let gPanelAnchors = [];
let gPanels = [];
let gPanelMultiViews = [];
const PANELVIEWS_COUNT = 4;
let gPanelViews = [];
let gPanelViewLabels = [];
const EVENT_TYPES = ["popupshown", "popuphidden", "PanelMultiViewHidden",
"ViewShowing", "ViewShown", "ViewHiding"];
/**
* Checks that the element is displayed, including the state of the popup where
* the element is located. This can trigger a synchronous reflow if necessary,
* because even though the code under test is designed to avoid synchronous
* reflows, it can raise completion events while a layout flush is still needed.
*
* In production code, event handlers for ViewShown have to wait for a flush if
* they need to read style or layout information, like other code normally does.
*/
function is_visible(element) {
var style = element.ownerGlobal.getComputedStyle(element);
if (style.display == "none")
return false;
if (style.visibility != "visible")
return false;
if (style.display == "-moz-popup" && element.state != "open")
return false;
// Hiding a parent element will hide all its children
if (element.parentNode != element.ownerDocument)
return is_visible(element.parentNode);
return true;
}
/**
* Checks whether the label in the specified view is visible.
*/
function assertLabelVisible(viewIndex, expectedVisible) {
Assert.equal(is_visible(gPanelViewLabels[viewIndex]), expectedVisible,
`Visibility of label in view ${viewIndex}`);
}
/**
* Opens the specified view as the main view in the specified panel.
*/
async function openPopup(panelIndex, viewIndex) {
gPanelMultiViews[panelIndex].setAttribute("mainViewId",
gPanelViews[viewIndex].id);
let promiseShown = BrowserTestUtils.waitForEvent(gPanels[panelIndex],
"popupshown");
PanelMultiView.openPopup(gPanels[panelIndex], gPanelAnchors[panelIndex],
"bottomcenter topright");
await promiseShown;
assertLabelVisible(viewIndex, true);
}
/**
* Closes the specified panel.
*/
async function hidePopup(panelIndex) {
gPanelMultiViews[panelIndex].setAttribute("mainViewId",
gPanelViews[panelIndex].id);
let promiseHidden = BrowserTestUtils.waitForEvent(gPanels[panelIndex],
"popuphidden");
PanelMultiView.hidePopup(gPanels[panelIndex]);
await promiseHidden;
}
/**
* Opens the specified subview in the specified panel.
*/
async function showSubView(panelIndex, viewIndex) {
let promiseShown = BrowserTestUtils.waitForEvent(gPanelViews[viewIndex],
"ViewShown");
gPanelMultiViews[panelIndex].showSubView(gPanelViews[viewIndex]);
await promiseShown;
assertLabelVisible(viewIndex, true);
}
/**
* Navigates backwards to the specified view, which is displayed as a result.
*/
async function goBack(panelIndex, viewIndex) {
let promiseShown = BrowserTestUtils.waitForEvent(gPanelViews[viewIndex],
"ViewShown");
gPanelMultiViews[panelIndex].goBack();
await promiseShown;
assertLabelVisible(viewIndex, true);
}
/**
* Records the specified events on an element into the specified array.
*/
function recordEvents(element, eventTypes, recordArray) {
element.recorders = eventTypes.map(eventType => {
let recorder = {
eventType,
listener(event) {
let eventString = `${event.originalTarget.id}: ${event.type}`;
info(`Event on ${eventString}`);
recordArray.push(eventString);
},
};
element.addEventListener(recorder.eventType, recorder.listener);
return recorder;
});
}
/**
* Stops recording events on an element.
*/
function stopRecordingEvents(element) {
for (let recorder of element.recorders) {
element.removeEventListener(recorder.eventType, recorder.listener);
}
delete element.recorders;
}
/**
* Sets up the elements in the browser window that will be used by all the other
* regression tests. Since the panel and view elements can live anywhere in the
* document, they are simply added to the same toolbar as the panel anchors.
*
* <toolbar id="nav-bar">
* <toolbarbutton/> -> gPanelAnchors[panelIndex]
* <panel> -> gPanels[panelIndex]
* <panelmultiview/> -> gPanelMultiViews[panelIndex]
* </panel>
* <panelview> -> gPanelViews[viewIndex]
* <label/> -> gPanelViewLabels[viewIndex]
* </panelview>
* </toolbar>
*/
add_task(async function test_setup() {
let navBar = document.getElementById("nav-bar");
for (let i = 0; i < PANELS_COUNT; i++) {
gPanelAnchors[i] = document.createElement("toolbarbutton");
gPanelAnchors[i].classList.add("toolbarbutton-1",
"chromeclass-toolbar-additional");
navBar.appendChild(gPanelAnchors[i]);
gPanels[i] = document.createElement("panel");
gPanels[i].id = "panel-" + i;
gPanels[i].setAttribute("type", "arrow");
gPanels[i].setAttribute("photon", true);
navBar.appendChild(gPanels[i]);
gPanelMultiViews[i] = document.createElement("panelmultiview");
gPanelMultiViews[i].id = "panelmultiview-" + i;
gPanels[i].appendChild(gPanelMultiViews[i]);
}
for (let i = 0; i < PANELVIEWS_COUNT; i++) {
gPanelViews[i] = document.createElement("panelview");
gPanelViews[i].id = "panelview-" + i;
navBar.appendChild(gPanelViews[i]);
gPanelViewLabels[i] = document.createElement("label");
gPanelViewLabels[i].setAttribute("value", "PanelView " + i);
gPanelViews[i].appendChild(gPanelViewLabels[i]);
}
registerCleanupFunction(() => {
[...gPanelAnchors, ...gPanels, ...gPanelViews].forEach(e => e.remove());
});
});
/**
* Shows and hides all views in a panel with this static structure:
*
* - Panel 0
* - View 0
* - View 1
* - View 3
* - View 2
*/
add_task(async function test_simple() {
// Show main view 0.
await openPopup(0, 0);
// Show and hide subview 1.
await showSubView(0, 1);
assertLabelVisible(0, false);
await goBack(0, 0);
assertLabelVisible(1, false);
// Show subview 3.
await showSubView(0, 3);
assertLabelVisible(0, false);
// Show and hide subview 2.
await showSubView(0, 2);
assertLabelVisible(3, false);
await goBack(0, 3);
assertLabelVisible(2, false);
// Hide subview 3.
await goBack(0, 0);
assertLabelVisible(3, false);
// Hide main view 0.
await hidePopup(0);
assertLabelVisible(0, false);
});
/**
* Tests the event sequence in a panel with this static structure:
*
* - Panel 0
* - View 0
* - View 1
* - View 3
* - View 2
*/
add_task(async function test_simple_event_sequence() {
let recordArray = [];
recordEvents(gPanels[0], EVENT_TYPES, recordArray);
await openPopup(0, 0);
await showSubView(0, 1);
await goBack(0, 0);
await showSubView(0, 3);
await showSubView(0, 2);
await goBack(0, 3);
await goBack(0, 0);
await hidePopup(0);
stopRecordingEvents(gPanels[0]);
Assert.deepEqual(recordArray, [
"panelview-0: ViewShowing",
"panelview-0: ViewShown",
"panel-0: popupshown",
"panelview-1: ViewShowing",
"panelview-1: ViewShown",
"panelview-1: ViewHiding",
"panelview-0: ViewShown",
"panelview-3: ViewShowing",
"panelview-3: ViewShown",
"panelview-2: ViewShowing",
"panelview-2: ViewShown",
"panelview-2: ViewHiding",
"panelview-3: ViewShown",
"panelview-3: ViewHiding",
"panelview-0: ViewShown",
"panelview-0: ViewHiding",
"panelmultiview-0: PanelMultiViewHidden",
"panel-0: popuphidden",
]);
});
/**
* Tests reusing views that are already open in another panel. In this test, the
* structure of the first panel will change dynamically:
*
* - Panel 0
* - View 0
* - View 1
* - Panel 1
* - View 1
* - View 2
* - Panel 0
* - View 1
* - View 0
*/
add_task(async function test_switch_event_sequence() {
let recordArray = [];
recordEvents(gPanels[0], EVENT_TYPES, recordArray);
recordEvents(gPanels[1], EVENT_TYPES, recordArray);
// Show panel 0.
await openPopup(0, 0);
await showSubView(0, 1);
// Show panel 1 with the view that is already open and visible in panel 0.
// This will close panel 0 automatically.
await openPopup(1, 1);
await showSubView(1, 2);
// Show panel 0 with a view that is already open but invisible in panel 1.
// This will close panel 1 automatically.
await openPopup(0, 1);
await showSubView(0, 0);
// Hide panel 0.
await hidePopup(0);
stopRecordingEvents(gPanels[0]);
stopRecordingEvents(gPanels[1]);
Assert.deepEqual(recordArray, [
"panelview-0: ViewShowing",
"panelview-0: ViewShown",
"panel-0: popupshown",
"panelview-1: ViewShowing",
"panelview-1: ViewShown",
"panelview-1: ViewHiding",
"panelview-0: ViewHiding",
"panelmultiview-0: PanelMultiViewHidden",
"panel-0: popuphidden",
"panelview-1: ViewShowing",
"panel-1: popupshown",
"panelview-1: ViewShown",
"panelview-2: ViewShowing",
"panelview-2: ViewShown",
"panel-1: popuphidden",
"panelview-2: ViewHiding",
"panelview-1: ViewHiding",
"panelmultiview-1: PanelMultiViewHidden",
"panelview-1: ViewShowing",
"panelview-1: ViewShown",
"panel-0: popupshown",
"panelview-0: ViewShowing",
"panelview-0: ViewShown",
"panelview-0: ViewHiding",
"panelview-1: ViewHiding",
"panelmultiview-0: PanelMultiViewHidden",
"panel-0: popuphidden",
]);
});