commit
a48915d4e0
21 changed files with 4203 additions and 436 deletions
@ -1,3 +1,4 @@ |
||||
/node_modules/ |
||||
/build/ |
||||
/e2e/ambassador/build/ |
||||
*.zip |
||||
|
@ -0,0 +1,28 @@ |
||||
{ |
||||
"manifest_version": 2, |
||||
"name": "ambassador", |
||||
"description": "WebExtension test helper", |
||||
"version": "0.1", |
||||
"content_scripts": [ |
||||
{ |
||||
"all_frames": true, |
||||
"matches": [ "<all_urls>" ], |
||||
"js": [ "build/content.js" ], |
||||
"run_at": "document_start", |
||||
"match_about_blank": true |
||||
} |
||||
], |
||||
"background": { |
||||
"scripts": [ |
||||
"build/background.js" |
||||
] |
||||
}, |
||||
"permissions": [ |
||||
"history", |
||||
"sessions", |
||||
"storage", |
||||
"tabs", |
||||
"clipboardRead", |
||||
"activeTab" |
||||
] |
||||
} |
@ -0,0 +1,36 @@ |
||||
import { |
||||
WINDOWS_CREATE, WINDOWS_REMOVE, WINDOWS_GET, |
||||
TABS_CREATE, |
||||
EVENT_KEYPRESS, EVENT_KEYDOWN, EVENT_KEYUP, |
||||
} from '../shared/messages'; |
||||
import * as tabs from './tabs'; |
||||
import { receiveContentMessage } from './ipc'; |
||||
|
||||
receiveContentMessage((message) => { |
||||
switch (message.type) { |
||||
case WINDOWS_CREATE: |
||||
return browser.windows.create({ url: message.url }); |
||||
case WINDOWS_REMOVE: |
||||
return browser.windows.remove(message.windowId); |
||||
case WINDOWS_GET: |
||||
return browser.windows.get(message.windowId, { populate: true }); |
||||
case TABS_CREATE: |
||||
return tabs.create({ |
||||
url: message.url, |
||||
windowId: message.windowId, |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
|
||||
receiveContentMessage((message) => { |
||||
switch (message.type) { |
||||
case EVENT_KEYPRESS: |
||||
case EVENT_KEYDOWN: |
||||
case EVENT_KEYUP: |
||||
return browser.tabs.sendMessage( |
||||
message.tabId, |
||||
message |
||||
); |
||||
} |
||||
}); |
@ -0,0 +1,7 @@ |
||||
const receiveContentMessage = (func) => { |
||||
browser.runtime.onMessage.addListener((message) => { |
||||
return func(message); |
||||
}); |
||||
}; |
||||
|
||||
export { receiveContentMessage }; |
@ -0,0 +1,18 @@ |
||||
const create = (props = {}) => { |
||||
return new Promise((resolve) => { |
||||
browser.tabs.create(props).then((createdTab) => { |
||||
let callback = (tabId, changeInfo, tab) => { |
||||
if (tab.url !== 'about:blank' && tabId === createdTab.id && |
||||
changeInfo.status === 'complete') { |
||||
browser.tabs.onUpdated.removeListener(callback); |
||||
resolve(tab); |
||||
} |
||||
}; |
||||
browser.tabs.onUpdated.addListener(callback); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
export { |
||||
create, |
||||
}; |
@ -0,0 +1,29 @@ |
||||
import { METHOD_REQUEST, METHOD_RESPONSE } from '../shared/messages'; |
||||
|
||||
const generateId = () => { |
||||
return Math.random().toString(); |
||||
}; |
||||
|
||||
const send = (message) => { |
||||
return new Promise((resolve) => { |
||||
let id = generateId(); |
||||
let callback = (e) => { |
||||
let packet = e.data; |
||||
if (e.source !== window || packet.method !== METHOD_RESPONSE || |
||||
packet.id !== id) { |
||||
return; |
||||
} |
||||
window.removeEventListener('message', callback); |
||||
resolve(packet.message); |
||||
}; |
||||
window.addEventListener('message', callback); |
||||
|
||||
window.postMessage({ |
||||
id, |
||||
method: METHOD_REQUEST, |
||||
message |
||||
}, window.origin); |
||||
}); |
||||
}; |
||||
|
||||
export { send }; |
@ -0,0 +1,29 @@ |
||||
import { EVENT_KEYPRESS, EVENT_KEYDOWN, EVENT_KEYUP } from '../shared/messages'; |
||||
import * as ipc from './ipc'; |
||||
|
||||
const press = (tabId, key) => { |
||||
return ipc.send({ |
||||
type: EVENT_KEYPRESS, |
||||
tabId, |
||||
key, |
||||
}); |
||||
}; |
||||
|
||||
const down = (tabId, key) => { |
||||
return ipc.send({ |
||||
type: EVENT_KEYDOWN, |
||||
tabId, |
||||
key, |
||||
}); |
||||
}; |
||||
|
||||
|
||||
const up = (tabId, key) => { |
||||
return ipc.send({ |
||||
type: EVENT_KEYUP, |
||||
tabId, |
||||
key, |
||||
}); |
||||
}; |
||||
|
||||
export { press, down, up }; |
@ -0,0 +1,12 @@ |
||||
import { TABS_CREATE } from '../shared/messages'; |
||||
import * as ipc from './ipc'; |
||||
|
||||
const create = (windowId, url) => { |
||||
return ipc.send({ |
||||
type: TABS_CREATE, |
||||
windowId, |
||||
url, |
||||
}); |
||||
}; |
||||
|
||||
export { create }; |
@ -0,0 +1,27 @@ |
||||
import { |
||||
WINDOWS_CREATE, WINDOWS_REMOVE, WINDOWS_GET |
||||
} from '../shared/messages'; |
||||
import * as ipc from './ipc'; |
||||
|
||||
const create = (url) => { |
||||
return ipc.send({ |
||||
type: WINDOWS_CREATE, |
||||
url, |
||||
}); |
||||
}; |
||||
|
||||
const remove = (windowId) => { |
||||
return ipc.send({ |
||||
type: WINDOWS_REMOVE, |
||||
windowId, |
||||
}); |
||||
}; |
||||
|
||||
const get = (windowId) => { |
||||
return ipc.send({ |
||||
type: WINDOWS_GET, |
||||
windowId, |
||||
}); |
||||
}; |
||||
|
||||
export { create, remove, get }; |
@ -0,0 +1,37 @@ |
||||
import { |
||||
WINDOWS_CREATE, WINDOWS_REMOVE, WINDOWS_GET, |
||||
TABS_CREATE, |
||||
EVENT_KEYPRESS, EVENT_KEYDOWN, EVENT_KEYUP, |
||||
} from '../shared/messages'; |
||||
import * as ipc from './ipc'; |
||||
|
||||
ipc.receivePageMessage((message) => { |
||||
switch (message.type) { |
||||
case WINDOWS_CREATE: |
||||
case WINDOWS_REMOVE: |
||||
case WINDOWS_GET: |
||||
case TABS_CREATE: |
||||
case EVENT_KEYPRESS: |
||||
case EVENT_KEYDOWN: |
||||
case EVENT_KEYUP: |
||||
return ipc.sendToBackground(message); |
||||
} |
||||
}); |
||||
|
||||
ipc.receiveBackgroundMesssage((message) => { |
||||
switch (message.type) { |
||||
case EVENT_KEYPRESS: |
||||
document.body.dispatchEvent( |
||||
new KeyboardEvent('keypress', { 'key': message.key })); |
||||
break; |
||||
case EVENT_KEYDOWN: |
||||
document.body.dispatchEvent( |
||||
new KeyboardEvent('keydown', { 'key': message.key })); |
||||
break; |
||||
case EVENT_KEYUP: |
||||
document.body.dispatchEvent( |
||||
new KeyboardEvent('keyup', { 'key': message.key })); |
||||
break; |
||||
} |
||||
return Promise.resolve({}); |
||||
}); |
@ -0,0 +1,40 @@ |
||||
import { METHOD_REQUEST, METHOD_RESPONSE } from '../shared/messages'; |
||||
|
||||
const sendToBackground = (message) => { |
||||
return browser.runtime.sendMessage(message); |
||||
}; |
||||
|
||||
const receiveBackgroundMesssage = (func) => { |
||||
return browser.runtime.onMessage.addListener((message) => { |
||||
return Promise.resolve(func(message)); |
||||
}); |
||||
}; |
||||
|
||||
const receivePageMessage = (func) => { |
||||
window.addEventListener('message', (e) => { |
||||
let packet = e.data; |
||||
if (e.origin !== window.origin || packet.method !== METHOD_REQUEST) { |
||||
return; |
||||
} |
||||
|
||||
let resp = { |
||||
id: packet.id, |
||||
method: METHOD_RESPONSE, |
||||
}; |
||||
let respMessage = func(packet.message); |
||||
if (respMessage instanceof Promise) { |
||||
return respMessage.then((data) => { |
||||
resp.message = data; |
||||
e.source.postMessage(resp, e.origin); |
||||
}); |
||||
} else if (respMessage) { |
||||
resp.message = respMessage; |
||||
} |
||||
e.source.postMessage(resp, e.origin); |
||||
}); |
||||
}; |
||||
|
||||
export { |
||||
sendToBackground, receiveBackgroundMesssage, |
||||
receivePageMessage, |
||||
}; |
@ -0,0 +1,24 @@ |
||||
const METHOD_REQUEST = 'request'; |
||||
const METHOD_RESPONSE = 'response'; |
||||
const WINDOWS_CREATE = 'windows.create'; |
||||
const WINDOWS_REMOVE = 'windows.remove'; |
||||
const WINDOWS_GET = 'windows.get'; |
||||
const TABS_CREATE = 'tabs.create'; |
||||
const EVENT_KEYPRESS = 'event.keypress'; |
||||
const EVENT_KEYDOWN = 'event.keydown'; |
||||
const EVENT_KEYUP = 'event.keyup'; |
||||
|
||||
export { |
||||
METHOD_REQUEST, |
||||
METHOD_RESPONSE, |
||||
|
||||
WINDOWS_CREATE, |
||||
WINDOWS_REMOVE, |
||||
WINDOWS_GET, |
||||
|
||||
TABS_CREATE, |
||||
|
||||
EVENT_KEYPRESS, |
||||
EVENT_KEYDOWN, |
||||
EVENT_KEYUP, |
||||
}; |
@ -0,0 +1,37 @@ |
||||
const path = require('path'); |
||||
|
||||
const src = path.resolve(__dirname, 'src'); |
||||
const dist = path.resolve(__dirname, 'build'); |
||||
|
||||
config = { |
||||
entry: { |
||||
content: path.join(src, 'content'), |
||||
background: path.join(src, 'background') |
||||
}, |
||||
|
||||
output: { |
||||
path: dist, |
||||
filename: '[name].js' |
||||
}, |
||||
|
||||
module: { |
||||
loaders: [ |
||||
{ |
||||
test: [ /\.js$/ ], |
||||
exclude: /node_modules/, |
||||
loader: 'babel-loader', |
||||
query: { |
||||
presets: ['es2015'] |
||||
} |
||||
} |
||||
] |
||||
}, |
||||
|
||||
resolve: { |
||||
extensions: [ '.js' ], |
||||
modules: [path.join(__dirname, 'src'), 'node_modules'] |
||||
} |
||||
}; |
||||
|
||||
module.exports = config |
||||
|
@ -0,0 +1,48 @@ |
||||
import { expect } from "chai"; |
||||
import * as windows from "../ambassador/src/client/windows"; |
||||
import * as tabs from "../ambassador/src/client/tabs"; |
||||
import * as keys from "../ambassador/src/client/keys"; |
||||
|
||||
const SERVER_URL = "localhost:11111"; |
||||
|
||||
describe("tab test", () => { |
||||
let targetWindow; |
||||
|
||||
before(() => { |
||||
return windows.create().then((win) => { |
||||
targetWindow = win; |
||||
}); |
||||
}); |
||||
|
||||
after(() => { |
||||
return windows.remove(targetWindow.id); |
||||
}); |
||||
|
||||
describe('press d', () => { |
||||
it('deletes tab', () => { |
||||
return tabs.create(targetWindow.id, SERVER_URL).then((tab) => { |
||||
return keys.press(tab.id, 'd'); |
||||
}).then(() => { |
||||
return windows.get(targetWindow.id); |
||||
}).then((after) => { |
||||
expect(after.tabs).to.have.lengthOf(1); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('press zd', () => { |
||||
it('duplicates tab', () => { |
||||
let targetTab = 0; |
||||
return tabs.create(targetWindow.id, SERVER_URL).then((tab) => { |
||||
targetTab = tab; |
||||
return keys.press(targetTab.id, 'z'); |
||||
}).then(() => { |
||||
return keys.press(targetTab.id, 'd'); |
||||
}).then(() => { |
||||
return windows.get(targetWindow.id); |
||||
}).then((after) => { |
||||
expect(after.tabs).to.have.lengthOf(3); |
||||
}); |
||||
}); |
||||
}) |
||||
}); |
@ -0,0 +1,10 @@ |
||||
'use strict'; |
||||
|
||||
window.__karma__.start = (function(start){ |
||||
return function(){ |
||||
var args = arguments |
||||
setTimeout(() => { |
||||
start(args) |
||||
}, 3000); |
||||
}; |
||||
}(window.__karma__.start)); |
@ -0,0 +1,53 @@ |
||||
'use strict' |
||||
|
||||
var fs = require('fs') |
||||
var path = require('path') |
||||
|
||||
var PREFS = { |
||||
'browser.shell.checkDefaultBrowser': 'false', |
||||
'browser.bookmarks.restore_default_bookmarks': 'false', |
||||
'dom.disable_open_during_load': 'false', |
||||
'dom.max_script_run_time': '0', |
||||
'dom.min_background_timeout_value': '10', |
||||
'extensions.autoDisableScopes': '0', |
||||
'extensions.enabledScopes': '15', |
||||
} |
||||
|
||||
var FirefoxWebExt = function (id, baseBrowserDecorator, args) { |
||||
baseBrowserDecorator(this) |
||||
|
||||
this._start = function (url) { |
||||
var self = this |
||||
var command = this._getCommand() |
||||
|
||||
let prefArgs = [].concat(...Object.keys(PREFS).map((key) => { |
||||
return ['--pref', key + '=' + PREFS[key]]; |
||||
})); |
||||
let sourceDirArgs = [].concat(...args.sourceDirs.map((dir) => { |
||||
return ['--source-dir', dir]; |
||||
})); |
||||
|
||||
self._execCommand( |
||||
command, |
||||
['run', '--start-url', url, '--no-input'].concat(sourceDirArgs, prefArgs) |
||||
) |
||||
} |
||||
} |
||||
|
||||
FirefoxWebExt.prototype = { |
||||
name: 'FirefoxWebExt', |
||||
|
||||
DEFAULT_CMD: { |
||||
linux: 'node_modules/web-ext/bin/web-ext', |
||||
darwin: 'node_modules/web-ext/bin/web-ext', |
||||
win32: 'node_modules/web-ext/bin/web-ext', |
||||
} |
||||
} |
||||
|
||||
FirefoxWebExt.$inject = ['id', 'baseBrowserDecorator', 'args'] |
||||
|
||||
// PUBLISH DI MODULE
|
||||
module.exports = { |
||||
'launcher:FirefoxWebExt': ['type', FirefoxWebExt], |
||||
} |
||||
|
@ -0,0 +1,45 @@ |
||||
module.exports = function (config) { |
||||
|
||||
config.set({ |
||||
basePath: '', |
||||
frameworks: ['mocha'], |
||||
files: [ |
||||
'karma-delay.js', |
||||
'**/*.test.js' |
||||
], |
||||
|
||||
preprocessors: { |
||||
'**/*.test.js': ['webpack'] |
||||
}, |
||||
|
||||
port: 9876, |
||||
colors: true, |
||||
logLevel: config.LOG_INFO, |
||||
|
||||
customLaunchers: { |
||||
FirefoxWebExtRunner: { |
||||
base: 'FirefoxWebExt', |
||||
sourceDirs: [ '.', 'e2e/ambassador'], |
||||
}, |
||||
}, |
||||
browsers: ['FirefoxWebExtRunner'], |
||||
sauceLabs: { |
||||
username: 'michael_jackson' |
||||
}, |
||||
|
||||
singleRun: true, |
||||
|
||||
webpackMiddleware: { |
||||
noInfo: true |
||||
}, |
||||
|
||||
reporters: ['mocha'], |
||||
|
||||
plugins: [ |
||||
require('./karma-webext-launcher'), |
||||
'karma-mocha', |
||||
'karma-webpack', |
||||
'karma-mocha-reporter', |
||||
], |
||||
}) |
||||
} |
@ -0,0 +1,14 @@ |
||||
var http = require('http'); |
||||
|
||||
const content = |
||||
'<!DOCTYPE html>' + |
||||
'<html lang="en">' + |
||||
'<body style="width:10000px; height:10000px">' + |
||||
'</body>' + |
||||
'</html">' ; |
||||
|
||||
|
||||
http.createServer(function (req, res) { |
||||
res.writeHead(200, {'Content-Type': 'text/html'}); |
||||
res.end(content); |
||||
}).listen(11111, '127.0.0.1'); |
File diff suppressed because it is too large
Load Diff
Reference in new issue