mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-10-24 15:24:18 +00:00
433 lines
17 KiB
JavaScript
433 lines
17 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
var gTestTab;
|
|
var gContentAPI;
|
|
var gContentWindow;
|
|
var gMessageHandlers;
|
|
var loopButton;
|
|
var fakeRoom;
|
|
var loopPanel = document.getElementById("loop-notification-panel");
|
|
|
|
const { LoopAPI } = Cu.import("chrome://loop/content/modules/MozLoopAPI.jsm", {});
|
|
const { LoopRooms } = Cu.import("chrome://loop/content/modules/LoopRooms.jsm", {});
|
|
const { MozLoopServiceInternal } = Cu.import("chrome://loop/content/modules/MozLoopService.jsm", {});
|
|
|
|
function test() {
|
|
UITourTest();
|
|
}
|
|
|
|
function runOffline(fun) {
|
|
return (done) => {
|
|
Services.io.offline = true;
|
|
fun(function onComplete() {
|
|
Services.io.offline = false;
|
|
done();
|
|
});
|
|
}
|
|
}
|
|
|
|
var tests = [
|
|
taskify(function* test_gettingStartedClicked_linkOpenedWithExpectedParams() {
|
|
Services.prefs.setBoolPref("loop.gettingStarted.seen", false);
|
|
Services.prefs.setCharPref("loop.gettingStarted.url", "http://example.com");
|
|
is(loopButton.open, false, "Menu should initially be closed");
|
|
loopButton.click();
|
|
|
|
yield waitForConditionPromise(() => {
|
|
return loopButton.open;
|
|
}, "Menu should be visible after showMenu()");
|
|
|
|
gContentAPI.registerPageID("hello-tour_OpenPanel_testPage");
|
|
yield new Promise(resolve => {
|
|
gContentAPI.ping(() => resolve());
|
|
});
|
|
|
|
let loopDoc = document.getElementById("loop-notification-panel").children[0].contentDocument;
|
|
yield waitForConditionPromise(() => {
|
|
return loopDoc.readyState == 'complete';
|
|
}, "Loop notification panel document should be fully loaded.", 50);
|
|
let gettingStartedButton = loopDoc.getElementById("fte-button");
|
|
ok(gettingStartedButton, "Getting Started button should be found");
|
|
|
|
let newTabPromise = waitForConditionPromise(() => {
|
|
return gBrowser.currentURI.path.includes("utm_source=firefox-browser");
|
|
}, "New tab with utm_content=testPageNewID should have opened");
|
|
|
|
gettingStartedButton.click();
|
|
yield newTabPromise;
|
|
ok(gBrowser.currentURI.path.includes("utm_content=hello-tour_OpenPanel_testPage"),
|
|
"Expected URL opened (" + gBrowser.currentURI.path + ")");
|
|
yield gBrowser.removeCurrentTab();
|
|
|
|
checkLoopPanelIsHidden();
|
|
}),
|
|
taskify(function* test_gettingStartedClicked_linkOpenedWithExpectedParams2() {
|
|
Services.prefs.setBoolPref("loop.gettingStarted.seen", false);
|
|
// Force a refresh of the loop panel since going from seen -> unseen doesn't trigger
|
|
// automatic re-rendering.
|
|
let loopWin = document.getElementById("loop-notification-panel").children[0].contentWindow;
|
|
var event = new loopWin.CustomEvent("GettingStartedSeen", { detail: false });
|
|
loopWin.dispatchEvent(event);
|
|
|
|
UITour.pageIDsForSession.clear();
|
|
Services.prefs.setCharPref("loop.gettingStarted.url", "http://example.com");
|
|
is(loopButton.open, false, "Menu should initially be closed");
|
|
loopButton.click();
|
|
|
|
yield waitForConditionPromise(() => {
|
|
return loopButton.open;
|
|
}, "Menu should be visible after showMenu()");
|
|
|
|
|
|
gContentAPI.registerPageID("hello-tour_OpenPanel_testPageOldId");
|
|
yield new Promise(resolve => {
|
|
gContentAPI.ping(() => resolve());
|
|
});
|
|
// Set the time of the page ID to 10 hours earlier, so that it is considered "expired".
|
|
UITour.pageIDsForSession.set("hello-tour_OpenPanel_testPageOldId",
|
|
{lastSeen: Date.now() - (10 * 60 * 60 * 1000)});
|
|
|
|
let loopDoc = loopWin.document;
|
|
let gettingStartedButton = loopDoc.getElementById("fte-button");
|
|
ok(gettingStartedButton, "Getting Started button should be found");
|
|
|
|
let newTabPromise = waitForConditionPromise(() => {
|
|
Services.console.logStringMessage(gBrowser.currentURI.path);
|
|
return gBrowser.currentURI.path.includes("utm_source=firefox-browser");
|
|
}, "New tab with utm_content=testPageNewID should have opened");
|
|
|
|
gettingStartedButton.click();
|
|
yield newTabPromise;
|
|
ok(!gBrowser.currentURI.path.includes("utm_content=hello-tour_OpenPanel_testPageOldId"),
|
|
"Expected URL opened without the utm_content parameter (" +
|
|
gBrowser.currentURI.path + ")");
|
|
yield gBrowser.removeCurrentTab();
|
|
|
|
checkLoopPanelIsHidden();
|
|
}),
|
|
taskify(function* test_menu_show_hide() {
|
|
// The targets to highlight only appear after getting started is launched.
|
|
Services.prefs.setBoolPref("loop.gettingStarted.seen", true);
|
|
is(loopButton.open, false, "Menu should initially be closed");
|
|
gContentAPI.showMenu("loop");
|
|
|
|
yield waitForConditionPromise(() => {
|
|
return loopButton.open;
|
|
}, "Menu should be visible after showMenu()");
|
|
|
|
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should be on the loop panel");
|
|
ok(loopPanel.hasAttribute("panelopen"), "The panel should have @panelopen");
|
|
is(loopPanel.state, "open", "The panel should be open");
|
|
ok(loopButton.hasAttribute("open"), "Loop button should know that the menu is open");
|
|
|
|
gContentAPI.hideMenu("loop");
|
|
yield waitForConditionPromise(() => {
|
|
return !loopButton.open;
|
|
}, "Menu should be hidden after hideMenu()");
|
|
|
|
checkLoopPanelIsHidden();
|
|
}),
|
|
// Test the menu was cleaned up in teardown.
|
|
taskify(function* setup_menu_cleanup() {
|
|
gContentAPI.showMenu("loop");
|
|
|
|
yield waitForConditionPromise(() => {
|
|
return loopButton.open;
|
|
}, "Menu should be visible after showMenu()");
|
|
|
|
// Leave it open so it gets torn down and we can test below that teardown was succesful.
|
|
}),
|
|
taskify(function* test_menu_cleanup() {
|
|
// Test that the open menu from above was torn down fully.
|
|
checkLoopPanelIsHidden();
|
|
}),
|
|
function test_availableTargets(done) {
|
|
gContentAPI.showMenu("loop");
|
|
gContentAPI.getConfiguration("availableTargets", (data) => {
|
|
for (let targetName of ["loop-newRoom", "loop-roomList", "loop-signInUpLink"]) {
|
|
isnot(data.targets.indexOf(targetName), -1, targetName + " should exist");
|
|
}
|
|
done();
|
|
});
|
|
},
|
|
function test_getConfigurationLoop(done) {
|
|
let gettingStartedSeen = Services.prefs.getBoolPref("loop.gettingStarted.seen");
|
|
gContentAPI.getConfiguration("loop", (data) => {
|
|
is(data.gettingStartedSeen, gettingStartedSeen,
|
|
"The configuration property should equal that of the pref");
|
|
done();
|
|
});
|
|
},
|
|
function test_hideMenuHidesAnnotations(done) {
|
|
let infoPanel = document.getElementById("UITourTooltip");
|
|
let highlightPanel = document.getElementById("UITourHighlightContainer");
|
|
|
|
gContentAPI.showMenu("loop", function menuCallback() {
|
|
gContentAPI.showHighlight("loop-roomList");
|
|
gContentAPI.showInfo("loop-newRoom", "Make a new room", "AKA. conversation");
|
|
UITour.getTarget(window, "loop-newRoom").then((target) => {
|
|
waitForPopupAtAnchor(infoPanel, target.node, Task.async(function* checkPanelIsOpen() {
|
|
isnot(loopPanel.state, "closed", "Loop panel should still be open");
|
|
ok(loopPanel.hasAttribute("noautohide"), "@noautohide should still be on the loop panel");
|
|
is(highlightPanel.getAttribute("targetName"), "loop-roomList", "Check highlight @targetname");
|
|
is(infoPanel.getAttribute("targetName"), "loop-newRoom", "Check info panel @targetname");
|
|
|
|
info("Close the loop menu and make sure the annotations inside disappear");
|
|
let hiddenPromises = [promisePanelElementHidden(window, infoPanel),
|
|
promisePanelElementHidden(window, highlightPanel)];
|
|
gContentAPI.hideMenu("loop");
|
|
yield Promise.all(hiddenPromises);
|
|
isnot(infoPanel.state, "open", "Info panel should have automatically hid");
|
|
isnot(highlightPanel.state, "open", "Highlight panel should have automatically hid");
|
|
done();
|
|
}), "Info panel should be anchored to the new room button");
|
|
});
|
|
});
|
|
},
|
|
runOffline(function test_notifyLoopChatWindowOpenedClosed(done) {
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
|
gContentAPI.observe((event, params) => {
|
|
ok(false, "No more notifications should have arrived");
|
|
});
|
|
});
|
|
done();
|
|
});
|
|
document.querySelector("#pinnedchats > chatbox").close();
|
|
});
|
|
LoopRooms.open("fakeTourRoom");
|
|
}),
|
|
runOffline(function test_notifyLoopRoomURLCopied(done) {
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
|
|
|
let chat = document.querySelector("#pinnedchats > chatbox");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:RoomURLCopied", "Check Loop:RoomURLCopied notification");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
|
});
|
|
chat.close();
|
|
done();
|
|
});
|
|
|
|
let window = chat.content.contentWindow;
|
|
waitForConditionPromise(
|
|
() => chat.content.contentDocument.querySelector(".btn-copy"),
|
|
"Copy button should be there"
|
|
).then(() => chat.content.contentDocument.querySelector(".btn-copy").click());
|
|
});
|
|
});
|
|
LoopRooms.open("fakeTourRoom");
|
|
}),
|
|
runOffline(function test_notifyLoopRoomURLEmailed(done) {
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowOpened", "Loop chat window should've opened");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
|
|
|
|
let chat = document.querySelector("#pinnedchats > chatbox");
|
|
let composeEmailCalled = false;
|
|
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:RoomURLEmailed", "Check Loop:RoomURLEmailed notification");
|
|
ok(composeEmailCalled, "mozLoop.composeEmail should be called");
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
|
|
});
|
|
chat.close();
|
|
done();
|
|
});
|
|
|
|
gMessageHandlers.ComposeEmail = function(message, reply) {
|
|
let [subject, body, recipient] = message.data;
|
|
ok(subject, "composeEmail should be invoked with at least a subject value");
|
|
composeEmailCalled = true;
|
|
reply();
|
|
};
|
|
|
|
waitForConditionPromise(
|
|
() => chat.content.contentDocument.querySelector(".btn-email"),
|
|
"Email button should be there"
|
|
).then(() => chat.content.contentDocument.querySelector(".btn-email").click());
|
|
});
|
|
});
|
|
LoopRooms.open("fakeTourRoom");
|
|
}),
|
|
taskify(function* test_arrow_panel_position() {
|
|
is(loopButton.open, false, "Menu should initially be closed");
|
|
let popup = document.getElementById("UITourTooltip");
|
|
|
|
yield showMenuPromise("loop");
|
|
|
|
let currentTarget = "loop-newRoom";
|
|
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
|
|
is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
|
|
|
|
currentTarget = "loop-roomList";
|
|
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be on the side");
|
|
is(popup.popupBoxObject.alignmentPosition, "start_before", "Check " + currentTarget + " position");
|
|
|
|
currentTarget = "loop-signInUpLink";
|
|
yield showInfoPromise(currentTarget, "This is " + currentTarget, "My arrow should be underneath");
|
|
is(popup.popupBoxObject.alignmentPosition, "after_end", "Check " + currentTarget + " position");
|
|
}),
|
|
taskify(function* test_setConfiguration() {
|
|
is(Services.prefs.getBoolPref("loop.gettingStarted.resumeOnFirstJoin"), false, "pref should be false but exist");
|
|
gContentAPI.setConfiguration("Loop:ResumeTourOnFirstJoin", true);
|
|
|
|
yield waitForConditionPromise(() => {
|
|
return Services.prefs.getBoolPref("loop.gettingStarted.resumeOnFirstJoin");
|
|
}, "Pref should change to true via setConfiguration");
|
|
|
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
|
}),
|
|
taskify(function* test_resumeViaMenuPanel_roomClosedTabOpen() {
|
|
Services.prefs.setBoolPref("loop.gettingStarted.resumeOnFirstJoin", true);
|
|
|
|
// Create a fake room and then add a fake non-owner participant
|
|
let roomsMap = setupFakeRoom();
|
|
roomsMap.get("fakeTourRoom").participants = [{
|
|
owner: false,
|
|
}];
|
|
|
|
// Set the tour URL to be the current page with a different query param
|
|
let gettingStartedURL = gTestTab.linkedBrowser.currentURI.resolve("?gettingstarted=1");
|
|
Services.prefs.setCharPref("loop.gettingStarted.url", gettingStartedURL);
|
|
|
|
let observationPromise = new Promise((resolve) => {
|
|
gContentAPI.observe((event, params) => {
|
|
is(event, "Loop:IncomingConversation", "Page should have been notified about incoming conversation");
|
|
is(params.conversationOpen, false, "conversationOpen should be false");
|
|
is(gBrowser.selectedTab, gTestTab, "The same tab should be selected");
|
|
resolve();
|
|
});
|
|
});
|
|
|
|
// Now open the menu while that non-owner is in the fake room to trigger resuming the tour
|
|
yield showMenuPromise("loop");
|
|
|
|
yield observationPromise;
|
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
|
}),
|
|
taskify(function* test_resumeViaMenuPanel_roomClosedTabClosed() {
|
|
Services.prefs.setBoolPref("loop.gettingStarted.resumeOnFirstJoin", true);
|
|
|
|
// Create a fake room and then add a fake non-owner participant
|
|
let roomsMap = setupFakeRoom();
|
|
roomsMap.get("fakeTourRoom").participants = [{
|
|
owner: false,
|
|
}];
|
|
|
|
// Set the tour URL to a page that's not open yet
|
|
Services.prefs.setCharPref("loop.gettingStarted.url", gBrowser.currentURI.prePath);
|
|
|
|
let newTabPromise = waitForConditionPromise(() => {
|
|
return gBrowser.currentURI.path.includes("incomingConversation=waiting");
|
|
}, "New tab with incomingConversation=waiting should have opened");
|
|
|
|
// Now open the menu while that non-owner is in the fake room to trigger resuming the tour
|
|
yield showMenuPromise("loop");
|
|
|
|
yield newTabPromise;
|
|
|
|
yield gBrowser.removeCurrentTab();
|
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
|
}),
|
|
];
|
|
|
|
// End tests
|
|
|
|
function checkLoopPanelIsHidden() {
|
|
ok(!loopPanel.hasAttribute("noautohide"), "@noautohide on the loop panel should have been cleaned up");
|
|
ok(!loopPanel.hasAttribute("panelopen"), "The panel shouldn't have @panelopen");
|
|
isnot(loopPanel.state, "open", "The panel shouldn't be open");
|
|
is(loopButton.hasAttribute("open"), false, "Loop button should know that the panel is closed");
|
|
}
|
|
|
|
function setupFakeRoom() {
|
|
let room = Object.create(fakeRoom);
|
|
let roomsMap = new Map([
|
|
[room.roomToken, room]
|
|
]);
|
|
LoopRooms.stubCache(roomsMap);
|
|
return roomsMap;
|
|
}
|
|
|
|
if (Services.prefs.getBoolPref("loop.enabled")) {
|
|
loopButton = window.LoopUI.toolbarButton.node;
|
|
|
|
fakeRoom = {
|
|
decryptedContext: { roomName: "fakeTourRoom" },
|
|
participants: [],
|
|
maxSize: 2,
|
|
ctime: Date.now()
|
|
};
|
|
for (let prop of ["roomToken", "roomOwner", "roomUrl"])
|
|
fakeRoom[prop] = "fakeTourRoom";
|
|
|
|
LoopAPI.stubMessageHandlers(gMessageHandlers = {
|
|
// Stub the rooms object API to fully control the test behavior.
|
|
"Rooms:*": function(action, message, reply) {
|
|
switch (action.split(":").pop()) {
|
|
case "GetAll":
|
|
reply([fakeRoom]);
|
|
break;
|
|
case "Get":
|
|
reply(fakeRoom);
|
|
break;
|
|
case "Join":
|
|
reply({
|
|
apiKey: "fakeTourRoom",
|
|
sessionToken: "fakeTourRoom",
|
|
sessionId: "fakeTourRoom",
|
|
expires: Date.now() + 240000
|
|
});
|
|
break;
|
|
case "RefreshMembership":
|
|
reply({ expires: Date.now() + 240000 });
|
|
default:
|
|
reply();
|
|
}
|
|
},
|
|
// Stub the metadata retrieval to suppress console warnings and return faster.
|
|
GetSelectedTabMetadata: function(message, reply) {
|
|
reply({ favicon: null });
|
|
}
|
|
});
|
|
|
|
registerCleanupFunction(() => {
|
|
Services.prefs.clearUserPref("loop.gettingStarted.resumeOnFirstJoin");
|
|
Services.prefs.clearUserPref("loop.gettingStarted.seen");
|
|
Services.prefs.clearUserPref("loop.gettingStarted.url");
|
|
Services.io.offline = false;
|
|
|
|
// Copied from browser/components/loop/test/mochitest/head.js
|
|
// Remove the iframe after each test. This also avoids mochitest complaining
|
|
// about leaks on shutdown as we intentionally hold the iframe open for the
|
|
// life of the application.
|
|
let frameId = loopButton.getAttribute("notificationFrameId");
|
|
let frame = document.getElementById(frameId);
|
|
if (frame) {
|
|
frame.remove();
|
|
}
|
|
|
|
// Remove the stubbed rooms.
|
|
LoopRooms.stubCache(null);
|
|
// Restore the stubbed handlers.
|
|
LoopAPI.restore();
|
|
});
|
|
} else {
|
|
ok(true, "Loop is disabled so skip the UITour Loop tests");
|
|
tests = [];
|
|
}
|