diff --git a/mocha-client-tests/.gitignore b/mocha-client-tests/.gitignore new file mode 100644 index 0000000..f53b1be --- /dev/null +++ b/mocha-client-tests/.gitignore @@ -0,0 +1,4 @@ +node_modules +addon/bower_components +addon/node_modules +.idea \ No newline at end of file diff --git a/mocha-client-tests/README.md b/mocha-client-tests/README.md new file mode 100644 index 0000000..1d0d376 --- /dev/null +++ b/mocha-client-tests/README.md @@ -0,0 +1,17 @@ +#Mocha client tests for WebExtensions +##Install dependency +`npm install` - will install all dependencies for running PhantomJS outside of addon + +Than please run `cd ./addon/` and `npm install` to install mocha. It give you possibility to run client test inside of addon with mocha UI. If you don't want to have mocha UI you can install [WebConsole-reporter](https://github.com/eeroan/WebConsole-reporter) + +##Run with web-ext cli +Just run `npm run web-ext` (will work with FF dev edition), if you have error with web-ext cli please add path for FF binary file with `--firefox-binary /path/to/firefox-bin` +[(web-ext docs)](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/web-ext_command_reference). + +When addon will start click on mocha icon in your browser bar to run client tests: + +![addon screenshot](screenshots/addon-button.png "Mocha test addon") + +Addon will run test of `./addon/background.js` in `./addon/tests/lib/background-messaging.test.js` +##PhantomJs tests +`npm test` will run simple test of `./addon/background.js` in `./tests/lib/background.test.js` \ No newline at end of file diff --git a/mocha-client-tests/addon/background.js b/mocha-client-tests/addon/background.js new file mode 100644 index 0000000..1bda77c --- /dev/null +++ b/mocha-client-tests/addon/background.js @@ -0,0 +1,15 @@ +var Background = { + receiveMessage: function(msg, sender, sendResponse) { + if (msg && msg.action && Background.hasOwnProperty(msg.action)) { + return Background[msg.action](msg, sender, sendResponse); + } else { + console.warning('No handler for message: ' + JSON.stringify(msg)); + } + }, + ping: function(msg, sender, sendResponse) { + sendResponse('pong'); + return true; + } +}; + +chrome.runtime.onMessage.addListener(Background.receiveMessage); \ No newline at end of file diff --git a/mocha-client-tests/addon/images/icon-16.png b/mocha-client-tests/addon/images/icon-16.png new file mode 100644 index 0000000..01da9f4 Binary files /dev/null and b/mocha-client-tests/addon/images/icon-16.png differ diff --git a/mocha-client-tests/addon/images/icon-19.png b/mocha-client-tests/addon/images/icon-19.png new file mode 100644 index 0000000..1c80c9d Binary files /dev/null and b/mocha-client-tests/addon/images/icon-19.png differ diff --git a/mocha-client-tests/addon/images/mocha.png b/mocha-client-tests/addon/images/mocha.png new file mode 100644 index 0000000..83f1196 Binary files /dev/null and b/mocha-client-tests/addon/images/mocha.png differ diff --git a/mocha-client-tests/addon/manifest.json b/mocha-client-tests/addon/manifest.json new file mode 100644 index 0000000..26b0f43 --- /dev/null +++ b/mocha-client-tests/addon/manifest.json @@ -0,0 +1,28 @@ +{ + "name": "Mocha tests", + "version": "1.0", + "manifest_version": 2, + "description": "Check ", + "icons": { + "16": "images/icon-16.png" + }, + "short_name": "MochaTest", + "background": { + "scripts": [ + "background.js" + ] + }, + "browser_action": { + "default_icon": { + "19": "images/icon-19.png" + }, + "default_title": "Mocha Test", + "default_popup": "popup.html" + }, + "applications": { + "gecko": { + "strict_min_version": "45.0" + } + }, + "content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self'" +} diff --git a/mocha-client-tests/addon/package.json b/mocha-client-tests/addon/package.json new file mode 100644 index 0000000..31faea1 --- /dev/null +++ b/mocha-client-tests/addon/package.json @@ -0,0 +1,15 @@ +{ + "name": "mocha-tests-webextension", + "version": "1.0.0", + "description": "Run test inside your addon", + "main": "background.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MPL-2.0", + "devDependencies": { + "expect.js": "^0.3.1", + "mocha": "^3.1.2" + } +} diff --git a/mocha-client-tests/addon/popup.html b/mocha-client-tests/addon/popup.html new file mode 100644 index 0000000..9c33a6f --- /dev/null +++ b/mocha-client-tests/addon/popup.html @@ -0,0 +1,25 @@ + + + + Mocha Tests + + + +
+ + + + +
Hello! Lets play at ping
+ + + + + + + + + + + + \ No newline at end of file diff --git a/mocha-client-tests/addon/scripts/browser-polyfill.min.js b/mocha-client-tests/addon/scripts/browser-polyfill.min.js new file mode 100644 index 0000000..8c87af7 --- /dev/null +++ b/mocha-client-tests/addon/scripts/browser-polyfill.min.js @@ -0,0 +1,19 @@ +/* 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/. */ +if(typeof browser==="undefined"){const wrapAPIs=()=>{const apiMetadata={"alarms":{"clear":{"minArgs":0,"maxArgs":1},"clearAll":{"minArgs":0,"maxArgs":0},"get":{"minArgs":0,"maxArgs":1},"getAll":{"minArgs":0,"maxArgs":0}},"bookmarks":{"create":{"minArgs":1,"maxArgs":1},"export":{"minArgs":0,"maxArgs":0},"get":{"minArgs":1,"maxArgs":1},"getChildren":{"minArgs":1,"maxArgs":1},"getRecent":{"minArgs":1,"maxArgs":1},"getTree":{"minArgs":0,"maxArgs":0},"getSubTree":{"minArgs":1,"maxArgs":1},"import":{"minArgs":0, +"maxArgs":0},"move":{"minArgs":2,"maxArgs":2},"remove":{"minArgs":1,"maxArgs":1},"removeTree":{"minArgs":1,"maxArgs":1},"search":{"minArgs":1,"maxArgs":1},"update":{"minArgs":2,"maxArgs":2}},"browserAction":{"getBadgeBackgroundColor":{"minArgs":1,"maxArgs":1},"getBadgeText":{"minArgs":1,"maxArgs":1},"getPopup":{"minArgs":1,"maxArgs":1},"getTitle":{"minArgs":1,"maxArgs":1},"setIcon":{"minArgs":1,"maxArgs":1}},"commands":{"getAll":{"minArgs":0,"maxArgs":0}},"contextMenus":{"update":{"minArgs":2,"maxArgs":2}, +"remove":{"minArgs":1,"maxArgs":1},"removeAll":{"minArgs":0,"maxArgs":0}},"cookies":{"get":{"minArgs":1,"maxArgs":1},"getAll":{"minArgs":1,"maxArgs":1},"getAllCookieStores":{"minArgs":0,"maxArgs":0},"remove":{"minArgs":1,"maxArgs":1},"set":{"minArgs":1,"maxArgs":1}},"downloads":{"download":{"minArgs":1,"maxArgs":1},"cancel":{"minArgs":1,"maxArgs":1},"erase":{"minArgs":1,"maxArgs":1},"getFileIcon":{"minArgs":1,"maxArgs":2},"open":{"minArgs":1,"maxArgs":1},"pause":{"minArgs":1,"maxArgs":1},"removeFile":{"minArgs":1, +"maxArgs":1},"resume":{"minArgs":1,"maxArgs":1},"search":{"minArgs":1,"maxArgs":1},"show":{"minArgs":1,"maxArgs":1}},"extension":{"isAllowedFileSchemeAccess":{"minArgs":0,"maxArgs":0},"isAllowedIncognitoAccess":{"minArgs":0,"maxArgs":0}},"history":{"addUrl":{"minArgs":1,"maxArgs":1},"getVisits":{"minArgs":1,"maxArgs":1},"deleteAll":{"minArgs":0,"maxArgs":0},"deleteRange":{"minArgs":1,"maxArgs":1},"deleteUrl":{"minArgs":1,"maxArgs":1},"search":{"minArgs":1,"maxArgs":1}},"i18n":{"detectLanguage":{"minArgs":1, +"maxArgs":1},"getAcceptLanguages":{"minArgs":0,"maxArgs":0}},"idle":{"queryState":{"minArgs":1,"maxArgs":1}},"management":{"get":{"minArgs":1,"maxArgs":1},"getAll":{"minArgs":0,"maxArgs":0},"getSelf":{"minArgs":0,"maxArgs":0},"uninstallSelf":{"minArgs":0,"maxArgs":1}},"notifications":{"clear":{"minArgs":1,"maxArgs":1},"create":{"minArgs":1,"maxArgs":2},"getAll":{"minArgs":0,"maxArgs":0},"getPermissionLevel":{"minArgs":0,"maxArgs":0},"update":{"minArgs":2,"maxArgs":2}},"pageAction":{"getPopup":{"minArgs":1, +"maxArgs":1},"getTitle":{"minArgs":1,"maxArgs":1},"hide":{"minArgs":0,"maxArgs":0},"setIcon":{"minArgs":1,"maxArgs":1},"show":{"minArgs":0,"maxArgs":0}},"runtime":{"getBackgroundPage":{"minArgs":0,"maxArgs":0},"getBrowserInfo":{"minArgs":0,"maxArgs":0},"getPlatformInfo":{"minArgs":0,"maxArgs":0},"openOptionsPage":{"minArgs":0,"maxArgs":0},"requestUpdateCheck":{"minArgs":0,"maxArgs":0},"sendMessage":{"minArgs":1,"maxArgs":3},"sendNativeMessage":{"minArgs":2,"maxArgs":2},"setUninstallURL":{"minArgs":1, +"maxArgs":1}},"storage":{"local":{"clear":{"minArgs":0,"maxArgs":0},"get":{"minArgs":0,"maxArgs":1},"getBytesInUse":{"minArgs":0,"maxArgs":1},"remove":{"minArgs":1,"maxArgs":1},"set":{"minArgs":1,"maxArgs":1}},"managed":{"get":{"minArgs":0,"maxArgs":1},"getBytesInUse":{"minArgs":0,"maxArgs":1}},"sync":{"clear":{"minArgs":0,"maxArgs":0},"get":{"minArgs":0,"maxArgs":1},"getBytesInUse":{"minArgs":0,"maxArgs":1},"remove":{"minArgs":1,"maxArgs":1},"set":{"minArgs":1,"maxArgs":1}}},"tabs":{"create":{"minArgs":1, +"maxArgs":1},"captureVisibleTab":{"minArgs":0,"maxArgs":2},"detectLanguage":{"minArgs":0,"maxArgs":1},"duplicate":{"minArgs":1,"maxArgs":1},"executeScript":{"minArgs":1,"maxArgs":2},"get":{"minArgs":1,"maxArgs":1},"getCurrent":{"minArgs":0,"maxArgs":0},"getZoom":{"minArgs":0,"maxArgs":1},"getZoomSettings":{"minArgs":0,"maxArgs":1},"highlight":{"minArgs":1,"maxArgs":1},"insertCSS":{"minArgs":1,"maxArgs":2},"move":{"minArgs":2,"maxArgs":2},"reload":{"minArgs":0,"maxArgs":2},"remove":{"minArgs":1,"maxArgs":1}, +"query":{"minArgs":1,"maxArgs":1},"removeCSS":{"minArgs":1,"maxArgs":2},"sendMessage":{"minArgs":2,"maxArgs":3},"setZoom":{"minArgs":1,"maxArgs":2},"setZoomSettings":{"minArgs":1,"maxArgs":2},"update":{"minArgs":1,"maxArgs":2}},"webNavigation":{"getAllFrames":{"minArgs":1,"maxArgs":1},"getFrame":{"minArgs":1,"maxArgs":1}},"webRequest":{"handlerBehaviorChanged":{"minArgs":0,"maxArgs":0}},"windows":{"create":{"minArgs":0,"maxArgs":1},"get":{"minArgs":1,"maxArgs":2},"getAll":{"minArgs":0,"maxArgs":1}, +"getCurrent":{"minArgs":0,"maxArgs":1},"getLastFocused":{"minArgs":0,"maxArgs":1},"remove":{"minArgs":1,"maxArgs":1},"update":{"minArgs":2,"maxArgs":2}}};class DefaultWeakMap extends WeakMap{constructor(createItem,items=undefined){super(items);this.createItem=createItem}get(key){if(!this.has(key))this.set(key,this.createItem(key));return super.get(key)}}const isThenable=(value)=>{return value&&typeof value==="object"&&typeof value.then==="function"};const makeCallback=(promise)=>{return(...callbackArgs)=> +{if(chrome.runtime.lastError)promise.reject(chrome.runtime.lastError);else if(callbackArgs.length===1)promise.resolve(callbackArgs[0]);else promise.resolve(callbackArgs)}};const wrapAsyncFunction=(name,metadata)=>{return function asyncFunctionWrapper(target,...args){if(args.lengthmetadata.maxArgs)throw new Error(`Expected at most ${metadata.maxArgs} arguments for ${name}(), got ${args.length}`); +return new Promise((resolve,reject)=>{target[name](...args,makeCallback({resolve,reject}))})}};const wrapMethod=(target,method,wrapper)=>{return new Proxy(method,{apply(targetMethod,thisObj,args){return wrapper.call(thisObj,target,...args)}})};let hasOwnProperty=Function.call.bind(Object.prototype.hasOwnProperty);const wrapObject=(target,wrappers={},metadata={})=>{let cache=Object.create(null);let handlers={has(target,prop){return prop in target||prop in cache},get(target,prop,receiver){if(prop in +cache)return cache[prop];if(!(prop in target))return undefined;let value=target[prop];if(typeof value==="function")if(typeof wrappers[prop]==="function")value=wrapMethod(target,target[prop],wrappers[prop]);else if(hasOwnProperty(metadata,prop)){let wrapper=wrapAsyncFunction(prop,metadata[prop]);value=wrapMethod(target,target[prop],wrapper)}else value=value.bind(target);else if(typeof value==="object"&&value!==null&&(hasOwnProperty(wrappers,prop)||hasOwnProperty(metadata,prop)))value=wrapObject(value, +wrappers[prop],metadata[prop]);else{Object.defineProperty(cache,prop,{configurable:true,enumerable:true,get(){return target[prop]},set(value){target[prop]=value}});return value}cache[prop]=value;return value},set(target,prop,value,receiver){if(prop in cache)cache[prop]=value;else target[prop]=value;return true},defineProperty(target,prop,desc){return Reflect.defineProperty(cache,prop,desc)},deleteProperty(target,prop){return Reflect.deleteProperty(cache,prop)}};return new Proxy(target,handlers)}; +const wrapEvent=(wrapperMap)=>{addListener(target,listener,...args){target.addListener(wrapperMap.get(listener),...args)},hasListener(target,listener){return target.hasListener(wrapperMap.get(listener))},removeListener(target,listener){target.removeListener(wrapperMap.get(listener))}};const onMessageWrappers=new DefaultWeakMap((listener)=>{if(typeof listener!=="function")return listener;return function onMessage(message,sender,sendResponse){let result=listener(message,sender);if(isThenable(result)){result.then(sendResponse, +(error)=>{console.error(error);sendResponse(error)});return true}else if(result!==undefined)sendResponse(result)}});const staticWrappers={runtime:{onMessage:wrapEvent(onMessageWrappers)}};return wrapObject(chrome,staticWrappers,apiMetadata)};this.browser=wrapAPIs()}; diff --git a/mocha-client-tests/addon/scripts/popup.js b/mocha-client-tests/addon/scripts/popup.js new file mode 100644 index 0000000..b352b5f --- /dev/null +++ b/mocha-client-tests/addon/scripts/popup.js @@ -0,0 +1,10 @@ + setInterval(function() { + var $game = document.querySelector('#game'); + if($game.innerText !== 'ping'){ + $game.innerText = 'ping'; + } else{ + chrome.runtime.sendMessage({action: 'ping'},function(response) { + $game.innerText = response; + }); + } + }, 1000); diff --git a/mocha-client-tests/addon/tests/lib/background-messaging.test.js b/mocha-client-tests/addon/tests/lib/background-messaging.test.js new file mode 100644 index 0000000..b91eb5a --- /dev/null +++ b/mocha-client-tests/addon/tests/lib/background-messaging.test.js @@ -0,0 +1,11 @@ +describe('Background', function() { + describe('ping', function() { + it('should return pong in response', function() { + // Return a promise for Mocha using the Firefox browser API instead of chrome. + return browser.runtime.sendMessage({action: 'ping'}) + .then(function(response) { + expect(response).to.equal('pong'); + }); + }); + }); +}); \ No newline at end of file diff --git a/mocha-client-tests/addon/tests/lib/test.array.js b/mocha-client-tests/addon/tests/lib/test.array.js new file mode 100644 index 0000000..40a5f5e --- /dev/null +++ b/mocha-client-tests/addon/tests/lib/test.array.js @@ -0,0 +1,8 @@ +describe('Array', function() { + describe('#indexOf()', function() { + it('should return -1 when the value is not present', function() { + expect([1,2,3]).to.not.contain(5); + expect([1,2,3]).to.not.contain(0); + }); + }); +}); \ No newline at end of file diff --git a/mocha-client-tests/addon/tests/mocha-run.js b/mocha-client-tests/addon/tests/mocha-run.js new file mode 100644 index 0000000..ec1be52 --- /dev/null +++ b/mocha-client-tests/addon/tests/mocha-run.js @@ -0,0 +1,5 @@ +mocha.checkLeaks(); +// Here we add initial global variables to prevent this error: +// Error: global leaks detected: AppView, ExtensionOptions, ExtensionView, WebView +mocha.globals(['AppView', 'ExtensionOptions', 'ExtensionView', 'WebView']); +mocha.run(); \ No newline at end of file diff --git a/mocha-client-tests/addon/tests/mocha-setup.js b/mocha-client-tests/addon/tests/mocha-setup.js new file mode 100644 index 0000000..58a9e9e --- /dev/null +++ b/mocha-client-tests/addon/tests/mocha-setup.js @@ -0,0 +1 @@ +mocha.setup('bdd'); \ No newline at end of file diff --git a/mocha-client-tests/package.json b/mocha-client-tests/package.json new file mode 100644 index 0000000..eb0adb2 --- /dev/null +++ b/mocha-client-tests/package.json @@ -0,0 +1,21 @@ +{ + "name": "mocha-test-webextension", + "version": "1.0.0", + "description": "Example how to run unit tests for WebExtension", + "main": "index.js", + "scripts": { + "test": "mocha-phantomjs -p ./node_modules/phantomjs-prebuilt/bin/phantomjs -R nyan tests/background.html", + "web-ext": "web-ext run -s ./addon" + }, + "author": "", + "license": "MPL-2.0", + "devDependencies": { + "chai": "^3.5.0", + "chrome-mock": "0.0.9", + "mocha": "^3.1.2", + "mocha-phantomjs": "^4.1.0", + "phantomjs-prebuilt": "^2.1.13", + "expect.js": "^0.3.1", + "web-ext": "^1.6.0" + } +} diff --git a/mocha-client-tests/screenshots/addon-button.png b/mocha-client-tests/screenshots/addon-button.png new file mode 100644 index 0000000..6172e83 Binary files /dev/null and b/mocha-client-tests/screenshots/addon-button.png differ diff --git a/mocha-client-tests/tests/background.html b/mocha-client-tests/tests/background.html new file mode 100644 index 0000000..b2993b1 --- /dev/null +++ b/mocha-client-tests/tests/background.html @@ -0,0 +1,26 @@ + + + + Tests for background + + + + +
+ + + + + + + + + + + diff --git a/mocha-client-tests/tests/lib/background.test.js b/mocha-client-tests/tests/lib/background.test.js new file mode 100644 index 0000000..bf42c31 --- /dev/null +++ b/mocha-client-tests/tests/lib/background.test.js @@ -0,0 +1,9 @@ +describe('Background', function() { + describe('ping', function() { + it('should return pong in response', function() { + Background.ping(false, false, function(response) { + expect(response).to.equal('pong'); + }); + }); + }); +}); \ No newline at end of file