diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .jpmignore | 10 | ||||
-rw-r--r-- | background.js | 222 | ||||
-rwxr-xr-x | build.py | 2 | ||||
-rw-r--r-- | icon.html | 6 | ||||
-rw-r--r-- | images/icon-active-128.png (renamed from images/icon128active.png) | bin | 1211 -> 1211 bytes | |||
-rw-r--r-- | images/icon-active-16.png (renamed from images/icon16active.png) | bin | 272 -> 272 bytes | |||
-rw-r--r-- | images/icon-active-19.png (renamed from images/icon19active.png) | bin | 285 -> 285 bytes | |||
-rw-r--r-- | images/icon-active-32.png (renamed from images/icon32active.png) | bin | 402 -> 402 bytes | |||
-rw-r--r-- | images/icon-active-38.png (renamed from images/icon38active.png) | bin | 417 -> 417 bytes | |||
-rw-r--r-- | images/icon-active-48.png (renamed from images/icon48active.png) | bin | 464 -> 464 bytes | |||
-rw-r--r-- | images/icon-active-64.png | bin | 0 -> 575 bytes | |||
-rw-r--r-- | images/icon-disabled-128.png (renamed from images/icon128disabled.png) | bin | 1202 -> 1202 bytes | |||
-rw-r--r-- | images/icon-disabled-16.png (renamed from images/icon16disabled.png) | bin | 274 -> 274 bytes | |||
-rw-r--r-- | images/icon-disabled-19.png (renamed from images/icon19disabled.png) | bin | 285 -> 285 bytes | |||
-rw-r--r-- | images/icon-disabled-32.png (renamed from images/icon32disabled.png) | bin | 399 -> 399 bytes | |||
-rw-r--r-- | images/icon-disabled-38.png (renamed from images/icon38disabled.png) | bin | 424 -> 424 bytes | |||
-rw-r--r-- | images/icon-disabled-48.png (renamed from images/icon48disabled.png) | bin | 474 -> 474 bytes | |||
-rw-r--r-- | images/icon-disabled-64.png | bin | 0 -> 583 bytes | |||
-rw-r--r-- | images/icon128redirected.png | bin | 1168 -> 0 bytes | |||
-rw-r--r-- | images/icon19redirected.png | bin | 262 -> 0 bytes | |||
-rw-r--r-- | images/icon38redirected.png | bin | 386 -> 0 bytes | |||
-rw-r--r-- | js/background.js | 79 | ||||
-rw-r--r-- | js/firefox/background-shim.js | 50 | ||||
-rw-r--r-- | js/firefox/page-shim.js | 10 | ||||
-rw-r--r-- | manifest.json | 13 | ||||
-rw-r--r-- | test/test-index.js | 19 |
27 files changed, 88 insertions, 326 deletions
@@ -3,5 +3,6 @@ *.zip build/* ffox.sh - +devprofile/* +debug.sh diff --git a/.jpmignore b/.jpmignore new file mode 100644 index 0000000..260fe4e --- /dev/null +++ b/.jpmignore @@ -0,0 +1,10 @@ +.DS_Store +*.zip +*.xpi +manifest.json +.git/* +.gitignore +*.py +devprofile/* +debug.sh + diff --git a/background.js b/background.js deleted file mode 100644 index 4dbbdd3..0000000 --- a/background.js +++ /dev/null @@ -1,222 +0,0 @@ - -//This is the background script. It is responsible for actually redirecting requests, -//as well as monitoring changes in the redirects and the disabled status and reacting to them. - -//TODO: Better browser detection... -var isFirefox = false; - -if (typeof chrome == 'undefined') { - isFirefox = true; - var firefoxShim = require('./firefox/shim'); - chrome = firefoxShim.chrome; - Redirect = firefoxShim.Redirect; -} -//Hopefully Firefox will fix this at some point and we can just use onBeforeRequest everywhere... -var redirectEvent = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.webRequest.onBeforeRequest; - -//Redirects partitioned by request type, so we have to run through -//the minimum number of redirects for each request. -var partitionedRedirects = {}; - -//Keep track of tabids where the main_frame url has been redirected. -//Mark it as green until a new url is loaded. -var tabIdToIcon = { - -}; - -//Cache of urls that have just been redirected to. They will not be redirected again, to -//stop recursive redirects, and endless redirect chains. -//Key is url, value is timestamp of redirect. -var ignoreNextRequest = { - -}; - -function log(msg) { - if (log.enabled) { - console.log('REDIRECTOR: ' + msg); - } -} -log.enabled = true; - -function setIcon(image19, image38, tabId) { - var data = { - path: { - 19: image19, - 38: image38 - } - }; - if (typeof tabId !== 'undefined') { - data.tabId = tabId; - } - chrome.browserAction.setIcon(data, function(tab) { - var err = chrome.runtime.lastError; - if (err) { - //If not checked we will get unchecked errors in the background page console... - log('Error in SetIcon: ' + err.message); - } - }); -} - -//This is the actual function that gets called for each request and must -//decide whether or not we want to redirect. -function checkRedirects(details) { - - //We only allow GET request to be redirected, don't want to accidentally redirect - //sensitive POST parameters - if (details.method != 'GET') { - return null; - } - - log('Checking: ' + details.type + ': ' + details.url); - - var list = partitionedRedirects[details.type]; - if (!list) { - log('No list for type: ' + details.type); - return null; - } - - var timestamp = ignoreNextRequest[details.url]; - if (timestamp) { - log('Ignoring ' + details.url + ', was just redirected ' + (new Date().getTime()-timestamp) + 'ms ago'); - delete ignoreNextRequest[details.url]; - return null; - } - - for (var i = 0; i < list.length; i++) { - var r = list[i]; - var result = r.getMatch(details.url); - - if (result.isMatch) { - - log('Redirecting ' + details.url + ' ===> ' + result.redirectTo + ', type: ' + details.type + ', pattern: ' + r.includePattern); - - /* Unfortunately the setBrowserIcon for a specific tab function is way too unreliable, fails all the time with tab not found, - even though the tab is there. So, for now I'm cancelling this feature, which would have been pretty great ... :/ - if (details.type == 'main_frame') { - log('Setting icon on tab ' + details.tabId + ' to green'); - - setIcon("images/icon19redirected.png", "images/icon38redirected.png", details.tabId); - tabIdToIcon[details.tabId] = true; - }*/ - ignoreNextRequest[result.redirectTo] = new Date().getTime(); - - return { redirectUrl: result.redirectTo }; - } - } - - /* Cancelled for now because of setBrowserIcon being really unreliable... - if (details.type == 'main_frame' && tabIdToIcon[details.tabId]) { - log('Setting icon on tab ' + details.tabId + ' back to active'); - setIcon("images/icon19active.png", "images/icon38active.png", details.tabId); - delete tabIdToIcon[details.tabId]; - }*/ - - return null; -} - -//Monitor changes in data, and setup everything again. -//This could probably be optimized to not do everything on every change -//but why bother? -chrome.storage.onChanged.addListener(function(changes, namespace) { - if (changes.disabled) { - updateIcon(); - - if (changes.disabled.newValue == true) { - log('Disabling Redirector, removing listener'); - redirectEvent.removeListener(checkRedirects); - } else { - log('Enabling Redirector, setting up listener'); - setUpRedirectListener(); - } - } - - if (changes.redirects) { - log('Redirects have changed, setting up listener again'); - setUpRedirectListener(); - } -}); - -//Creates a filter to pass to the listener so we don't have to run through -//all the redirects for all the request types we don't have any redirects for anyway. -function createFilter(redirects) { - var types = []; - for (var i = 0; i < redirects.length; i++) { - redirects[i].appliesTo.forEach(function(type) { - if (types.indexOf(type) == -1) { - types.push(type); - } - }); - } - types.sort(); - - return { - urls: ["http://*/*", "https://*/*"], - types : types - }; -} - -function createPartitionedRedirects(redirects) { - var partitioned = {}; - - for (var i = 0; i < redirects.length; i++) { - var redirect = new Redirect(redirects[i]); - redirect.compile(); - for (var j=0; j<redirect.appliesTo.length;j++) { - var requestType = redirect.appliesTo[j]; - if (partitioned[requestType]) { - partitioned[requestType].push(redirect); - } else { - partitioned[requestType] = [redirect]; - } - } - } - return partitioned; -} - -//Sets up the listener, partitions the redirects, creates the appropriate filters etc. -function setUpRedirectListener() { - - redirectEvent.removeListener(checkRedirects); //Unsubscribe first, in case there are changes... - - chrome.storage.local.get({redirects:'firstrun'}, function(obj) { - var redirects = obj.redirects; - - if (redirects === 'firstrun') { - log('No redirects to set up, first run of extension'); - //TODO: import old Firefox redirects - return; - } - - if (redirects.length == 0) { - return; - } - - partitionedRedirects = createPartitionedRedirects(redirects); - var filter = createFilter(redirects); - - log('Setting filter for listener: ' + JSON.stringify(filter)); - redirectEvent.addListener(checkRedirects, filter, ["blocking"]); - }); -} - -function updateIcon() { - chrome.storage.local.get({disabled:false}, function(obj) { - if (obj.disabled) { - setIcon("images/icon19disabled.png", "images/icon38disabled.png"); - } else { - setIcon("images/icon19active.png", "images/icon38active.png"); - } - }); -} - -//First time setup -updateIcon(); -chrome.storage.local.get({disabled:false}, function(obj) { - if (!obj.disabled) { - setUpRedirectListener(); - } else { - log('Redirector is disabled'); - } -}); -log('Redirector starting up...'); -
\ No newline at end of file @@ -4,7 +4,7 @@ import os, os.path, re, zipfile, json def get_files_to_zip(): #Exclude git stuff, build scripts etc. - exclude = [r'(\\|/)\.git(\\|/)', r'\.(py|sh)$', r'\.DS_Store$', r'\.gitignore$',r'(\\|/)build(\\|/)'] + exclude = [r'(\\|/)\.git(\\|/)', r'\.(py|sh)$', r'\.DS_Store$', r'\.gitignore$',r'(\\|/)build(\\|/)', '.*devprofile.*', r'debug\.sh'] zippable_files = [] for root, folders, files in os.walk('.'): @@ -23,7 +23,7 @@ <script> function createImageLink(size, logoFontSize, logoX, logoY) { - var colors = {'#333' : 'active', '#bbb' : 'disabled', 'green' : 'redirected'}; + var colors = {'#333' : 'active', '#bbb' : 'disabled'}; for (var color in colors) { var canvas = document.createElement('canvas'); canvas.width = canvas.height = size; @@ -37,7 +37,7 @@ var img = document.createElement('img'); img.src = canvas.toDataURL(); a.href = canvas.toDataURL(); - a.download = 'icon' + size + colors[color] + '.png'; + a.download = 'icon-' + colors[color] + '-' + size + '.png'; a.appendChild(img); a.style.width = size + 'px' document.body.appendChild(a); @@ -50,8 +50,8 @@ createImageLink(32, 64, 1, 32); createImageLink(38, 75, 2, 38); createImageLink(48, 95, 1, 48); + createImageLink(64, 125, 3, 63); createImageLink(128, 215, 12, 116); - }); </script> diff --git a/images/icon128active.png b/images/icon-active-128.png Binary files differindex 5ef6a8b..5ef6a8b 100644 --- a/images/icon128active.png +++ b/images/icon-active-128.png diff --git a/images/icon16active.png b/images/icon-active-16.png Binary files differindex 9482d4b..9482d4b 100644 --- a/images/icon16active.png +++ b/images/icon-active-16.png diff --git a/images/icon19active.png b/images/icon-active-19.png Binary files differindex def8e2f..def8e2f 100644 --- a/images/icon19active.png +++ b/images/icon-active-19.png diff --git a/images/icon32active.png b/images/icon-active-32.png Binary files differindex 2bc01ff..2bc01ff 100644 --- a/images/icon32active.png +++ b/images/icon-active-32.png diff --git a/images/icon38active.png b/images/icon-active-38.png Binary files differindex 2e08aec..2e08aec 100644 --- a/images/icon38active.png +++ b/images/icon-active-38.png diff --git a/images/icon48active.png b/images/icon-active-48.png Binary files differindex f63956b..f63956b 100644 --- a/images/icon48active.png +++ b/images/icon-active-48.png diff --git a/images/icon-active-64.png b/images/icon-active-64.png Binary files differnew file mode 100644 index 0000000..accf6a5 --- /dev/null +++ b/images/icon-active-64.png diff --git a/images/icon128disabled.png b/images/icon-disabled-128.png Binary files differindex 002c9d5..002c9d5 100644 --- a/images/icon128disabled.png +++ b/images/icon-disabled-128.png diff --git a/images/icon16disabled.png b/images/icon-disabled-16.png Binary files differindex 23d6675..23d6675 100644 --- a/images/icon16disabled.png +++ b/images/icon-disabled-16.png diff --git a/images/icon19disabled.png b/images/icon-disabled-19.png Binary files differindex f5eaa06..f5eaa06 100644 --- a/images/icon19disabled.png +++ b/images/icon-disabled-19.png diff --git a/images/icon32disabled.png b/images/icon-disabled-32.png Binary files differindex 28d2dc0..28d2dc0 100644 --- a/images/icon32disabled.png +++ b/images/icon-disabled-32.png diff --git a/images/icon38disabled.png b/images/icon-disabled-38.png Binary files differindex 7e900ba..7e900ba 100644 --- a/images/icon38disabled.png +++ b/images/icon-disabled-38.png diff --git a/images/icon48disabled.png b/images/icon-disabled-48.png Binary files differindex e2826c4..e2826c4 100644 --- a/images/icon48disabled.png +++ b/images/icon-disabled-48.png diff --git a/images/icon-disabled-64.png b/images/icon-disabled-64.png Binary files differnew file mode 100644 index 0000000..97f057a --- /dev/null +++ b/images/icon-disabled-64.png diff --git a/images/icon128redirected.png b/images/icon128redirected.png Binary files differdeleted file mode 100644 index 8f7c6df..0000000 --- a/images/icon128redirected.png +++ /dev/null diff --git a/images/icon19redirected.png b/images/icon19redirected.png Binary files differdeleted file mode 100644 index dce8b13..0000000 --- a/images/icon19redirected.png +++ /dev/null diff --git a/images/icon38redirected.png b/images/icon38redirected.png Binary files differdeleted file mode 100644 index 45c1db8..0000000 --- a/images/icon38redirected.png +++ /dev/null diff --git a/js/background.js b/js/background.js index 4b2d1cf..4cd3d62 100644 --- a/js/background.js +++ b/js/background.js @@ -5,12 +5,11 @@ //TODO: Better browser detection... var isFirefox = false; -if (!this.chrome) { +if (typeof chrome == 'undefined') { isFirefox = true; var firefoxShim = require('./firefox/background-shim'); chrome = firefoxShim.chrome; Redirect = firefoxShim.Redirect; - console.log(this.Redirect) } //Hopefully Firefox will fix this at some point and we can just use onBeforeRequest everywhere... var redirectEvent = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.webRequest.onBeforeRequest; @@ -19,12 +18,6 @@ var redirectEvent = isFirefox ? chrome.webRequest.onBeforeSendHeaders : chrome.w //the minimum number of redirects for each request. var partitionedRedirects = {}; -//Keep track of tabids where the main_frame url has been redirected. -//Mark it as green until a new url is loaded. -var tabIdToIcon = { - -}; - //Cache of urls that have just been redirected to. They will not be redirected again, to //stop recursive redirects, and endless redirect chains. //Key is url, value is timestamp of redirect. @@ -39,17 +32,13 @@ function log(msg) { } log.enabled = true; -function setIcon(image19, image38, tabId) { - var data = { - path: { - 19: image19, - 38: image38 - } - }; - if (typeof tabId !== 'undefined') { - data.tabId = tabId; - } - chrome.browserAction.setIcon(data, function(tab) { +function setIcon(image) { + var sizes = [16,19,32,38,48,64]; + var data = { path: {}}; + for (var s of sizes) { + data.path[s] = 'images/' + image + '-' + s + '.png'; + } + chrome.browserAction.setIcon(data, function() { var err = chrome.runtime.lastError; if (err) { //If not checked we will get unchecked errors in the background page console... @@ -61,26 +50,31 @@ function setIcon(image19, image38, tabId) { //This is the actual function that gets called for each request and must //decide whether or not we want to redirect. function checkRedirects(details) { - + + //Oh Firefox, please fix your broken url matching soon... + if (isFirefox && !details.url.match(/^https?:\/\//)) { + log('Not http: ' + details.url); + return {}; + } + //We only allow GET request to be redirected, don't want to accidentally redirect //sensitive POST parameters if (details.method != 'GET') { - return null; + return {}; } - log('Checking: ' + details.type + ': ' + details.url); var list = partitionedRedirects[details.type]; if (!list) { log('No list for type: ' + details.type); - return null; + return {}; } var timestamp = ignoreNextRequest[details.url]; if (timestamp) { log('Ignoring ' + details.url + ', was just redirected ' + (new Date().getTime()-timestamp) + 'ms ago'); delete ignoreNextRequest[details.url]; - return null; + return {}; } for (var i = 0; i < list.length; i++) { @@ -91,28 +85,13 @@ function checkRedirects(details) { log('Redirecting ' + details.url + ' ===> ' + result.redirectTo + ', type: ' + details.type + ', pattern: ' + r.includePattern); - /* Unfortunately the setBrowserIcon for a specific tab function is way too unreliable, fails all the time with tab not found, - even though the tab is there. So, for now I'm cancelling this feature, which would have been pretty great ... :/ - if (details.type == 'main_frame') { - log('Setting icon on tab ' + details.tabId + ' to green'); - - setIcon("images/icon19redirected.png", "images/icon38redirected.png", details.tabId); - tabIdToIcon[details.tabId] = true; - }*/ ignoreNextRequest[result.redirectTo] = new Date().getTime(); return { redirectUrl: result.redirectTo }; } } - /* Cancelled for now because of setBrowserIcon being really unreliable... - if (details.type == 'main_frame' && tabIdToIcon[details.tabId]) { - log('Setting icon on tab ' + details.tabId + ' back to active'); - setIcon("images/icon19active.png", "images/icon38active.png", details.tabId); - delete tabIdToIcon[details.tabId]; - }*/ - - return null; + return {}; } //Monitor changes in data, and setup everything again. @@ -150,8 +129,10 @@ function createFilter(redirects) { } types.sort(); + //FIXME: The Firefox implementation of the url matching is seriously broken still, + //so we can't filter by url on Firefox for now, have to cut non http urls out in checkRedirects. return { - urls: ["http://*/*", "https://*/*"], + urls: isFirefox ? null : ["https://*", "http://*"], types : types }; } @@ -179,16 +160,11 @@ function setUpRedirectListener() { redirectEvent.removeListener(checkRedirects); //Unsubscribe first, in case there are changes... - chrome.storage.local.get({redirects:'firstrun'}, function(obj) { + chrome.storage.local.get({redirects:[]}, function(obj) { var redirects = obj.redirects; - if (redirects === 'firstrun') { - log('No redirects to set up, first run of extension'); - //TODO: import old Firefox redirects - return; - } - if (redirects.length == 0) { + log('No redirects defined, not setting up listener'); return; } @@ -202,16 +178,13 @@ function setUpRedirectListener() { function updateIcon() { chrome.storage.local.get({disabled:false}, function(obj) { - if (obj.disabled) { - setIcon("images/icon19disabled.png", "images/icon38disabled.png"); - } else { - setIcon("images/icon19active.png", "images/icon38active.png"); - } + setIcon(obj.disabled ? 'icon-disabled' : 'icon-active'); }); } //First time setup updateIcon(); + chrome.storage.local.get({disabled:false}, function(obj) { if (!obj.disabled) { setUpRedirectListener(); diff --git a/js/firefox/background-shim.js b/js/firefox/background-shim.js index fb08039..453feff 100644 --- a/js/firefox/background-shim.js +++ b/js/firefox/background-shim.js @@ -16,8 +16,8 @@ var button = ToggleButton({ id: "redirector", label: "Redirector", icon: { - "16": makeUrl("images/icon16active.png"), - "32": makeUrl("images/icon32active.png") + "16": makeUrl("images/icon-active-16.png"), + "32": makeUrl("images/icon-active-32.png") }, onChange: function(state) { if (state.checked) { @@ -26,15 +26,6 @@ var button = ToggleButton({ } }); -var panel = panels.Panel({ - width: 200, - height: 130, - contentURL: makeUrl('popup.html'), - contentScriptFile : makeUrl('js/firefox/content-script-proxy.js'), - onHide: function() { - button.state('window', {checked: false}); - } -}); var extensionId = require('../../package.json').id; @@ -66,37 +57,58 @@ var chrome = { browserAction : { setIcon : function(data, callback) { - + var icon = {}; + for (var key in data.path) { + icon[key] = makeUrl(data.path[key]); + } + button.icon = icon; } } }; var pageMod = require("sdk/page-mod"); +var panel = panels.Panel({ + width: 200, + height: 130, + contentURL: makeUrl('popup.html'), + contentScriptFile : makeUrl('js/firefox/content-script-proxy.js'), + onHide: function() { + button.state('window', {checked: false}); + } +}); + function attachedPage(worker) { + function sendReply(originalMessage, reply) { + if (JSON.stringify(reply) == "{}") { + throw 'fuck'; + } + var msg = {messageId:originalMessage.messageId, payload:reply}; + console.info('background sending message: ' + JSON.stringify(msg)); + worker.port.emit('message', msg); + } worker.port.on('message', function(message) { console.info('background got message: ' + JSON.stringify(message)); if (message.messageType == 'storage.get') { console.info('Getting from storage'); chrome.storage.local.get(message.payload, function(data) { - var resultMsg = { messageId: message.messageId, payload: data }; - console.info('background sending message: ' + JSON.stringify(resultMsg)); - worker.port.emit('message', resultMsg); + sendReply(message, data); }); } else if (message.messageType == 'storage.set') { chrome.storage.local.set(message.payload, function(data) { - var resultMsg = { messageId: message.messageId, payload: data }; - console.info('background sending message: ' + JSON.stringify(resultMsg)); - worker.port.emit('message', resultMsg); + sendReply(message, data); }); - } + } }); } +attachedPage(panel); + pageMod.PageMod({ include: makeUrl('redirector.html'), contentScriptFile: makeUrl('js/firefox/content-script-proxy.js'), + contentScriptWhen: 'start', onAttach : attachedPage }); diff --git a/js/firefox/page-shim.js b/js/firefox/page-shim.js index fc63f89..3531fa4 100644 --- a/js/firefox/page-shim.js +++ b/js/firefox/page-shim.js @@ -5,7 +5,7 @@ var callbacks = {}; function send(type, message, callback) { var id = messageId++; - window.postMessage({sender:'page', messageId:id, messageType:type, payload:message}, '*'); + window.postMessage({sender:'page', url:location.href, messageId:id, messageType:type, payload:message}, '*'); callbacks[id] = callback; } @@ -23,6 +23,12 @@ } }); + var req = new XMLHttpRequest(); + req.overrideMimeType('application/json'); + req.open("GET", 'package.json', false); + req.send(); + var manifest = JSON.parse(req.responseText); + window.chrome = { storage : { local : { @@ -53,7 +59,7 @@ runtime : { getManifest : function() { - return { version : '3.0' }; + return manifest; } } }; diff --git a/manifest.json b/manifest.json index b0c7b8e..405765d 100644 --- a/manifest.json +++ b/manifest.json @@ -5,10 +5,11 @@ "description": "Redirect pages based on user-defined patterns.", "version": "3.0", - "icons": { "16": "images/icon16active.png", - "32": "images/icon32active.png", - "48": "images/icon48active.png", - "128": "images/icon128active.png" }, + "icons": { "16": "images/icon-active-16.png", + "32": "images/icon-active-32.png", + "48": "images/icon-active-48.png", + "64": "images/icon-active-64.png", + "128": "images/icon-active-128.png" }, "permissions" : ["webRequest", "webRequestBlocking", "storage", "tabs", "http://*/*", "https://*/*"], @@ -30,8 +31,8 @@ "browser_action": { "default_icon": { - "19": "images/icon19active.png", - "38": "images/icon38active.png" + "19": "images/icon-active-19.png", + "38": "images/icon-active-38.png" }, "default_title": "Redirector", "default_popup": "popup.html" diff --git a/test/test-index.js b/test/test-index.js deleted file mode 100644 index b3ad6e8..0000000 --- a/test/test-index.js +++ /dev/null @@ -1,19 +0,0 @@ -var main = require("../"); - -exports["test main"] = function(assert) { - assert.pass("Unit test running!"); -}; - -exports["test main async"] = function(assert, done) { - assert.pass("async Unit test running!"); - done(); -}; - -exports["test dummy"] = function(assert, done) { - main.dummy("foo", function(text) { - assert.ok((text === "foo"), "Is the text actually 'foo'"); - done(); - }); -}; - -require("sdk/test").run(exports); |