aboutsummaryrefslogtreecommitdiff
path: root/e2e
diff options
context:
space:
mode:
Diffstat (limited to 'e2e')
-rw-r--r--e2e/ambassador/manifest.json28
-rw-r--r--e2e/ambassador/src/background/index.js42
-rw-r--r--e2e/ambassador/src/background/ipc.js7
-rw-r--r--e2e/ambassador/src/background/tabs.js26
-rw-r--r--e2e/ambassador/src/client/ipc.js29
-rw-r--r--e2e/ambassador/src/client/keys.js31
-rw-r--r--e2e/ambassador/src/client/scrolls.js20
-rw-r--r--e2e/ambassador/src/client/tabs.js37
-rw-r--r--e2e/ambassador/src/client/windows.js27
-rw-r--r--e2e/ambassador/src/content/events.js31
-rw-r--r--e2e/ambassador/src/content/index.js30
-rw-r--r--e2e/ambassador/src/content/ipc.js40
-rw-r--r--e2e/ambassador/src/content/scrolls.js20
-rw-r--r--e2e/ambassador/src/shared/messages.js34
-rw-r--r--e2e/ambassador/webpack.config.js24
-rw-r--r--e2e/contents/scroll.test.js151
-rw-r--r--e2e/contents/tab.test.js216
-rw-r--r--e2e/contents/zoom.test.js72
-rw-r--r--e2e/karma-delay.js10
-rw-r--r--e2e/karma-webext-launcher.js53
-rw-r--r--e2e/karma.conf.js51
-rw-r--r--e2e/web-server/index.js14
22 files changed, 993 insertions, 0 deletions
diff --git a/e2e/ambassador/manifest.json b/e2e/ambassador/manifest.json
new file mode 100644
index 0000000..d2253f6
--- /dev/null
+++ b/e2e/ambassador/manifest.json
@@ -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"
+ ]
+}
diff --git a/e2e/ambassador/src/background/index.js b/e2e/ambassador/src/background/index.js
new file mode 100644
index 0000000..db2deb3
--- /dev/null
+++ b/e2e/ambassador/src/background/index.js
@@ -0,0 +1,42 @@
+import {
+ WINDOWS_CREATE, WINDOWS_REMOVE, WINDOWS_GET,
+ TABS_CREATE, TABS_SELECT_AT, TABS_GET_ZOOM, TABS_SET_ZOOM,
+ EVENT_KEYPRESS, EVENT_KEYDOWN, EVENT_KEYUP,
+ SCROLL_GET, SCROLL_SET,
+} 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,
+ });
+ case TABS_SELECT_AT:
+ return tabs.selectAt({
+ windowId: message.windowId,
+ index: message.index,
+ });
+ case TABS_GET_ZOOM:
+ return browser.tabs.getZoom(message.tabId);
+ case TABS_SET_ZOOM:
+ return browser.tabs.setZoom(message.tabId, message.factor);
+ case EVENT_KEYPRESS:
+ case EVENT_KEYDOWN:
+ case EVENT_KEYUP:
+ case SCROLL_GET:
+ case SCROLL_SET:
+ return browser.tabs.sendMessage(
+ message.tabId,
+ message
+ );
+ }
+});
diff --git a/e2e/ambassador/src/background/ipc.js b/e2e/ambassador/src/background/ipc.js
new file mode 100644
index 0000000..95d2164
--- /dev/null
+++ b/e2e/ambassador/src/background/ipc.js
@@ -0,0 +1,7 @@
+const receiveContentMessage = (func) => {
+ browser.runtime.onMessage.addListener((message) => {
+ return func(message);
+ });
+};
+
+export { receiveContentMessage };
diff --git a/e2e/ambassador/src/background/tabs.js b/e2e/ambassador/src/background/tabs.js
new file mode 100644
index 0000000..d049500
--- /dev/null
+++ b/e2e/ambassador/src/background/tabs.js
@@ -0,0 +1,26 @@
+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);
+ });
+ });
+};
+
+const selectAt = (props = {}) => {
+ return browser.tabs.query({ windowId: props.windowId }).then((tabs) => {
+ let target = tabs[props.index];
+ return browser.tabs.update(target.id, { active: true });
+ });
+};
+
+
+export {
+ create, selectAt
+};
diff --git a/e2e/ambassador/src/client/ipc.js b/e2e/ambassador/src/client/ipc.js
new file mode 100644
index 0000000..9f232ea
--- /dev/null
+++ b/e2e/ambassador/src/client/ipc.js
@@ -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 };
diff --git a/e2e/ambassador/src/client/keys.js b/e2e/ambassador/src/client/keys.js
new file mode 100644
index 0000000..37b9c0a
--- /dev/null
+++ b/e2e/ambassador/src/client/keys.js
@@ -0,0 +1,31 @@
+import { EVENT_KEYPRESS, EVENT_KEYDOWN, EVENT_KEYUP } from '../shared/messages';
+import * as ipc from './ipc';
+
+const NEUTRAL_MODIFIERS = { shiftKey: false, altKey: false, ctrlKey: false };
+
+const press = (tabId, key, modifiers = NEUTRAL_MODIFIERS) => {
+ return ipc.send(Object.assign({}, modifiers, {
+ type: EVENT_KEYPRESS,
+ tabId,
+ key,
+ }));
+};
+
+const down = (tabId, key, modifiers = NEUTRAL_MODIFIERS) => {
+ return ipc.send(Object.assign({}, modifiers, {
+ type: EVENT_KEYDOWN,
+ tabId,
+ key,
+ }));
+};
+
+
+const up = (tabId, key, modifiers = NEUTRAL_MODIFIERS) => {
+ return ipc.send(Object.assign({}, modifiers, {
+ type: EVENT_KEYUP,
+ tabId,
+ key,
+ }));
+};
+
+export { press, down, up };
diff --git a/e2e/ambassador/src/client/scrolls.js b/e2e/ambassador/src/client/scrolls.js
new file mode 100644
index 0000000..f8f82e9
--- /dev/null
+++ b/e2e/ambassador/src/client/scrolls.js
@@ -0,0 +1,20 @@
+import { SCROLL_GET, SCROLL_SET } from '../shared/messages';
+import * as ipc from './ipc';
+
+const get = (tabId) => {
+ return ipc.send({
+ type: SCROLL_GET,
+ tabId,
+ });
+};
+
+const set = (tabId, x, y) => {
+ return ipc.send({
+ type: SCROLL_SET,
+ tabId,
+ x,
+ y,
+ });
+};
+
+export { get, set };
diff --git a/e2e/ambassador/src/client/tabs.js b/e2e/ambassador/src/client/tabs.js
new file mode 100644
index 0000000..c7b1340
--- /dev/null
+++ b/e2e/ambassador/src/client/tabs.js
@@ -0,0 +1,37 @@
+import {
+ TABS_CREATE, TABS_SELECT_AT, TABS_GET_ZOOM, TABS_SET_ZOOM,
+} from '../shared/messages';
+import * as ipc from './ipc';
+
+const create = (windowId, url) => {
+ return ipc.send({
+ type: TABS_CREATE,
+ windowId,
+ url,
+ });
+};
+
+const selectAt = (windowId, index) => {
+ return ipc.send({
+ type: TABS_SELECT_AT,
+ windowId,
+ index,
+ });
+};
+
+const getZoom = (tabId) => {
+ return ipc.send({
+ tabId,
+ type: TABS_GET_ZOOM,
+ });
+};
+
+const setZoom = (tabId, factor) => {
+ return ipc.send({
+ type: TABS_SET_ZOOM,
+ tabId,
+ factor,
+ });
+};
+
+export { create, selectAt, getZoom, setZoom };
diff --git a/e2e/ambassador/src/client/windows.js b/e2e/ambassador/src/client/windows.js
new file mode 100644
index 0000000..f92405a
--- /dev/null
+++ b/e2e/ambassador/src/client/windows.js
@@ -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 };
diff --git a/e2e/ambassador/src/content/events.js b/e2e/ambassador/src/content/events.js
new file mode 100644
index 0000000..1e45909
--- /dev/null
+++ b/e2e/ambassador/src/content/events.js
@@ -0,0 +1,31 @@
+const keypress = (opts) => {
+ let event = new KeyboardEvent('keypress', {
+ key: opts.key,
+ altKey: opts.altKey,
+ shiftKey: opts.shiftKey,
+ ctrlKey: opts.ctrlKey
+ });
+ document.body.dispatchEvent(event);
+};
+
+const keydown = (opts) => {
+ let event = new KeyboardEvent('keydown', {
+ key: opts.key,
+ altKey: opts.altKey,
+ shiftKey: opts.shiftKey,
+ ctrlKey: opts.ctrlKey
+ });
+ document.body.dispatchEvent(event);
+};
+
+const keyup = (opts) => {
+ let event = new KeyboardEvent('keyup', {
+ key: opts.key,
+ altKey: opts.altKey,
+ shiftKey: opts.shiftKey,
+ ctrlKey: opts.ctrlKey
+ });
+ document.body.dispatchEvent(event);
+};
+
+export { keypress, keydown, keyup };
diff --git a/e2e/ambassador/src/content/index.js b/e2e/ambassador/src/content/index.js
new file mode 100644
index 0000000..fd19136
--- /dev/null
+++ b/e2e/ambassador/src/content/index.js
@@ -0,0 +1,30 @@
+import {
+ EVENT_KEYPRESS, EVENT_KEYDOWN, EVENT_KEYUP,
+ SCROLL_GET, SCROLL_SET,
+} from '../shared/messages';
+import * as ipc from './ipc';
+import * as events from './events';
+import * as scrolls from './scrolls';
+
+ipc.receivePageMessage((message) => {
+ return ipc.sendToBackground(message);
+});
+
+ipc.receiveBackgroundMesssage((message) => {
+ switch (message.type) {
+ case EVENT_KEYPRESS:
+ events.keypress(message);
+ break;
+ case EVENT_KEYDOWN:
+ events.keydown(message);
+ break;
+ case EVENT_KEYUP:
+ events.keyup(message);
+ break;
+ case SCROLL_GET:
+ return Promise.resolve(scrolls.get());
+ case SCROLL_SET:
+ return Promise.resolve(scrolls.set(message.x, message.y));
+ }
+ return Promise.resolve({});
+});
diff --git a/e2e/ambassador/src/content/ipc.js b/e2e/ambassador/src/content/ipc.js
new file mode 100644
index 0000000..917623c
--- /dev/null
+++ b/e2e/ambassador/src/content/ipc.js
@@ -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,
+};
diff --git a/e2e/ambassador/src/content/scrolls.js b/e2e/ambassador/src/content/scrolls.js
new file mode 100644
index 0000000..4227cf7
--- /dev/null
+++ b/e2e/ambassador/src/content/scrolls.js
@@ -0,0 +1,20 @@
+const get = () => {
+ let element = document.documentElement;
+ return {
+ xMax: element.scrollWidth - element.clientWidth,
+ yMax: element.scrollHeight - element.clientHeight,
+ x: element.scrollLeft,
+ y: element.scrollTop,
+ frameWidth: element.clientWidth,
+ frameHeight: element.clientHeight,
+ };
+};
+
+const set = (x, y) => {
+ let element = document.documentElement;
+ element.scrollLeft = x;
+ element.scrollTop = y;
+ return get();
+};
+
+export { get, set };
diff --git a/e2e/ambassador/src/shared/messages.js b/e2e/ambassador/src/shared/messages.js
new file mode 100644
index 0000000..1fc47d2
--- /dev/null
+++ b/e2e/ambassador/src/shared/messages.js
@@ -0,0 +1,34 @@
+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 TABS_SELECT_AT = 'tabs.selectAt';
+const TABS_GET_ZOOM = 'tabs.get.zoom';
+const TABS_SET_ZOOM = 'tabs.set.zoom';
+const EVENT_KEYPRESS = 'event.keypress';
+const EVENT_KEYDOWN = 'event.keydown';
+const EVENT_KEYUP = 'event.keyup';
+const SCROLL_GET = 'scroll.get';
+const SCROLL_SET = 'scroll.set';
+
+export {
+ METHOD_REQUEST,
+ METHOD_RESPONSE,
+
+ WINDOWS_CREATE,
+ WINDOWS_REMOVE,
+ WINDOWS_GET,
+
+ TABS_CREATE,
+ TABS_SELECT_AT,
+ TABS_GET_ZOOM,
+ TABS_SET_ZOOM,
+
+ EVENT_KEYPRESS,
+ EVENT_KEYDOWN,
+ EVENT_KEYUP,
+ SCROLL_GET,
+ SCROLL_SET,
+};
diff --git a/e2e/ambassador/webpack.config.js b/e2e/ambassador/webpack.config.js
new file mode 100644
index 0000000..d292317
--- /dev/null
+++ b/e2e/ambassador/webpack.config.js
@@ -0,0 +1,24 @@
+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'
+ },
+
+ resolve: {
+ extensions: [ '.js' ],
+ modules: [path.join(__dirname, 'src'), 'node_modules']
+ }
+};
+
+module.exports = config
+
diff --git a/e2e/contents/scroll.test.js b/e2e/contents/scroll.test.js
new file mode 100644
index 0000000..070529a
--- /dev/null
+++ b/e2e/contents/scroll.test.js
@@ -0,0 +1,151 @@
+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";
+import * as scrolls from "../ambassador/src/client/scrolls";
+
+const SERVER_URL = "localhost:11111";
+
+describe("scroll test", () => {
+ let targetWindow;
+ let targetTab;
+
+ before(() => {
+ return windows.create().then((win) => {
+ targetWindow = win;
+ return tabs.create(targetWindow.id, SERVER_URL);
+ }).then((tab) => {
+ targetTab = tab;
+ });
+ });
+
+ after(() => {
+ return windows.remove(targetWindow.id);
+ });
+
+ it('scrolls up by k', () => {
+ let before
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'k');
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.be.lessThan(before.y);
+ });
+ });
+
+ it('scrolls down by j', () => {
+ let before
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'j');
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.be.greaterThan(before.y);
+ });
+ });
+
+ it('scrolls left by h', () => {
+ let before
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'h');
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.x).to.be.lessThan(before.x);
+ });
+ });
+
+ it('scrolls top by gg', () => {
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ return keys.press(targetTab.id, 'g');
+ }).then(() => {
+ return keys.press(targetTab.id, 'g');
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.be.equals(0);
+ });
+ });
+
+ it('scrolls bottom by G', () => {
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ return keys.press(targetTab.id, 'G', { shiftKey: true });
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.be.equals(actual.yMax);
+ });
+ });
+
+ it('scrolls bottom by 0', () => {
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ return keys.press(targetTab.id, '0');
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.x).to.be.equals(0);
+ });
+ });
+
+ it('scrolls bottom by $', () => {
+ return scrolls.set(targetTab.id, 100, 100).then((scroll) => {
+ return keys.press(targetTab.id, '$');
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.x).to.be.equals(actual.xMax);
+ });
+ });
+
+ it('scrolls bottom by <C-U>', () => {
+ let before
+ return scrolls.set(targetTab.id, 5000, 5000).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'u', { ctrlKey: true });
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.closeTo(before.y - before.frameHeight / 2, 1);
+ });
+ });
+
+ it('scrolls bottom by <C-D>', () => {
+ let before
+ return scrolls.set(targetTab.id, 5000, 5000).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'd', { ctrlKey: true });
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.closeTo(before.y + before.frameHeight / 2, 1);
+ });
+ });
+
+ it('scrolls bottom by <C-B>', () => {
+ let before
+ return scrolls.set(targetTab.id, 5000, 5000).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'b', { ctrlKey: true });
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.equals(before.y - before.frameHeight);
+ });
+ });
+
+ it('scrolls bottom by <C-F>', () => {
+ let before
+ return scrolls.set(targetTab.id, 5000, 5000).then((scroll) => {
+ before = scroll;
+ return keys.press(targetTab.id, 'f', { ctrlKey: true });
+ }).then(() => {
+ return scrolls.get(targetTab.id);
+ }).then((actual) => {
+ expect(actual.y).to.equals(before.y + before.frameHeight);
+ });
+ });
+});
diff --git a/e2e/contents/tab.test.js b/e2e/contents/tab.test.js
new file mode 100644
index 0000000..4374907
--- /dev/null
+++ b/e2e/contents/tab.test.js
@@ -0,0 +1,216 @@
+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;
+
+ beforeEach(() => {
+ return windows.create(SERVER_URL).then((win) => {
+ targetWindow = win;
+ });
+ });
+
+ afterEach(() => {
+ return windows.remove(targetWindow.id);
+ });
+
+ it('deletes tab by d', () => {
+ let before;
+ let targetTab;
+ return tabs.create(targetWindow.id, SERVER_URL).then((tab) => {
+ targetTab = tab;
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ before = win;
+ return keys.press(targetTab.id, 'd');
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((actual) => {
+ expect(actual.tabs).to.have.lengthOf(before.tabs.length - 1);
+ });
+ });
+
+ it('duplicates tab by zd', () => {
+ let before;
+ let targetTab;
+ return tabs.create(targetWindow.id, SERVER_URL).then((tab) => {
+ targetTab = tab;
+ return windows.get(targetWindow.id)
+ }).then((win) => {;
+ before = win;
+ return keys.press(targetTab.id, 'z');
+ }).then(() => {
+ return keys.press(targetTab.id, 'd');
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((actual) => {
+ expect(actual.tabs).to.have.lengthOf(before.tabs.length + 1);
+ });
+ })
+
+ it('makes pinned by zp', () => {
+ let before;
+ let targetTab;
+ return tabs.create(targetWindow.id, SERVER_URL).then((tab) => {
+ targetTab = tab;
+ return windows.get(targetWindow.id)
+ }).then((win) => {;
+ before = win;
+ return keys.press(targetTab.id, 'z');
+ }).then(() => {
+ return keys.press(targetTab.id, 'p');
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((actual) => {
+ expect(actual.tabs[0].pinned).to.be.true;
+ });
+ })
+
+ it('selects previous tab by K', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 2);
+ }).then((tab) => {
+ return keys.press(tab.id, 'K', { shiftKey: true });
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[1].active).to.be.true;
+ });
+ });
+
+ it('selects previous tab by K rotatory', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 0);
+ }).then((tab) => {
+ return keys.press(tab.id, 'K', { shiftKey: true });
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[3].active).to.be.true;
+ });
+ });
+
+ it('selects next tab by J', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 2);
+ }).then((tab) => {
+ return keys.press(tab.id, 'J', { shiftKey: true });
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[3].active).to.be.true;
+ });
+ });
+
+ it('selects previous tab by J rotatory', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 3);
+ }).then((tab) => {
+ return keys.press(tab.id, 'J', { shiftKey: true });
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[0].active).to.be.true;
+ });
+ });
+
+ it('selects first tab by g0', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 2);
+ }).then((tab) => {
+ return keys.press(tab.id, 'g').then(() => tab);
+ }).then((tab) => {
+ return keys.press(tab.id, '0');
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[0].active).to.be.true;
+ });
+ });
+
+ it('selects last tab by g$', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 2);
+ }).then((tab) => {
+ return keys.press(tab.id, 'g').then(() => tab);
+ }).then((tab) => {
+ return keys.press(tab.id, '$');
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[3].active).to.be.true;
+ });
+ });
+
+ it('selects last selected tab by <C-6>', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#2')
+ }).then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#3');
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 1);
+ }).then(() => {
+ return tabs.selectAt(targetWindow.id, 3);
+ }).then((tab) => {
+ return keys.press(tab.id, '6', { ctrlKey: true });
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs[1].active).to.be.true;
+ });
+ });
+
+ it('deletes tab by d', () => {
+ return Promise.resolve().then(() => {
+ return tabs.create(targetWindow.id, SERVER_URL + '#1');
+ }).then((tab) => {
+ return keys.press(tab.id, 'd');
+ }).then(() => {
+ return windows.get(targetWindow.id);
+ }).then((win) => {
+ expect(win.tabs).to.have.lengthOf(1);
+ });
+ });
+});
diff --git a/e2e/contents/zoom.test.js b/e2e/contents/zoom.test.js
new file mode 100644
index 0000000..603e0b6
--- /dev/null
+++ b/e2e/contents/zoom.test.js
@@ -0,0 +1,72 @@
+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("zoom test", () => {
+ let targetWindow;
+ let targetTab;
+
+ before(() => {
+ return windows.create(SERVER_URL).then((win) => {
+ targetWindow = win;
+ });
+ });
+
+ after(() => {
+ return windows.remove(targetWindow.id);
+ });
+
+ beforeEach(() => {
+ return tabs.create(targetWindow.id, SERVER_URL).then((tab) => {
+ targetTab = tab;
+ });
+ });
+
+ it('zooms-in by zi', () => {
+ let before;
+ return tabs.getZoom(targetTab.id).then((zoom) => {
+ before = zoom;
+ return keys.press(targetTab.id, 'z');
+ }).then(() => {
+ return keys.press(targetTab.id, 'i');
+ }).then(() => {
+ return tabs.getZoom(targetTab.id);
+ }).then((actual) => {
+ expect(actual).to.be.greaterThan(before);
+ });
+ });
+
+ it('zooms-in by zo', () => {
+ let before;
+ return tabs.getZoom(targetTab.id).then((zoom) => {
+ before = zoom;
+ return keys.press(targetTab.id, 'z');
+ }).then(() => {
+ return keys.press(targetTab.id, 'o');
+ }).then(() => {
+ return tabs.getZoom(targetTab.id);
+ }).then((actual) => {
+ expect(actual).to.be.lessThan(before);
+ });
+ });
+
+ it('zooms-in by zz', () => {
+ let before;
+ tabs.setZoom(targetTab.id, 1.5).then(() => {
+ return tabs.getZoom(targetTab.id);
+ }).then((zoom) => {
+ before = zoom;
+ return keys.press(targetTab.id, 'z');
+ }).then(() => {
+ return keys.press(targetTab.id, 'z');
+ }).then(() => {
+ return tabs.getZoom(targetTab.id);
+ }).then((actual) => {
+ expect(actual).to.be.lessThan(before);
+ expect(actual).to.be.be(1);
+ });
+ });
+});
diff --git a/e2e/karma-delay.js b/e2e/karma-delay.js
new file mode 100644
index 0000000..7d18c4a
--- /dev/null
+++ b/e2e/karma-delay.js
@@ -0,0 +1,10 @@
+'use strict';
+
+window.__karma__.start = (function(start){
+return function(){
+ var args = arguments
+ setTimeout(() => {
+ start(args)
+ }, 3000);
+};
+}(window.__karma__.start));
diff --git a/e2e/karma-webext-launcher.js b/e2e/karma-webext-launcher.js
new file mode 100644
index 0000000..e0a3e42
--- /dev/null
+++ b/e2e/karma-webext-launcher.js
@@ -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],
+}
+
diff --git a/e2e/karma.conf.js b/e2e/karma.conf.js
new file mode 100644
index 0000000..5ef4646
--- /dev/null
+++ b/e2e/karma.conf.js
@@ -0,0 +1,51 @@
+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',
+ ],
+
+ client: {
+ mocha: {
+ timeout: 5000
+ }
+ }
+ })
+}
diff --git a/e2e/web-server/index.js b/e2e/web-server/index.js
new file mode 100644
index 0000000..81e11c1
--- /dev/null
+++ b/e2e/web-server/index.js
@@ -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');