From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../unit/content-src/components/LinkMenu.test.jsx | 582 +++++++++++++++++++++ 1 file changed, 582 insertions(+) create mode 100644 browser/components/newtab/test/unit/content-src/components/LinkMenu.test.jsx (limited to 'browser/components/newtab/test/unit/content-src/components/LinkMenu.test.jsx') diff --git a/browser/components/newtab/test/unit/content-src/components/LinkMenu.test.jsx b/browser/components/newtab/test/unit/content-src/components/LinkMenu.test.jsx new file mode 100644 index 0000000000..8aa74a3a46 --- /dev/null +++ b/browser/components/newtab/test/unit/content-src/components/LinkMenu.test.jsx @@ -0,0 +1,582 @@ +import { ContextMenu } from "content-src/components/ContextMenu/ContextMenu"; +import { _LinkMenu as LinkMenu } from "content-src/components/LinkMenu/LinkMenu"; +import React from "react"; +import { shallow } from "enzyme"; + +describe("", () => { + let wrapper; + beforeEach(() => { + wrapper = shallow( + {}} + /> + ); + }); + it("should render a ContextMenu element", () => { + assert.ok(wrapper.find(ContextMenu).exists()); + }); + it("should pass onUpdate, and options to ContextMenu", () => { + assert.ok(wrapper.find(ContextMenu).exists()); + const contextMenuProps = wrapper.find(ContextMenu).props(); + ["onUpdate", "options"].forEach(prop => + assert.property(contextMenuProps, prop) + ); + }); + it("should give ContextMenu the correct tabbable options length for a11y", () => { + const { options } = wrapper.find(ContextMenu).props(); + const [firstItem] = options; + const lastItem = options[options.length - 1]; + + // first item should have {first: true} + assert.isTrue(firstItem.first); + assert.ok(!firstItem.last); + + // last item should have {last: true} + assert.isTrue(lastItem.last); + assert.ok(!lastItem.first); + + // middle items should have neither + for (let i = 1; i < options.length - 1; i++) { + assert.ok(!options[i].first && !options[i].last); + } + }); + it("should show the correct options for default sites", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + let i = 0; + assert.propertyVal(options[i++], "id", "newtab-menu-pin"); + assert.propertyVal(options[i++], "id", "newtab-menu-edit-topsites"); + assert.propertyVal(options[i++], "type", "separator"); + assert.propertyVal(options[i++], "id", "newtab-menu-open-new-window"); + assert.propertyVal( + options[i++], + "id", + "newtab-menu-open-new-private-window" + ); + assert.propertyVal(options[i++], "type", "separator"); + assert.propertyVal(options[i++], "id", "newtab-menu-dismiss"); + assert.propertyVal(options, "length", i); + // Double check that delete options are not included for default top sites + options + .filter(o => o.type !== "separator") + .forEach(o => { + assert.notInclude(["newtab-menu-delete-history"], o.id); + }); + }); + it("should show Unpin option for a pinned site if CheckPinTopSite in options list", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined(options.find(o => o.id && o.id === "newtab-menu-unpin")); + }); + it("should show Pin option for an unpinned site if CheckPinTopSite in options list", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined(options.find(o => o.id && o.id === "newtab-menu-pin")); + }); + it("should show Unbookmark option for a bookmarked site if CheckBookmark in options list", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-remove-bookmark") + ); + }); + it("should show Bookmark option for an unbookmarked site if CheckBookmark in options list", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-bookmark") + ); + }); + it("should show Save to Pocket option for an unsaved Pocket item if CheckSavedToPocket in options list", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-save-to-pocket") + ); + }); + it("should show Delete from Pocket option for a saved Pocket item if CheckSavedToPocket in options list", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-delete-pocket") + ); + }); + it("should show Archive from Pocket option for a saved Pocket item if CheckBookmarkOrArchive", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-archive-pocket") + ); + }); + it("should show Bookmark option for an unbookmarked site if CheckBookmarkOrArchive in options list and no pocket_id", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-bookmark") + ); + }); + it("should show Unbookmark option for a bookmarked site if CheckBookmarkOrArchive in options list and no pocket_id", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-remove-bookmark") + ); + }); + it("should show Archive from Pocket option for a saved Pocket item if CheckArchiveFromPocket", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-archive-pocket") + ); + }); + it("should show empty from no Pocket option for no saved Pocket item if CheckArchiveFromPocket", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isUndefined( + options.find(o => o.id && o.id === "newtab-menu-archive-pocket") + ); + }); + it("should show Delete from Pocket option for a saved Pocket item if CheckDeleteFromPocket", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-delete-pocket") + ); + }); + it("should show empty from Pocket option for no saved Pocket item if CheckDeleteFromPocket", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isUndefined( + options.find(o => o.id && o.id === "newtab-menu-archive-pocket") + ); + }); + it("should show Open File option for a downloaded item", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-open-file") + ); + }); + it("should show Show File option for a downloaded item on a default platform", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-show-file") + ); + }); + it("should show Copy Downlad Link option for a downloaded item when CopyDownloadLink", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-copy-download-link") + ); + }); + it("should show Go To Download Page option for a downloaded item when GoToDownloadPage", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-go-to-download-page") + ); + assert.isFalse(options[0].disabled); + }); + it("should show Go To Download Page option as disabled for a downloaded item when GoToDownloadPage if no referrer exists", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-go-to-download-page") + ); + assert.isTrue(options[0].disabled); + }); + it("should show Remove Download Link option for a downloaded item when RemoveDownload", () => { + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + assert.isDefined( + options.find(o => o.id && o.id === "newtab-menu-remove-download") + ); + }); + it("should show Edit option", () => { + const props = { url: "foo", label: "label" }; + const index = 5; + wrapper = shallow( + {}} + /> + ); + const { options } = wrapper.find(ContextMenu).props(); + const option = options.find( + o => o.id && o.id === "newtab-menu-edit-topsites" + ); + assert.isDefined(option); + assert.equal(option.action.data.index, index); + }); + describe(".onClick", () => { + const FAKE_EVENT = {}; + const FAKE_INDEX = 3; + const FAKE_SOURCE = "TOP_SITES"; + const FAKE_SITE = { + bookmarkGuid: 1234, + hostname: "foo", + path: "foo", + pocket_id: "1234", + referrer: "https://foo.com/ref", + title: "bar", + type: "bookmark", + typedBonus: true, + url: "https://foo.com", + sponsored_tile_id: 12345, + }; + const dispatch = sinon.stub(); + const propOptions = [ + "ShowFile", + "CopyDownloadLink", + "GoToDownloadPage", + "RemoveDownload", + "Separator", + "ShowPrivacyInfo", + "RemoveBookmark", + "AddBookmark", + "OpenInNewWindow", + "OpenInPrivateWindow", + "BlockUrl", + "DeleteUrl", + "PinTopSite", + "UnpinTopSite", + "SaveToPocket", + "DeleteFromPocket", + "ArchiveFromPocket", + "WebExtDismiss", + ]; + const expectedActionData = { + "newtab-menu-remove-bookmark": FAKE_SITE.bookmarkGuid, + "newtab-menu-bookmark": { + url: FAKE_SITE.url, + title: FAKE_SITE.title, + type: FAKE_SITE.type, + }, + "newtab-menu-open-new-window": { + url: FAKE_SITE.url, + referrer: FAKE_SITE.referrer, + typedBonus: FAKE_SITE.typedBonus, + sponsored_tile_id: FAKE_SITE.sponsored_tile_id, + }, + "newtab-menu-open-new-private-window": { + url: FAKE_SITE.url, + referrer: FAKE_SITE.referrer, + }, + "newtab-menu-dismiss": [ + { + url: FAKE_SITE.url, + pocket_id: FAKE_SITE.pocket_id, + isSponsoredTopSite: undefined, + }, + ], + menu_action_webext_dismiss: { + source: "TOP_SITES", + url: FAKE_SITE.url, + action_position: 3, + }, + "newtab-menu-delete-history": { + url: FAKE_SITE.url, + pocket_id: FAKE_SITE.pocket_id, + forceBlock: FAKE_SITE.bookmarkGuid, + }, + "newtab-menu-pin": { site: FAKE_SITE, index: FAKE_INDEX }, + "newtab-menu-unpin": { site: { url: FAKE_SITE.url } }, + "newtab-menu-save-to-pocket": { + site: { url: FAKE_SITE.url, title: FAKE_SITE.title }, + }, + "newtab-menu-delete-pocket": { pocket_id: "1234" }, + "newtab-menu-archive-pocket": { pocket_id: "1234" }, + "newtab-menu-show-file": { url: FAKE_SITE.url }, + "newtab-menu-copy-download-link": { url: FAKE_SITE.url }, + "newtab-menu-go-to-download-page": { url: FAKE_SITE.referrer }, + "newtab-menu-remove-download": { url: FAKE_SITE.url }, + }; + const { options } = shallow( + + ) + .find(ContextMenu) + .props(); + afterEach(() => dispatch.reset()); + options + .filter(o => o.type !== "separator") + .forEach(option => { + it(`should fire a ${option.action.type} action for ${option.id} with the expected data`, () => { + option.onClick(FAKE_EVENT); + + if (option.impression && option.userEvent) { + assert.calledThrice(dispatch); + } else if (option.impression || option.userEvent) { + assert.calledTwice(dispatch); + } else { + assert.calledOnce(dispatch); + } + + // option.action is dispatched + assert.ok(dispatch.firstCall.calledWith(option.action)); + + // option.action has correct data + // (delete is a special case as it dispatches a nested DIALOG_OPEN-type action) + // in the case of this FAKE_SITE, we send a bookmarkGuid therefore we also want + // to block this if we delete it + if (option.id === "newtab-menu-delete-history") { + assert.deepEqual( + option.action.data.onConfirm[0].data, + expectedActionData[option.id] + ); + // Test UserEvent send correct meta about item deleted + assert.propertyVal( + option.action.data.onConfirm[1].data, + "action_position", + FAKE_INDEX + ); + assert.propertyVal( + option.action.data.onConfirm[1].data, + "source", + FAKE_SOURCE + ); + } else { + assert.deepEqual(option.action.data, expectedActionData[option.id]); + } + }); + it(`should fire a UserEvent action for ${option.id} if configured`, () => { + if (option.userEvent) { + option.onClick(FAKE_EVENT); + const [action] = dispatch.secondCall.args; + assert.isUserEventAction(action); + assert.propertyVal(action.data, "source", FAKE_SOURCE); + assert.propertyVal(action.data, "action_position", FAKE_INDEX); + assert.propertyVal(action.data.value, "card_type", FAKE_SITE.type); + } + }); + it(`should send impression stats for ${option.id}`, () => { + if (option.impression) { + option.onClick(FAKE_EVENT); + const [action] = dispatch.thirdCall.args; + assert.deepEqual(action, option.impression); + } + }); + }); + it(`should not send impression stats if not configured`, () => { + const fakeOptions = shallow( + + ) + .find(ContextMenu) + .props().options; + + fakeOptions + .filter(o => o.type !== "separator") + .forEach(option => { + if (option.impression) { + option.onClick(FAKE_EVENT); + assert.calledTwice(dispatch); + assert.notEqual(dispatch.firstCall.args[0], option.impression); + assert.notEqual(dispatch.secondCall.args[0], option.impression); + dispatch.reset(); + } + }); + }); + it(`should pin a SPOC with all of the site details sent`, () => { + const pinSpocTopSite = "PinTopSite"; + const { options: spocOptions } = shallow( + + ) + .find(ContextMenu) + .props(); + + const [pinSpocOption] = spocOptions; + pinSpocOption.onClick(FAKE_EVENT); + + if (pinSpocOption.impression && pinSpocOption.userEvent) { + assert.calledThrice(dispatch); + } else if (pinSpocOption.impression || pinSpocOption.userEvent) { + assert.calledTwice(dispatch); + } else { + assert.calledOnce(dispatch); + } + + // option.action is dispatched + assert.ok(dispatch.firstCall.calledWith(pinSpocOption.action)); + + assert.deepEqual(pinSpocOption.action.data, { + site: FAKE_SITE, + index: FAKE_INDEX, + }); + }); + }); +}); -- cgit v1.2.3