forked from mirrors/gecko-dev
1234 lines
39 KiB
JavaScript
1234 lines
39 KiB
JavaScript
"use strict";
|
|
|
|
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
|
/* global UIState */
|
|
|
|
const lastModifiedFixture = 1507655615.87; // Approx Oct 10th 2017
|
|
const mockTargets = [
|
|
{
|
|
id: "0",
|
|
name: "foo",
|
|
type: "phone",
|
|
clientRecord: {
|
|
id: "cli0",
|
|
serverLastModified: lastModifiedFixture,
|
|
type: "phone",
|
|
},
|
|
},
|
|
{
|
|
id: "1",
|
|
name: "bar",
|
|
type: "desktop",
|
|
clientRecord: {
|
|
id: "cli1",
|
|
serverLastModified: lastModifiedFixture,
|
|
type: "desktop",
|
|
},
|
|
},
|
|
{
|
|
id: "2",
|
|
name: "baz",
|
|
type: "phone",
|
|
clientRecord: {
|
|
id: "cli2",
|
|
serverLastModified: lastModifiedFixture,
|
|
type: "phone",
|
|
},
|
|
},
|
|
{ id: "3", name: "no client record device", type: "phone" },
|
|
];
|
|
|
|
add_task(async function openPanel() {
|
|
if (AppConstants.platform == "macosx") {
|
|
// Ignore this test on Mac.
|
|
return;
|
|
}
|
|
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Should still open the panel when Ctrl key is pressed.
|
|
await promisePageActionPanelOpen({ ctrlKey: true });
|
|
|
|
// Done.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
});
|
|
});
|
|
|
|
add_task(async function starButtonCtrlClick() {
|
|
// On macOS, ctrl-click shouldn't open the panel because this normally opens
|
|
// the context menu. This happens via the `contextmenu` event which is created
|
|
// by widget code, so our simulated clicks do not do so, so we can't test
|
|
// anything on macOS.
|
|
if (AppConstants.platform == "macosx") {
|
|
return;
|
|
}
|
|
|
|
// Open a unique page.
|
|
let url = "http://example.com/browser_page_action_star_button";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
StarUI._createPanelIfNeeded();
|
|
// The button ignores activation while the bookmarked status is being
|
|
// updated. So, wait for it to finish updating.
|
|
await TestUtils.waitForCondition(
|
|
() => BookmarkingUI.status != BookmarkingUI.STATUS_UPDATING
|
|
);
|
|
|
|
const popup = document.getElementById("editBookmarkPanel");
|
|
const starButtonBox = document.getElementById("star-button-box");
|
|
|
|
let shownPromise = promisePanelShown(popup);
|
|
EventUtils.synthesizeMouseAtCenter(starButtonBox, { ctrlKey: true });
|
|
await shownPromise;
|
|
ok(true, "Panel shown after button pressed");
|
|
|
|
let hiddenPromise = promisePanelHidden(popup);
|
|
document.getElementById("editBookmarkPanelRemoveButton").click();
|
|
await hiddenPromise;
|
|
});
|
|
});
|
|
|
|
add_task(async function bookmark() {
|
|
// Open a unique page.
|
|
let url = "http://example.com/browser_page_action_menu";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
|
|
// The bookmark button should read "Bookmark This Page" and not be starred.
|
|
let bookmarkButton = document.getElementById("pageAction-panel-bookmark");
|
|
Assert.equal(bookmarkButton.label, "Bookmark This Page");
|
|
Assert.ok(!bookmarkButton.hasAttribute("starred"));
|
|
|
|
// Click the button.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
EventUtils.synthesizeMouseAtCenter(bookmarkButton, {});
|
|
await hiddenPromise;
|
|
|
|
// Make sure the edit-bookmark panel opens, then hide it.
|
|
await new Promise(resolve => {
|
|
if (StarUI.panel.state == "open") {
|
|
resolve();
|
|
return;
|
|
}
|
|
StarUI.panel.addEventListener("popupshown", resolve, { once: true });
|
|
});
|
|
Assert.equal(
|
|
BookmarkingUI.starBox.getAttribute("open"),
|
|
"true",
|
|
"Star has open attribute"
|
|
);
|
|
StarUI.panel.hidePopup();
|
|
Assert.ok(
|
|
!BookmarkingUI.starBox.hasAttribute("open"),
|
|
"Star no longer has open attribute"
|
|
);
|
|
|
|
// Open the panel again.
|
|
await promisePageActionPanelOpen();
|
|
|
|
// The bookmark button should now read "Edit This Bookmark" and be starred.
|
|
Assert.equal(bookmarkButton.label, "Edit This Bookmark");
|
|
Assert.ok(bookmarkButton.hasAttribute("starred"));
|
|
Assert.equal(bookmarkButton.getAttribute("starred"), "true");
|
|
|
|
// Click it again.
|
|
hiddenPromise = promisePageActionPanelHidden();
|
|
EventUtils.synthesizeMouseAtCenter(bookmarkButton, {});
|
|
await hiddenPromise;
|
|
|
|
// The edit-bookmark panel should open again.
|
|
await new Promise(resolve => {
|
|
if (StarUI.panel.state == "open") {
|
|
resolve();
|
|
return;
|
|
}
|
|
StarUI.panel.addEventListener("popupshown", resolve, { once: true });
|
|
});
|
|
|
|
let onItemRemovedPromise = PlacesTestUtils.waitForNotification(
|
|
"bookmark-removed",
|
|
events => events.some(event => event.url == url),
|
|
"places"
|
|
);
|
|
|
|
// Click the remove-bookmark button in the panel.
|
|
StarUI._element("editBookmarkPanelRemoveButton").click();
|
|
|
|
// Wait for the bookmark to be removed before continuing.
|
|
await onItemRemovedPromise;
|
|
|
|
// Open the panel again.
|
|
await promisePageActionPanelOpen();
|
|
|
|
// The bookmark button should read "Bookmark This Page" and not be starred.
|
|
Assert.equal(bookmarkButton.label, "Bookmark This Page");
|
|
Assert.ok(!bookmarkButton.hasAttribute("starred"));
|
|
|
|
// Done.
|
|
hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
});
|
|
});
|
|
|
|
add_task(async function pinTabFromPanel() {
|
|
// Open an actionable page so that the main page action button appears. (It
|
|
// does not appear on about:blank for example.)
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Open the panel and click Pin Tab.
|
|
await promisePageActionPanelOpen();
|
|
|
|
let pinTabButton = document.getElementById("pageAction-panel-pinTab");
|
|
Assert.equal(pinTabButton.label, "Pin Tab");
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
EventUtils.synthesizeMouseAtCenter(pinTabButton, {});
|
|
await hiddenPromise;
|
|
|
|
Assert.ok(gBrowser.selectedTab.pinned, "Tab was pinned");
|
|
|
|
// Open the panel and click Unpin Tab.
|
|
Assert.equal(pinTabButton.label, "Unpin Tab");
|
|
await promisePageActionPanelOpen();
|
|
|
|
hiddenPromise = promisePageActionPanelHidden();
|
|
EventUtils.synthesizeMouseAtCenter(pinTabButton, {});
|
|
await hiddenPromise;
|
|
|
|
Assert.ok(!gBrowser.selectedTab.pinned, "Tab was unpinned");
|
|
});
|
|
});
|
|
|
|
add_task(async function pinTabFromURLBar() {
|
|
// Open an actionable page so that the main page action button appears. (It
|
|
// does not appear on about:blank for example.)
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Add action to URL bar.
|
|
let action = PageActions._builtInActions.find(a => a.id == "pinTab");
|
|
action.pinnedToUrlbar = true;
|
|
registerCleanupFunction(() => (action.pinnedToUrlbar = false));
|
|
|
|
// Click the Pin Tab button.
|
|
let pinTabButton = document.getElementById("pageAction-urlbar-pinTab");
|
|
EventUtils.synthesizeMouseAtCenter(pinTabButton, {});
|
|
await TestUtils.waitForCondition(
|
|
() => gBrowser.selectedTab.pinned,
|
|
"Tab was pinned"
|
|
);
|
|
|
|
// Click the Unpin Tab button
|
|
EventUtils.synthesizeMouseAtCenter(pinTabButton, {});
|
|
await TestUtils.waitForCondition(
|
|
() => !gBrowser.selectedTab.pinned,
|
|
"Tab was unpinned"
|
|
);
|
|
});
|
|
});
|
|
|
|
add_task(async function emailLink() {
|
|
// Open an actionable page so that the main page action button appears. (It
|
|
// does not appear on about:blank for example.)
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Replace the email-link entry point to check whether it's called.
|
|
let originalFn = MailIntegration.sendLinkForBrowser;
|
|
let fnCalled = false;
|
|
MailIntegration.sendLinkForBrowser = () => {
|
|
fnCalled = true;
|
|
};
|
|
registerCleanupFunction(() => {
|
|
MailIntegration.sendLinkForBrowser = originalFn;
|
|
});
|
|
|
|
// Open the panel and click Email Link.
|
|
await promisePageActionPanelOpen();
|
|
let emailLinkButton = document.getElementById("pageAction-panel-emailLink");
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
EventUtils.synthesizeMouseAtCenter(emailLinkButton, {});
|
|
await hiddenPromise;
|
|
|
|
Assert.ok(fnCalled);
|
|
});
|
|
});
|
|
|
|
add_task(async function copyURLFromPanel() {
|
|
// Open an actionable page so that the main page action button appears. (It
|
|
// does not appear on about:blank for example.)
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Add action to URL bar.
|
|
let action = PageActions._builtInActions.find(a => a.id == "copyURL");
|
|
action.pinnedToUrlbar = true;
|
|
registerCleanupFunction(() => (action.pinnedToUrlbar = false));
|
|
|
|
// Open the panel and click Copy URL.
|
|
await promisePageActionPanelOpen();
|
|
Assert.ok(true, "page action panel opened");
|
|
|
|
let copyURLButton = document.getElementById("pageAction-panel-copyURL");
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
EventUtils.synthesizeMouseAtCenter(copyURLButton, {});
|
|
await hiddenPromise;
|
|
|
|
let feedbackPanel = ConfirmationHint._panel;
|
|
let feedbackShownPromise = BrowserTestUtils.waitForEvent(
|
|
feedbackPanel,
|
|
"popupshown"
|
|
);
|
|
await feedbackShownPromise;
|
|
Assert.equal(
|
|
feedbackPanel.anchorNode.id,
|
|
"pageActionButton",
|
|
"Feedback menu should be anchored on the main Page Action button"
|
|
);
|
|
let feedbackHiddenPromise = promisePanelHidden(feedbackPanel);
|
|
await feedbackHiddenPromise;
|
|
|
|
action.pinnedToUrlbar = false;
|
|
});
|
|
});
|
|
|
|
add_task(async function copyURLFromURLBar() {
|
|
// Open an actionable page so that the main page action button appears. (It
|
|
// does not appear on about:blank for example.)
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Add action to URL bar.
|
|
let action = PageActions._builtInActions.find(a => a.id == "copyURL");
|
|
action.pinnedToUrlbar = true;
|
|
registerCleanupFunction(() => (action.pinnedToUrlbar = false));
|
|
|
|
let copyURLButton = document.getElementById("pageAction-urlbar-copyURL");
|
|
let panel = ConfirmationHint._panel;
|
|
let feedbackShownPromise = promisePanelShown(panel);
|
|
EventUtils.synthesizeMouseAtCenter(copyURLButton, {});
|
|
|
|
await feedbackShownPromise;
|
|
Assert.equal(
|
|
panel.anchorNode.id,
|
|
"pageAction-urlbar-copyURL",
|
|
"Feedback menu should be anchored on the main URL bar button"
|
|
);
|
|
let feedbackHiddenPromise = promisePanelHidden(panel);
|
|
await feedbackHiddenPromise;
|
|
|
|
action.pinnedToUrlbar = false;
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_nonSendable() {
|
|
// Open a tab that's not sendable but where the page action buttons still
|
|
// appear. about:about is convenient.
|
|
await BrowserTestUtils.withNewTab("about:about", async () => {
|
|
await promiseSyncReady();
|
|
// Open the panel. Send to Device should be disabled.
|
|
await promisePageActionPanelOpen();
|
|
Assert.equal(
|
|
BrowserPageActions.mainButtonNode.getAttribute("open"),
|
|
"true",
|
|
"Main button has 'open' attribute"
|
|
);
|
|
let panelButton = BrowserPageActions.panelButtonNodeForActionID(
|
|
"sendToDevice"
|
|
);
|
|
Assert.equal(
|
|
panelButton.disabled,
|
|
true,
|
|
"The panel button should be disabled"
|
|
);
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
Assert.ok(
|
|
!BrowserPageActions.mainButtonNode.hasAttribute("open"),
|
|
"Main button no longer has 'open' attribute"
|
|
);
|
|
// The urlbar button shouldn't exist.
|
|
let urlbarButton = BrowserPageActions.urlbarButtonNodeForActionID(
|
|
"sendToDevice"
|
|
);
|
|
Assert.equal(urlbarButton, null, "The urlbar button shouldn't exist");
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_syncNotReady_other_states() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => null);
|
|
sandbox
|
|
.stub(UIState, "get")
|
|
.returns({ status: UIState.STATUS_NOT_VERIFIED });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
// Click Send to Device.
|
|
let viewPromise = promisePageActionViewShown();
|
|
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
|
let view = await viewPromise;
|
|
Assert.equal(view.id, "pageAction-panel-sendToDevice-subview");
|
|
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "Account Not Verified",
|
|
},
|
|
disabled: true,
|
|
},
|
|
null,
|
|
{
|
|
attrs: {
|
|
label: "Verify Your Account...",
|
|
},
|
|
},
|
|
];
|
|
checkSendToDeviceItems(expectedItems);
|
|
|
|
// Done, hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
|
|
cleanUp();
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_syncNotReady_configured() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
const recentDeviceList = sandbox
|
|
.stub(fxAccounts.device, "recentDeviceList")
|
|
.get(() => null);
|
|
sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
|
|
sandbox.stub(fxAccounts.device, "refreshDeviceList").callsFake(() => {
|
|
recentDeviceList.get(() =>
|
|
mockTargets.map(({ id, name, type }) => ({ id, name, type }))
|
|
);
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
|
.callsFake(fxaDeviceId => {
|
|
let target = mockTargets.find(c => c.id == fxaDeviceId);
|
|
return target ? target.clientRecord : null;
|
|
});
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientType")
|
|
.callsFake(
|
|
id =>
|
|
mockTargets.find(c => c.clientRecord && c.clientRecord.id == id)
|
|
.clientRecord.type
|
|
);
|
|
});
|
|
|
|
let onShowingSubview = BrowserPageActions.sendToDevice.onShowingSubview;
|
|
sandbox
|
|
.stub(BrowserPageActions.sendToDevice, "onShowingSubview")
|
|
.callsFake((...args) => {
|
|
this.numCall++ || (this.numCall = 1);
|
|
onShowingSubview.call(BrowserPageActions.sendToDevice, ...args);
|
|
testSendTabToDeviceMenu(this.numCall);
|
|
});
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
// Click Send to Device.
|
|
let viewPromise = promisePageActionViewShown();
|
|
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
|
let view = await viewPromise;
|
|
Assert.equal(view.id, "pageAction-panel-sendToDevice-subview");
|
|
|
|
function testSendTabToDeviceMenu(numCall) {
|
|
if (numCall == 1) {
|
|
// "Syncing devices" should be shown.
|
|
checkSendToDeviceItems([
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
disabled: true,
|
|
},
|
|
]);
|
|
} else if (numCall == 2) {
|
|
// The devices should be shown in the subview.
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
];
|
|
for (let target of mockTargets) {
|
|
const attrs = {
|
|
clientId: target.id,
|
|
label: target.name,
|
|
clientType: target.type,
|
|
};
|
|
if (target.clientRecord && target.clientRecord.serverLastModified) {
|
|
attrs.tooltiptext = gSync.formatLastSyncDate(
|
|
new Date(target.clientRecord.serverLastModified * 1000)
|
|
);
|
|
}
|
|
expectedItems.push({
|
|
attrs,
|
|
});
|
|
}
|
|
expectedItems.push(null, {
|
|
attrs: {
|
|
label: "Send to All Devices",
|
|
},
|
|
});
|
|
checkSendToDeviceItems(expectedItems);
|
|
} else {
|
|
ok(false, "This should never happen");
|
|
}
|
|
}
|
|
|
|
// Done, hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
cleanUp();
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_notSignedIn() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
// Click Send to Device.
|
|
let viewPromise = promisePageActionViewShown();
|
|
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
|
let view = await viewPromise;
|
|
Assert.equal(view.id, "pageAction-panel-sendToDevice-subview");
|
|
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "Not Signed In",
|
|
},
|
|
disabled: true,
|
|
},
|
|
null,
|
|
{
|
|
attrs: {
|
|
label: "Sign in to Firefox...",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "Learn About Sending Tabs...",
|
|
},
|
|
},
|
|
];
|
|
checkSendToDeviceItems(expectedItems);
|
|
|
|
// Done, hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_noDevices() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => []);
|
|
sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
sandbox.stub(fxAccounts.device, "refreshDeviceList").resolves(true);
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
|
.callsFake(fxaDeviceId => {
|
|
let target = mockTargets.find(c => c.id == fxaDeviceId);
|
|
return target ? target.clientRecord : null;
|
|
});
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientType")
|
|
.callsFake(
|
|
id =>
|
|
mockTargets.find(c => c.clientRecord && c.clientRecord.id == id)
|
|
.clientRecord.type
|
|
);
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
// Click Send to Device.
|
|
let viewPromise = promisePageActionViewShown();
|
|
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
|
let view = await viewPromise;
|
|
Assert.equal(view.id, "pageAction-panel-sendToDevice-subview");
|
|
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "No Devices Connected",
|
|
},
|
|
disabled: true,
|
|
},
|
|
null,
|
|
{
|
|
attrs: {
|
|
label: "Connect Another Device...",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "Learn About Sending Tabs...",
|
|
},
|
|
},
|
|
];
|
|
checkSendToDeviceItems(expectedItems);
|
|
|
|
// Done, hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
|
|
cleanUp();
|
|
|
|
await UIState.reset();
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_devices() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox
|
|
.stub(fxAccounts.device, "recentDeviceList")
|
|
.get(() => mockTargets.map(({ id, name, type }) => ({ id, name, type })));
|
|
sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
sandbox
|
|
.stub(fxAccounts.commands.sendTab, "isDeviceCompatible")
|
|
.returns(true);
|
|
sandbox.stub(fxAccounts.device, "refreshDeviceList").resolves(true);
|
|
sandbox.spy(Weave.Service, "sync");
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
|
.callsFake(fxaDeviceId => {
|
|
let target = mockTargets.find(c => c.id == fxaDeviceId);
|
|
return target ? target.clientRecord : null;
|
|
});
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientType")
|
|
.callsFake(
|
|
id =>
|
|
mockTargets.find(c => c.clientRecord && c.clientRecord.id == id)
|
|
.clientRecord.type
|
|
);
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
// Click Send to Device.
|
|
let viewPromise = promisePageActionViewShown();
|
|
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
|
let view = await viewPromise;
|
|
Assert.equal(view.id, "pageAction-panel-sendToDevice-subview");
|
|
|
|
// The devices should be shown in the subview.
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "1",
|
|
label: "bar",
|
|
clientType: "desktop",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "2",
|
|
label: "baz",
|
|
clientType: "phone",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "0",
|
|
label: "foo",
|
|
clientType: "phone",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "3",
|
|
label: "no client record device",
|
|
clientType: "phone",
|
|
},
|
|
},
|
|
null,
|
|
{
|
|
attrs: {
|
|
label: "Send to All Devices",
|
|
},
|
|
},
|
|
];
|
|
checkSendToDeviceItems(expectedItems);
|
|
|
|
Assert.ok(Weave.Service.sync.notCalled);
|
|
|
|
// Done, hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
|
|
cleanUp();
|
|
});
|
|
});
|
|
|
|
add_task(async function sendTabToDevice_syncEnabled() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => []);
|
|
sandbox
|
|
.stub(UIState, "get")
|
|
.returns({ status: UIState.STATUS_SIGNED_IN, syncEnabled: true });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
sandbox.spy(fxAccounts.device, "refreshDeviceList");
|
|
sandbox.spy(Weave.Service, "sync");
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
|
.callsFake(fxaDeviceId => {
|
|
let target = mockTargets.find(c => c.id == fxaDeviceId);
|
|
return target ? target.clientRecord : null;
|
|
});
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientType")
|
|
.callsFake(
|
|
id =>
|
|
mockTargets.find(c => c.clientRecord && c.clientRecord.id == id)
|
|
.clientRecord.type
|
|
);
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Open the panel.
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
// Click Send to Device.
|
|
let viewPromise = promisePageActionViewShown();
|
|
EventUtils.synthesizeMouseAtCenter(sendToDeviceButton, {});
|
|
let view = await viewPromise;
|
|
Assert.equal(view.id, "pageAction-panel-sendToDevice-subview");
|
|
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "No Devices Connected",
|
|
},
|
|
disabled: true,
|
|
},
|
|
null,
|
|
{
|
|
attrs: {
|
|
label: "Connect Another Device...",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
label: "Learn About Sending Tabs...",
|
|
},
|
|
},
|
|
];
|
|
checkSendToDeviceItems(expectedItems);
|
|
|
|
Assert.ok(Weave.Service.sync.notCalled);
|
|
Assert.equal(fxAccounts.device.refreshDeviceList.callCount, 1);
|
|
|
|
// Done, hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
|
|
cleanUp();
|
|
});
|
|
});
|
|
|
|
add_task(async function sendToDevice_title() {
|
|
// Open two tabs that are sendable.
|
|
await BrowserTestUtils.withNewTab(
|
|
"http://example.com/a",
|
|
async otherBrowser => {
|
|
await BrowserTestUtils.withNewTab("http://example.com/b", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => []);
|
|
sandbox
|
|
.stub(UIState, "get")
|
|
.returns({ status: UIState.STATUS_SIGNED_IN });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
sandbox.stub(fxAccounts.device, "refreshDeviceList").resolves(true);
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
|
.callsFake(fxaDeviceId => {
|
|
let target = mockTargets.find(c => c.id == fxaDeviceId);
|
|
return target ? target.clientRecord : null;
|
|
});
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientType")
|
|
.callsFake(
|
|
id =>
|
|
mockTargets.find(c => c.clientRecord && c.clientRecord.id == id)
|
|
.clientRecord.type
|
|
);
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Open the panel. Only one tab is selected, so the action's title should
|
|
// be "Send Tab to Device".
|
|
await promisePageActionPanelOpen();
|
|
let sendToDeviceButton = document.getElementById(
|
|
"pageAction-panel-sendToDevice"
|
|
);
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
|
|
Assert.equal(sendToDeviceButton.label, "Send Tab to Device");
|
|
Assert.equal(
|
|
PageActions.actionForID("sendToDevice").getTitle(window),
|
|
"Send Tab to Device"
|
|
);
|
|
|
|
// Hide the panel.
|
|
let hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
|
|
// Add the other tab to the selection.
|
|
gBrowser.addToMultiSelectedTabs(
|
|
gBrowser.getTabForBrowser(otherBrowser),
|
|
{ isLastMultiSelectChange: true }
|
|
);
|
|
|
|
// Open the panel again. Now the action's title should be "Send 2 Tabs to
|
|
// Device".
|
|
await promisePageActionPanelOpen();
|
|
Assert.ok(!sendToDeviceButton.disabled);
|
|
Assert.equal(sendToDeviceButton.label, "Send 2 Tabs to Device");
|
|
Assert.equal(
|
|
PageActions.actionForID("sendToDevice").getTitle(window),
|
|
"Send 2 Tabs to Device"
|
|
);
|
|
|
|
// Hide the panel.
|
|
hiddenPromise = promisePageActionPanelHidden();
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
await hiddenPromise;
|
|
|
|
cleanUp();
|
|
|
|
await UIState.reset();
|
|
});
|
|
}
|
|
);
|
|
});
|
|
|
|
add_task(async function sendToDevice_inUrlbar() {
|
|
// Open a tab that's sendable.
|
|
await BrowserTestUtils.withNewTab("http://example.com/", async () => {
|
|
await promiseSyncReady();
|
|
const sandbox = sinon.createSandbox();
|
|
sandbox
|
|
.stub(fxAccounts.device, "recentDeviceList")
|
|
.get(() => mockTargets.map(({ id, name, type }) => ({ id, name, type })));
|
|
sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN });
|
|
sandbox.stub(gSync, "isSendableURI").returns(true);
|
|
sandbox
|
|
.stub(fxAccounts.commands.sendTab, "isDeviceCompatible")
|
|
.returns(true);
|
|
sandbox.stub(fxAccounts.device, "refreshDeviceList").resolves(true);
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
|
|
.callsFake(fxaDeviceId => {
|
|
let target = mockTargets.find(c => c.id == fxaDeviceId);
|
|
return target ? target.clientRecord : null;
|
|
});
|
|
sandbox
|
|
.stub(Weave.Service.clientsEngine, "getClientType")
|
|
.callsFake(
|
|
id =>
|
|
mockTargets.find(c => c.clientRecord && c.clientRecord.id == id)
|
|
.clientRecord.type
|
|
);
|
|
sandbox.stub(gSync, "sendTabToDevice").resolves(true);
|
|
|
|
let cleanUp = () => {
|
|
sandbox.restore();
|
|
};
|
|
registerCleanupFunction(cleanUp);
|
|
|
|
// Add Send to Device to the urlbar.
|
|
let action = PageActions.actionForID("sendToDevice");
|
|
action.pinnedToUrlbar = true;
|
|
|
|
// Click it to open its panel.
|
|
let urlbarButton = document.getElementById(
|
|
BrowserPageActions.urlbarButtonNodeIDForActionID(action.id)
|
|
);
|
|
Assert.notEqual(urlbarButton, null, "The urlbar button should exist");
|
|
Assert.ok(
|
|
!urlbarButton.disabled,
|
|
"The urlbar button should not be disabled"
|
|
);
|
|
EventUtils.synthesizeMouseAtCenter(urlbarButton, {});
|
|
// The panel element for _activatedActionPanelID is created synchronously
|
|
// only after the associated button has been clicked.
|
|
await promisePanelShown(BrowserPageActions._activatedActionPanelID);
|
|
Assert.equal(
|
|
urlbarButton.getAttribute("open"),
|
|
"true",
|
|
"Button has open attribute"
|
|
);
|
|
|
|
// The devices should be shown in the subview.
|
|
let expectedItems = [
|
|
{
|
|
className: "pageAction-sendToDevice-notReady",
|
|
display: "none",
|
|
disabled: true,
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "1",
|
|
label: "bar",
|
|
clientType: "desktop",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "2",
|
|
label: "baz",
|
|
clientType: "phone",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "0",
|
|
label: "foo",
|
|
clientType: "phone",
|
|
},
|
|
},
|
|
{
|
|
attrs: {
|
|
clientId: "3",
|
|
label: "no client record device",
|
|
clientType: "phone",
|
|
},
|
|
},
|
|
null,
|
|
{
|
|
attrs: {
|
|
label: "Send to All Devices",
|
|
},
|
|
},
|
|
];
|
|
checkSendToDeviceItems(expectedItems, true);
|
|
|
|
// Get the first device menu item in the panel.
|
|
let bodyID =
|
|
BrowserPageActions._panelViewNodeIDForActionID("sendToDevice", true) +
|
|
"-body";
|
|
let body = document.getElementById(bodyID);
|
|
let deviceMenuItem = body.querySelector(".sendtab-target");
|
|
Assert.notEqual(deviceMenuItem, null);
|
|
|
|
// For good measure, wait until it's visible.
|
|
let dwu = window.windowUtils;
|
|
await TestUtils.waitForCondition(() => {
|
|
let bounds = dwu.getBoundsWithoutFlushing(deviceMenuItem);
|
|
return bounds.height > 0 && bounds.width > 0;
|
|
}, "Waiting for first device menu item to appear");
|
|
|
|
// Click it, which should cause the panel to close.
|
|
let hiddenPromise = promisePanelHidden(
|
|
BrowserPageActions._activatedActionPanelID
|
|
);
|
|
EventUtils.synthesizeMouseAtCenter(deviceMenuItem, {});
|
|
info("Waiting for Send to Device panel to close after clicking a device");
|
|
await hiddenPromise;
|
|
Assert.ok(
|
|
!urlbarButton.hasAttribute("open"),
|
|
"URL bar button no longer has open attribute"
|
|
);
|
|
|
|
// And then the "Sent!" notification panel should open and close by itself
|
|
// after a moment.
|
|
info("Waiting for the Sent! notification panel to open");
|
|
await promisePanelShown(ConfirmationHint._panel.id);
|
|
Assert.equal(ConfirmationHint._panel.anchorNode.id, urlbarButton.id);
|
|
info("Waiting for the Sent! notification panel to close");
|
|
await promisePanelHidden(ConfirmationHint._panel.id);
|
|
|
|
// Remove Send to Device from the urlbar.
|
|
action.pinnedToUrlbar = false;
|
|
|
|
cleanUp();
|
|
});
|
|
});
|
|
|
|
add_task(async function contextMenu() {
|
|
// Open an actionable page so that the main page action button appears.
|
|
let url = "http://example.com/";
|
|
await BrowserTestUtils.withNewTab(url, async () => {
|
|
// Open the panel and then open the context menu on the bookmark button.
|
|
await promisePageActionPanelOpen();
|
|
let bookmarkButton = document.getElementById("pageAction-panel-bookmark");
|
|
let contextMenuPromise = promisePanelShown("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(bookmarkButton, {
|
|
type: "contextmenu",
|
|
button: 2,
|
|
});
|
|
await contextMenuPromise;
|
|
|
|
// The context menu should show the "remove" item. Click it.
|
|
let menuItems = collectContextMenuItems();
|
|
Assert.equal(menuItems.length, 1, "Context menu has one child");
|
|
Assert.equal(
|
|
menuItems[0].label,
|
|
"Remove from Address Bar",
|
|
"Context menu is in the 'remove' state"
|
|
);
|
|
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
|
|
await contextMenuPromise;
|
|
|
|
// The action should be removed from the urlbar. In this case, the bookmark
|
|
// star, the node in the urlbar should be hidden.
|
|
let starButtonBox = document.getElementById("star-button-box");
|
|
await TestUtils.waitForCondition(() => {
|
|
return starButtonBox.hidden;
|
|
}, "Waiting for star button to become hidden");
|
|
|
|
// Open the context menu again on the bookmark button. (The page action
|
|
// panel remains open.)
|
|
contextMenuPromise = promisePanelShown("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(bookmarkButton, {
|
|
type: "contextmenu",
|
|
button: 2,
|
|
});
|
|
await contextMenuPromise;
|
|
|
|
// The context menu should show the "add" item. Click it.
|
|
menuItems = collectContextMenuItems();
|
|
Assert.equal(menuItems.length, 1, "Context menu has one child");
|
|
Assert.equal(
|
|
menuItems[0].label,
|
|
"Add to Address Bar",
|
|
"Context menu is in the 'add' state"
|
|
);
|
|
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
|
|
await contextMenuPromise;
|
|
|
|
// The action should be added to the urlbar.
|
|
await TestUtils.waitForCondition(() => {
|
|
return !starButtonBox.hidden;
|
|
}, "Waiting for star button to become unhidden");
|
|
|
|
// Open the context menu on the bookmark star in the urlbar.
|
|
contextMenuPromise = promisePanelShown("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(starButtonBox, {
|
|
type: "contextmenu",
|
|
button: 2,
|
|
});
|
|
await contextMenuPromise;
|
|
|
|
// The context menu should show the "remove" item. Click it.
|
|
menuItems = collectContextMenuItems();
|
|
Assert.equal(menuItems.length, 1, "Context menu has one child");
|
|
Assert.equal(
|
|
menuItems[0].label,
|
|
"Remove from Address Bar",
|
|
"Context menu is in the 'remove' state"
|
|
);
|
|
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
|
|
await contextMenuPromise;
|
|
|
|
// The action should be removed from the urlbar.
|
|
await TestUtils.waitForCondition(() => {
|
|
return starButtonBox.hidden;
|
|
}, "Waiting for star button to become hidden");
|
|
|
|
// Finally, add the bookmark star back to the urlbar so that other tests
|
|
// that rely on it are OK.
|
|
await promisePageActionPanelOpen();
|
|
contextMenuPromise = promisePanelShown("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(bookmarkButton, {
|
|
type: "contextmenu",
|
|
button: 2,
|
|
});
|
|
await contextMenuPromise;
|
|
|
|
menuItems = collectContextMenuItems();
|
|
Assert.equal(menuItems.length, 1, "Context menu has one child");
|
|
Assert.equal(
|
|
menuItems[0].label,
|
|
"Add to Address Bar",
|
|
"Context menu is in the 'add' state"
|
|
);
|
|
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
|
|
EventUtils.synthesizeMouseAtCenter(menuItems[0], {});
|
|
await contextMenuPromise;
|
|
await TestUtils.waitForCondition(() => {
|
|
return !starButtonBox.hidden;
|
|
}, "Waiting for star button to become unhidden");
|
|
});
|
|
|
|
// urlbar tests that run after this one can break if the mouse is left over
|
|
// the area where the urlbar popup appears, which seems to happen due to the
|
|
// above synthesized mouse events. Move it over the urlbar.
|
|
EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, { type: "mousemove" });
|
|
gURLBar.focus();
|
|
});
|
|
|
|
function promiseSyncReady() {
|
|
let service = Cc["@mozilla.org/weave/service;1"].getService(Ci.nsISupports)
|
|
.wrappedJSObject;
|
|
return service.whenLoaded().then(() => {
|
|
UIState.isReady();
|
|
return UIState.refresh();
|
|
});
|
|
}
|
|
|
|
function checkSendToDeviceItems(expectedItems, forUrlbar = false) {
|
|
let bodyID =
|
|
BrowserPageActions._panelViewNodeIDForActionID("sendToDevice", forUrlbar) +
|
|
"-body";
|
|
let body = document.getElementById(bodyID);
|
|
Assert.equal(body.children.length, expectedItems.length);
|
|
for (let i = 0; i < expectedItems.length; i++) {
|
|
let expected = expectedItems[i];
|
|
let actual = body.children[i];
|
|
if (!expected) {
|
|
Assert.equal(actual.localName, "toolbarseparator");
|
|
continue;
|
|
}
|
|
if ("id" in expected) {
|
|
Assert.equal(actual.id, expected.id);
|
|
}
|
|
if ("className" in expected) {
|
|
let expectedNames = expected.className.split(/\s+/);
|
|
for (let name of expectedNames) {
|
|
Assert.ok(
|
|
actual.classList.contains(name),
|
|
`classList contains: ${name}`
|
|
);
|
|
}
|
|
}
|
|
let display = "display" in expected ? expected.display : "-moz-box";
|
|
Assert.equal(getComputedStyle(actual).display, display);
|
|
let disabled = "disabled" in expected ? expected.disabled : false;
|
|
Assert.equal(actual.disabled, disabled);
|
|
if ("attrs" in expected) {
|
|
for (let name in expected.attrs) {
|
|
Assert.ok(actual.hasAttribute(name));
|
|
let attrVal = actual.getAttribute(name);
|
|
if (name == "label") {
|
|
attrVal = attrVal.normalize("NFKC"); // There's a bug with …
|
|
}
|
|
Assert.equal(attrVal, expected.attrs[name]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function collectContextMenuItems() {
|
|
let contextMenu = document.getElementById("pageActionContextMenu");
|
|
return Array.prototype.filter.call(contextMenu.children, node => {
|
|
return window.getComputedStyle(node).visibility == "visible";
|
|
});
|
|
}
|