diff options
Diffstat (limited to 'addon-sdk/source/test/test-context-menu@2.js')
-rw-r--r-- | addon-sdk/source/test/test-context-menu@2.js | 1350 |
1 files changed, 1350 insertions, 0 deletions
diff --git a/addon-sdk/source/test/test-context-menu@2.js b/addon-sdk/source/test/test-context-menu@2.js new file mode 100644 index 000000000..78c496220 --- /dev/null +++ b/addon-sdk/source/test/test-context-menu@2.js @@ -0,0 +1,1350 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const { Cc, Ci } = require("chrome"); +const {openWindow, closeWindow, openTab, closeTab, + openContextMenu, closeContextMenu, select, + readNode, captureContextMenu, withTab, withItems } = require("./context-menu/util"); +const {when} = require("sdk/dom/events"); +const {Item, Menu, Separator, Contexts, Readers } = require("sdk/context-menu@2"); +const prefs = require("sdk/preferences/service"); +const { before, after } = require('sdk/test/utils'); + +const testPageURI = require.resolve("./test-context-menu").replace(".js", ".html"); + +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +const data = input => + `data:text/html;charset=utf-8,${encodeURIComponent(input)}` + +const menugroup = (...children) => Object.assign({ + tagName: "menugroup", + namespaceURI: XUL_NS, + style: "-moz-box-orient: vertical;", + className: "sdk-context-menu-extension" +}, children.length ? {children} : {}); + +const menuseparator = () => ({ + tagName: "menuseparator", + namespaceURI: XUL_NS, + className: "sdk-context-menu-separator" +}) + +const menuitem = properties => Object.assign({ + tagName: "menuitem", + namespaceURI: XUL_NS, + className: "sdk-context-menu-item menuitem-iconic" +}, properties); + +const menu = (properties, ...children) => Object.assign({ + tagName: "menu", + namespaceURI: XUL_NS, + className: "sdk-context-menu menu-iconic" +}, properties, { + children: [Object.assign({tagName: "menupopup", namespaceURI: XUL_NS}, + children.length ? {children} : {})] +}); + +// Destroying items that were previously created should cause them to be absent +// from the menu. +exports["test create / destroy menu item"] = withTab(function*(assert) { + const item = new Item({ + label: "test-1" + }); + + const before = yield captureContextMenu("h1"); + + assert.deepEqual(before, + menugroup(menuseparator(), + menuitem({label: "test-1"})), + "context menu contains separator & added item"); + + item.destroy(); + + const after = yield captureContextMenu("h1"); + assert.deepEqual(after, menugroup(), + "all items were removed children are present"); +}, data`<h1>hello</h1>`); + + +/* Bug 1115419 - Disable occasionally failing test until we + figure out why it fails. +// Items created should be present on all browser windows. +exports["test menu item in new window"] = function*(assert) { + const isMenuPopulated = function*(tab) { + const state = yield captureContextMenu("h1", tab); + assert.deepEqual(state, + menugroup(menuseparator(), + menuitem({label: "multi-window"})), + "created menu item is present") + }; + + const isMenuEmpty = function*(tab) { + const state = yield captureContextMenu("h1", tab); + assert.deepEqual(state, menugroup(), "no sdk items present"); + }; + + const item = new Item({ label: "multi-window" }); + + const tab1 = yield openTab(`data:text/html,<h1>hello</h1>`); + yield* isMenuPopulated(tab1); + + const window2 = yield openWindow(); + assert.pass("window is ready"); + + const tab2 = yield openTab(`data:text/html,<h1>hello window-2</h1>`, window2); + assert.pass("tab is ready"); + + yield* isMenuPopulated(tab2); + + item.destroy(); + + yield* isMenuEmpty(tab2); + yield closeWindow(window2); + + yield* isMenuEmpty(tab1); + + yield closeTab(tab1); +}; +*/ + + +// Multilpe items can be created and destroyed at different points +// in time & they should not affect each other. +exports["test multiple items"] = withTab(function*(assert) { + const item1 = new Item({ label: "one" }); + + const step1 = yield captureContextMenu("h1"); + assert.deepEqual(step1, + menugroup(menuseparator(), + menuitem({label: "one"})), + "item1 is present"); + + const item2 = new Item({ label: "two" }); + const step2 = yield captureContextMenu("h1"); + + assert.deepEqual(step2, + menugroup(menuseparator(), + menuitem({label: "one"}), + menuitem({label: "two"})), + "both items where present"); + + item1.destroy(); + + const step3 = yield captureContextMenu("h1"); + assert.deepEqual(step3, + menugroup(menuseparator(), + menuitem({label: "two"})), + "one items left"); + + item2.destroy(); + + const step4 = yield captureContextMenu("h1"); + assert.deepEqual(step4, menugroup(), "no items left"); +}, data`<h1>Multiple Items</h1>`); + +// Destroying an item twice should not cause an error. +exports["test destroy twice"] = withTab(function*(assert) { + const item = new Item({ label: "destroy" }); + const withItem = yield captureContextMenu("h2"); + assert.deepEqual(withItem, + menugroup(menuseparator(), + menuitem({label:"destroy"})), + "Item is added"); + + item.destroy(); + + const withoutItem = yield captureContextMenu("h2"); + assert.deepEqual(withoutItem, menugroup(), "Item was removed"); + + item.destroy(); + assert.pass("Destroying an item twice should not cause an error."); +}, "data:text/html,<h2>item destroy</h2>"); + +// CSS selector contexts should cause their items to be absent from the menu +// when the menu is not invoked on nodes that match selectors. +exports["test selector context"] = withTab(function*(assert) { + const item = new Item({ + context: [new Contexts.Selector("body b")], + label: "bold" + }); + + const match = yield captureContextMenu("b"); + assert.deepEqual(match, + menugroup(menuseparator(), + menuitem({label: "bold"})), + "item mathched context"); + + const noMatch = yield captureContextMenu("i"); + assert.deepEqual(noMatch, menugroup(), "item did not match context"); + + item.destroy(); + + const cleared = yield captureContextMenu("b"); + assert.deepEqual(cleared, menugroup(), "item was removed"); +}, data`<body><i>one</i><b>two</b></body>`); + +// CSS selector contexts should cause their items to be absent in the menu +// when the menu is invoked even on nodes that have ancestors that match the +// selectors. +exports["test parent selector don't match children"] = withTab(function*(assert) { + const item = new Item({ + label: "parent match", + context: [new Contexts.Selector("a[href]")] + }); + + const match = yield captureContextMenu("a"); + assert.deepEqual(match, + menugroup(menuseparator(), + menuitem({label: "parent match"})), + "item mathched context"); + + const noMatch = yield captureContextMenu("strong"); + assert.deepEqual(noMatch, menugroup(), "item did not mathch context"); + + item.destroy(); + + const destroyed = yield captureContextMenu("a"); + assert.deepEqual(destroyed, menugroup(), "no items left"); +}, data`<a href='/foo'>This text must be long & <strong>bold!</strong></a>`); + +// Page contexts should cause their items to be present in the menu when the +// menu is not invoked on an active element. +exports["test page context match"] = withTab(function*(assert) { + const isPageMatch = (tree, description="page context matched") => + assert.deepEqual(tree, + menugroup(menuseparator(), + menuitem({label: "page match"}), + menuitem({label: "any match"})), + description); + + const isntPageMatch = (tree, description="page context did not match") => + assert.deepEqual(tree, + menugroup(menuseparator(), + menuitem({label: "any match"})), + description); + + yield* withItems({ + pageMatch: new Item({ + label: "page match", + context: [new Contexts.Page()], + }), + anyMatch: new Item({ + label: "any match" + }) + }, function*({pageMatch, anyMatch}) { + for (let tagName of [null, "p", "h3"]) { + isPageMatch((yield captureContextMenu(tagName)), + `Page context matches ${tagName} passive element`); + } + + for (let tagName of ["button", "canvas", "img", "input", "textarea", + "select", "menu", "embed" ,"object", "video", "audio", + "applet"]) + { + isntPageMatch((yield captureContextMenu(tagName)), + `Page context does not match <${tagName}/> active element`); + } + + for (let selector of ["span"]) + { + isntPageMatch((yield captureContextMenu(selector)), + `Page context does not match decedents of active element`); + } + }); +}, +data`<head> + <style> + p, object, embed { display: inline-block; } + </style> +</head> +<body> + <div><p>paragraph</p></div> + <div><a href=./link><span>link</span></a></div> + <h3>hi</h3> + <div><button>button</button></div> + <div><canvas height=10 /></div> + <div><img height=10 width=10 /></div> + <div><input value=input /></div> + <div><textarea>text</textarea></div> + <div><select><option>one</option><option>two</option></select></div> + <div><menu><button>item</button></menu></div> + <div><object width=10 height=10><param name=foo value=bar /></object></div> + <div><embed width=10 height=10/></div> + <div><video width=10 height=10 controls /></div> + <div><audio width=10 height=10 controls /></div> + <div><applet width=10 height=10 /></div> +</body>`); + +// Page context does not match if if there is a selection. +exports["test page context doesn't match on selection"] = withTab(function*(assert) { + const isPageMatch = (tree, description="page context matched") => + assert.deepEqual(tree, + menugroup(menuseparator(), + menuitem({label: "page match"}), + menuitem({label: "any match"})), + description); + + const isntPageMatch = (tree, description="page context did not match") => + assert.deepEqual(tree, + menugroup(menuseparator(), + menuitem({label: "any match"})), + description); + + yield* withItems({ + pageMatch: new Item({ + label: "page match", + context: [new Contexts.Page()], + }), + anyMatch: new Item({ + label: "any match" + }) + }, function*({pageMatch, anyMatch}) { + yield select("b"); + isntPageMatch((yield captureContextMenu("i")), + "page context does not match if there is a selection"); + + yield select(null); + isPageMatch((yield captureContextMenu("i")), + "page context match if there is no selection"); + }); +}, data`<body><i>one</i><b>two</b></body>`); + +exports["test selection context"] = withTab(function*(assert) { + yield* withItems({ + item: new Item({ + label: "selection", + context: [new Contexts.Selection()] + }) + }, function*({item}) { + assert.deepEqual((yield captureContextMenu()), + menugroup(), + "item does not match if there is no selection"); + + yield select("b"); + + assert.deepEqual((yield captureContextMenu()), + menugroup(menuseparator(), + menuitem({label: "selection"})), + "item matches if there is a selection"); + }); +}, data`<i>one</i><b>two</b>`); + +exports["test selection context in textarea"] = withTab(function*(assert) { + yield* withItems({ + item: new Item({ + label: "selection", + context: [new Contexts.Selection()] + }) + }, function*({item}) { + assert.deepEqual((yield captureContextMenu()), + menugroup(), + "does not match if there's no selection"); + + yield select({target:"textarea", start:0, end:5}); + + assert.deepEqual((yield captureContextMenu("b")), + menugroup(), + "does not match if target isn't input with selection"); + + assert.deepEqual((yield captureContextMenu("textarea")), + menugroup(menuseparator(), + menuitem({label: "selection"})), + "matches if target is input with selected text"); + + yield select({target: "textarea", start: 0, end: 0}); + + assert.deepEqual((yield captureContextMenu("textarea")), + menugroup(), + "does not match when selection is cleared"); + }); +}, data`<textarea>Hello World</textarea><b>!!</b>`); + +exports["test url contexts"] = withTab(function*(assert) { + yield* withItems({ + a: new Item({ + label: "a", + context: [new Contexts.URL(testPageURI)] + }), + b: new Item({ + label: "b", + context: [new Contexts.URL("*.bogus.com")] + }), + c: new Item({ + label: "c", + context: [new Contexts.URL("*.bogus.com"), + new Contexts.URL(testPageURI)] + }), + d: new Item({ + label: "d", + context: [new Contexts.URL(/.*\.html/)] + }), + e: new Item({ + label: "e", + context: [new Contexts.URL("http://*"), + new Contexts.URL(testPageURI)] + }), + f: new Item({ + label: "f", + context: [new Contexts.URL("http://*").required, + new Contexts.URL(testPageURI)] + }), + }, function*(_) { + assert.deepEqual((yield captureContextMenu()), + menugroup(menuseparator(), + menuitem({label: "a"}), + menuitem({label: "c"}), + menuitem({label: "d"}), + menuitem({label: "e"})), + "shows only matching items"); + }); +}, testPageURI); + +exports["test iframe context"] = withTab(function*(assert) { + yield* withItems({ + page: new Item({ + label: "page", + context: [new Contexts.Page()] + }), + iframe: new Item({ + label: "iframe", + context: [new Contexts.Frame()] + }), + h2: new Item({ + label: "element", + context: [new Contexts.Selector("*")] + }) + }, function(_) { + assert.deepEqual((yield captureContextMenu("iframe")), + menugroup(menuseparator(), + menuitem({label: "page"}), + menuitem({label: "iframe"}), + menuitem({label: "element"})), + "matching items are present"); + + assert.deepEqual((yield captureContextMenu("h1")), + menugroup(menuseparator(), + menuitem({label: "page"}), + menuitem({label: "element"})), + "only matching items are present"); + + }); + +}, +data`<h1>hello</h1> +<iframe src='data:text/html,<body>Bye</body>' />`); + +exports["test link context"] = withTab(function*(assert) { + yield* withItems({ + item: new Item({ + label: "link", + context: [new Contexts.Link()] + }) + }, function*(_) { + assert.deepEqual((yield captureContextMenu("h1")), + menugroup(menuseparator(), + menuitem({label: "link"})), + "matches anchor child"); + + assert.deepEqual((yield captureContextMenu("i")), + menugroup(menuseparator(), + menuitem({label: "link"})), + "matches anchor decedent"); + assert.deepEqual((yield captureContextMenu("h2")), + menugroup(), + "does not match if not under anchor"); + }); +}, data`<a href="/link"><h1>Hello <i>World</i></h1></a><h2>miss</h2>`); + + +exports["test editable context"] = withTab(function*(assert) { + const isntEditable = function*(selector) { + assert.deepEqual((yield captureContextMenu(selector)), + menugroup(), + `${selector} isn't editable`); + }; + + const isEditable = function*(selector) { + assert.deepEqual((yield captureContextMenu(selector)), + menugroup(menuseparator(), + menuitem({label: "editable"})), + `${selector} is editable`); + }; + + yield* withItems({ + item: new Item({ + label: "editable", + context: [new Contexts.Editable()] + }) + }, function*(_) { + yield* isntEditable("h1"); + yield* isEditable("input[id=text]"); + yield* isntEditable("input[disabled=true]"); + yield* isntEditable("input[readonly=true]"); + yield* isntEditable("input[type=submit]"); + yield* isntEditable("input[type=radio]"); + yield* isntEditable("input[type=checkbox]"); + yield* isEditable("input[type=foo]"); + yield* isEditable("textarea"); + yield* isEditable("[contenteditable=true]"); + }); +}, data`<body> +<h1>examles</h1> +<pre contenteditable="true">This content is editable.</pre> +<input type="text" readonly="true" value="readonly value"> +<input type="text" disabled="true" value="disabled value"> +<input type="text" id=text value="test value"> +<input type="submit" /> +<input type="radio" /> +<input type="foo" /> +<input type="checkbox" /> +<textarea>A text field, +with some text.</textarea> +</body>`); + +exports["test image context"] = withTab(function*(assert) { + yield withItems({ + item: new Item({ + label: "image", + context: [new Contexts.Image()] + }) + }, function*(_) { + assert.deepEqual((yield captureContextMenu("img")), + menugroup(menuseparator(), menuitem({label: "image"})), + `<img/> matches image context`); + + assert.deepEqual((yield captureContextMenu("p image")), + menugroup(), + `<image/> does not image context`); + + assert.deepEqual((yield captureContextMenu("svg image")), + menugroup(menuseparator(), menuitem({label: "image"})), + `<svg:image/> matches image context`); + }); +}, data`<body> +<p><image style="width: 50px; height: 50px" /></p> +<img src='' /> +<div> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink= "http://www.w3.org/1999/xlink"> + <image x="0" y="0" height="50px" width="50px" xlink:href=""/> +</svg> +<div> +</body>`); + + +exports["test audiot & video contexts"] = withTab(function*(assert) { + yield withItems({ + audio: new Item({ + label: "audio", + context: [new Contexts.Audio()] + }), + video: new Item({ + label: "video", + context: [new Contexts.Video()] + }), + media: new Item({ + label: "media", + context: [new Contexts.Audio(), + new Contexts.Video()] + }) + }, function*(_) { + assert.deepEqual((yield captureContextMenu("img")), + menugroup(), + `<img/> does not match video or audio context`); + + assert.deepEqual((yield captureContextMenu("audio")), + menugroup(menuseparator(), + menuitem({label: "audio"}), + menuitem({label: "media"})), + `<audio/> matches audio context`); + + assert.deepEqual((yield captureContextMenu("video")), + menugroup(menuseparator(), + menuitem({label: "video"}), + menuitem({label: "media"})), + `<video/> matches video context`); + }) +}, data`<body> +<div><video width=10 height=10 controls /></div> +<div><audio width=10 height=10 controls /></div> +<div><image style="width: 50px; height: 50px" /></div> +</body>`); + +const predicateTestURL = data`<html> + <head> + <style> + p, object, embed { display: inline-block; } + </style> + </head> + <body> + <strong><p>paragraph</p></strong> + <p><a href=./link><span>link</span></a></p> + <p><h3>hi</h3></p> + <p><button>button</button></p> + <p><canvas height=50 width=50 /></p> + <p><img height=50 width=50 src="./no.png" /></p> + <p><code contenteditable="true">This content is editable.</code></p> + <p><input type="text" readonly="true" value="readonly value"></p> + <p><input type="text" disabled="true" value="disabled value"></p> + <p><input type="text" id=text value="test value" /></p> + <p><input type="submit" /></p> + <p><input type="radio" /></p> + <p><input type="foo" /></p> + <p><input type="checkbox" /></p> + <p><textarea>A text field, + with some text.</textarea></p> + <p><iframe src='data:text/html,<body style="height:100%">Bye</body>'></iframe></p> + <p><select><option>one</option><option>two</option></select></p> + <p><menu><button>item</button></menu></p> + <p><object width=10 height=10><param name=foo value=bar /></object></p> + <p><embed width=10 height=10/></p> + <p><video width=50 height=50 controls /></p> + <p><audio width=10 height=10 controls /></p> + <p><applet width=30 height=30 /></p> + </body> +</html>`; +exports["test predicate context"] = withTab(function*(assert) { + const test = function*(selector, expect) { + var isMatch = false; + test.return = (target) => { + return isMatch = expect(target); + } + assert.deepEqual((yield captureContextMenu(selector)), + isMatch ? menugroup(menuseparator(), + menuitem({label:"predicate"})) : + menugroup(), + isMatch ? `predicate item matches ${selector}` : + `predicate item doesn't match ${selector}`); + }; + test.predicate = target => test.return(target); + + yield* withItems({ + item: new Item({ + label: "predicate", + read: { + mediaType: new Readers.MediaType(), + link: new Readers.LinkURL(), + isPage: new Readers.isPage(), + isFrame: new Readers.isFrame(), + isEditable: new Readers.isEditable(), + tagName: new Readers.Query("tagName"), + appCodeName: new Readers.Query("ownerDocument.defaultView.navigator.appCodeName"), + width: new Readers.Attribute("width"), + src: new Readers.SrcURL(), + url: new Readers.PageURL(), + selection: new Readers.Selection() + }, + context: [Contexts.Predicate(test.predicate)] + }) + }, function*(items) { + yield* test("strong p", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: true, + isFrame: false, + isEditable: false, + tagName: "P", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "pagraph read test"); + return true; + }); + + yield* test("a span", target => { + assert.deepEqual(target, { + mediaType: null, + link: "./link", + isPage: false, + isFrame: false, + isEditable: false, + tagName: "SPAN", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "video tag test"); + return false; + }); + + yield* test("h3", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: true, + isFrame: false, + isEditable: false, + tagName: "H3", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "video tag test"); + return false; + }); + + yield select("h3"); + + yield* test("a span", target => { + assert.deepEqual(target, { + mediaType: null, + link: "./link", + isPage: false, + isFrame: false, + isEditable: false, + tagName: "SPAN", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: "hi", + }, "test selection with link"); + return true; + }); + + yield select(null); + + + yield* test("button", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "BUTTON", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test button"); + return true; + }); + + yield* test("canvas", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "CANVAS", + appCodeName: "Mozilla", + width: "50", + src: null, + url: predicateTestURL, + selection: null, + }, "test button"); + return true; + }); + + yield* test("img", target => { + assert.deepEqual(target, { + mediaType: "image", + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "IMG", + appCodeName: "Mozilla", + width: "50", + src: "./no.png", + url: predicateTestURL, + selection: null, + }, "test image"); + return true; + }); + + yield* test("code", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: true, + tagName: "CODE", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test content editable"); + return false; + }); + + yield* test("input[readonly=true]", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test readonly input"); + return false; + }); + + yield* test("input[disabled=true]", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test disabled input"); + return false; + }); + + yield select({target: "input#text", start: 0, end: 5 }); + + yield* test("input#text", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: true, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: "test ", + }, "test editable input"); + return false; + }); + + yield select({target: "input#text", start:0, end: 0}); + + yield* test("input[type=submit]", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test submit input"); + return false; + }); + + yield* test("input[type=radio]", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test radio input"); + return false; + }); + + yield* test("input[type=checkbox]", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test checkbox input"); + return false; + }); + + yield* test("input[type=foo]", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: true, + tagName: "INPUT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test unrecognized input"); + return false; + }); + + yield* test("textarea", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: true, + tagName: "TEXTAREA", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test textarea"); + return false; + }); + + + yield* test("iframe", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: true, + isFrame: true, + isEditable: false, + tagName: "BODY", + appCodeName: "Mozilla", + width: null, + src: null, + url: `data:text/html,<body%20style="height:100%">Bye</body>`, + selection: null, + }, "test iframe"); + return true; + }); + + yield* test("select", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "SELECT", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test select"); + return true; + }); + + yield* test("menu", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "MENU", + appCodeName: "Mozilla", + width: null, + src: null, + url: predicateTestURL, + selection: null, + }, "test menu"); + return false; + }); + + yield* test("video", target => { + assert.deepEqual(target, { + mediaType: "video", + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "VIDEO", + appCodeName: "Mozilla", + width: "50", + src: null, + url: predicateTestURL, + selection: null, + }, "test video"); + return true; + }); + + yield* test("audio", target => { + assert.deepEqual(target, { + mediaType: "audio", + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "AUDIO", + appCodeName: "Mozilla", + width: "10", + src: null, + url: predicateTestURL, + selection: null, + }, "test audio"); + return true; + }); + + yield* test("object", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "OBJECT", + appCodeName: "Mozilla", + width: "10", + src: null, + url: predicateTestURL, + selection: null, + }, "test object"); + return true; + }); + + yield* test("embed", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "EMBED", + appCodeName: "Mozilla", + width: "10", + src: null, + url: predicateTestURL, + selection: null, + }, "test embed"); + return true; + }); + + yield* test("applet", target => { + assert.deepEqual(target, { + mediaType: null, + link: null, + isPage: false, + isFrame: false, + isEditable: false, + tagName: "APPLET", + appCodeName: "Mozilla", + width: "30", + src: null, + url: predicateTestURL, + selection: null, + }, "test applet"); + return false; + }); + + }); +}, predicateTestURL); + +exports["test extractor reader"] = withTab(function*(assert) { + const test = function*(selector, expect) { + var isMatch = false; + test.return = (target) => { + return isMatch = expect(target); + } + assert.deepEqual((yield captureContextMenu(selector)), + isMatch ? menugroup(menuseparator(), + menuitem({label:"extractor"})) : + menugroup(), + isMatch ? `predicate item matches ${selector}` : + `predicate item doesn't match ${selector}`); + }; + test.predicate = target => test.return(target); + + + yield* withItems({ + item: new Item({ + label: "extractor", + context: [Contexts.Predicate(test.predicate)], + read: { + tagName: Readers.Query("tagName"), + selector: Readers.Extractor(target => { + let node = target; + let path = []; + while (node) { + if (node.id) { + path.unshift(`#${node.id}`); + node = null; + } + else { + path.unshift(node.localName); + node = node.parentElement; + } + } + return path.join(" > "); + }) + } + }) + }, function*(_) { + yield* test("footer", target => { + assert.deepEqual(target, { + tagName: "FOOTER", + selector: "html > body > nav > footer" + }, "test footer"); + return false; + }); + + + }); +}, data`<html> + <body> + <nav> + <header>begin</header> + <footer>end</footer> + </nav> + <article data-index=1> + <header>First title</header> + <div> + <p>First paragraph</p> + <p>Second paragraph</p> + </div> + </article> + <article data-index=2> + <header>Second title</header> + <div> + <p>First <strong id=foo>paragraph</strong></p> + <p>Second paragraph</p> + </div> + </article> + </body> +</html>`); + +exports["test items overflow"] = withTab(function*(assert) { + yield* withItems({ + i1: new Item({label: "item-1"}), + i2: new Item({label: "item-2"}), + i3: new Item({label: "item-3"}), + i4: new Item({label: "item-4"}), + i5: new Item({label: "item-5"}), + i6: new Item({label: "item-6"}), + i7: new Item({label: "item-7"}), + i8: new Item({label: "item-8"}), + i9: new Item({label: "item-9"}), + i10: new Item({label: "item-10"}), + }, function*(_) { + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menu({ + className: "sdk-context-menu-overflow-menu", + label: "Add-ons", + accesskey: "A", + }, menuitem({label: "item-1"}), + menuitem({label: "item-2"}), + menuitem({label: "item-3"}), + menuitem({label: "item-4"}), + menuitem({label: "item-5"}), + menuitem({label: "item-6"}), + menuitem({label: "item-7"}), + menuitem({label: "item-8"}), + menuitem({label: "item-9"}), + menuitem({label: "item-10"}))), + "context menu has an overflow"); + }); + + prefs.set("extensions.addon-sdk.context-menu.overflowThreshold", 3); + + yield* withItems({ + i1: new Item({label: "item-1"}), + i2: new Item({label: "item-2"}), + }, function*(_) { + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menuitem({label: "item-1"}), + menuitem({label: "item-2"})), + "two items do not overflow"); + }); + + yield* withItems({ + one: new Item({label: "one"}), + two: new Item({label: "two"}), + three: new Item({label: "three"}) + }, function*(_) { + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menu({className: "sdk-context-menu-overflow-menu", + label: "Add-ons", + accesskey: "A"}, + menuitem({label: "one"}), + menuitem({label: "two"}), + menuitem({label: "three"}))), + "three items overflow"); + }); + + prefs.reset("extensions.addon-sdk.context-menu.overflowThreshold"); + + yield* withItems({ + one: new Item({label: "one"}), + two: new Item({label: "two"}), + three: new Item({label: "three"}) + }, function*(_) { + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menuitem({label: "one"}), + menuitem({label: "two"}), + menuitem({label: "three"})), + "three items no longer overflow"); + }); +}, data`<p>Hello</p>`); + + +exports["test context menus"] = withTab(function*(assert) { + const one = new Item({ + label: "one", + context: [Contexts.Selector("p")], + read: {tagName: Readers.Query("tagName")} + }); + + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menuitem({label: "one"})), + "item is present"); + + const two = new Item({ + label: "two", + read: {tagName: Readers.Query("tagName")} + }); + + + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menuitem({label: "one"}), + menuitem({label: "two"})), + "both items are present"); + + const groupLevel1 = new Menu({label: "Level 1"}, + [one]); + + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menuitem({label: "two"}), + menu({label: "Level 1"}, + menuitem({label: "one"}))), + "first item moved to group"); + + assert.deepEqual((yield captureContextMenu("h1")), + menugroup(menuseparator(), + menuitem({label: "two"})), + "menu is hidden since only item does not match"); + + + const groupLevel2 = new Menu({label: "Level 2" }, [groupLevel1]); + + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menuitem({label: "two"}), + menu({label: "Level 2"}, + menu({label: "Level 1"}, + menuitem({label: "one"})))), + "top level menu moved to submenu"); + + assert.deepEqual((yield captureContextMenu("h1")), + menugroup(menuseparator(), + menuitem({label: "two"})), + "menu is hidden since only item does not match"); + + + const contextGroup = new Menu({ + label: "H1 Group", + context: [Contexts.Selector("h1")] + }, [ + two, + new Separator(), + new Item({ label: "three" }) + ]); + + + assert.deepEqual((yield captureContextMenu("p")), + menugroup(menuseparator(), + menu({label: "Level 2"}, + menu({label: "Level 1"}, + menuitem({label: "one"})))), + "nested menu is rendered"); + + assert.deepEqual((yield captureContextMenu("h1")), + menugroup(menuseparator(), + menu({label: "H1 Group"}, + menuitem({label: "two"}), + menuseparator(), + menuitem({label: "three"}))), + "new contextual menu rendered"); + + yield* withItems({one, two, + groupLevel1, groupLevel2, contextGroup}, function*() { + + }); + + assert.deepEqual((yield captureContextMenu("p")), + menugroup(), + "everyhing matching p was desposed"); + + assert.deepEqual((yield captureContextMenu("h1")), + menugroup(), + "everyhing matching h1 was desposed"); + +}, data`<body><h1>Title</h1><p>Content</p></body>`); + +exports["test unloading"] = withTab(function*(assert) { + const { Loader } = require("sdk/test/loader"); + const loader = Loader(module); + + const {Item, Menu, Separator, Contexts, Readers } = loader.require("sdk/context-menu@2"); + + const item = new Item({label: "item"}); + const group = new Menu({label: "menu"}, + [new Separator(), + new Item({label: "sub-item"})]); + assert.deepEqual((yield captureContextMenu()), + menugroup(menuseparator(), + menuitem({label: "item"}), + menu({label: "menu"}, + menuseparator(), + menuitem({label: "sub-item"}))), + "all items rendered"); + + + loader.unload(); + + assert.deepEqual((yield captureContextMenu()), + menugroup(), + "all items disposed"); +}, data`<body></body>`); + +if (require("@loader/options").isNative) { + module.exports = { + "test skip on jpm": (assert) => assert.pass("skipping this file with jpm") + }; +} + +before(exports, (name, assert) => { + // Make sure Java doesn't activate + prefs.set("plugin.state.java", 0); +}); + +after(exports, (name, assert) => { + prefs.reset("plugin.state.java"); +}); + +require("sdk/test").run(module.exports); |