diff options
64 files changed, 3904 insertions, 3983 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 1294557..342842d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -63,6 +63,13 @@ jobs: - checkout - setup_npm - run: npm run lint + - run: + # NOTE: Karma loads ts-node automatically and treats karma.conf.js as a TypeScript. + # Karma does not starts by karma.conf.js transpile failure, and this hack removes + # ts-node module from the local before test. + # See: https://github.com/karma-runner/karma/issues/3329 + name: Remove node-ts from node_modules + command: mv node_modules/ts-node node_modules/ts-node.orig - run: npm test - run: npm run package diff --git a/e2e/blacklist.test.js b/e2e/blacklist.test.js deleted file mode 100644 index fa8e8db..0000000 --- a/e2e/blacklist.test.js +++ /dev/null @@ -1,77 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const settings = require('./settings'); - -const newApp = () => { - let app = express(); - app.get('/*', (req, res) => { - res.status(200).send(`<!DOCTYPEhtml> -<html lang="en"> - <body style="width:10000px; height:10000px"></body> -</html>`); - }); - return app; -}; - -describe("navigate test", () => { - - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - it('should disable add-on if the URL is in the blacklist', async () => { - await browser.storage.local.set({ - settings: { - source: 'json', - json: `{ - "keymaps": { - "j": { "type": "scroll.vertically", "count": 1 } - }, - "blacklist": [ "127.0.0.1:${port}/a" ] - }`, - }, - }); - - await session.navigateTo(`http://127.0.0.1:${port}/a`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('j'); - - // not works - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 0); - - await session.navigateTo(`http://127.0.0.1:${port}/ab`); - body = await session.findElementByCSS('body'); - await body.sendKeys('j'); - - // works - pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 64); - }); -}); - diff --git a/e2e/blacklist.test.ts b/e2e/blacklist.test.ts new file mode 100644 index 0000000..8bf1bd8 --- /dev/null +++ b/e2e/blacklist.test.ts @@ -0,0 +1,62 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("blacklist test", () => { + let server = new TestServer().receiveContent('/*', + `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html">`, + ); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + + let url = server.url('/a').replace('http://', ''); + await browser.storage.local.set({ + settings: { + source: 'json', + json: `{ + "keymaps": { + "j": { "type": "scroll.vertically", "count": 1 } + }, + "blacklist": [ "${url}" ] + }`, + }, + }); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + it('should disable add-on if the URL is in the blacklist', async () => { + let page = await Page.navigateTo(webdriver, server.url('/a')); + await page.sendKeys('j') + + let scrollY = await page.getScrollY(); + assert.strictEqual(scrollY, 0); + }); + + it('should enabled add-on if the URL is not in the blacklist', async () => { + let page = await Page.navigateTo(webdriver, server.url('/ab')); + await page.sendKeys('j'); + + let scrollY = await page.getScrollY(); + assert.strictEqual(scrollY, 64); + }); +}); diff --git a/e2e/clipboard.test.js b/e2e/clipboard.test.js deleted file mode 100644 index 82e45fc..0000000 --- a/e2e/clipboard.test.js +++ /dev/null @@ -1,123 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const clipboard = require('./lib/clipboard'); -const settings = require('./settings'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.status(200).send(`<html lang="en"></html">`); - }); - return app; -}; - -describe("navigate test", () => { - - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - }); - session = firefox.session; - browser = firefox.browser; - - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - }) - - it('should copy current URL by y', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/#should_copy_url`); - let body = await session.findElementByCSS('body'); - - await body.sendKeys('y'); - await eventually(async() => { - let data = await clipboard.read(); - assert.equal(data, `http://127.0.0.1:${port}/#should_copy_url`); - }); - }); - - it('should open an URL from clipboard by p', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - let body = await session.findElementByCSS('body'); - - await clipboard.write(`http://127.0.0.1:${port}/#open_from_clipboard`); - await body.sendKeys('p'); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].url, `http://127.0.0.1:${port}/#open_from_clipboard`); - }); - }); - - it('should open an URL from clipboard to new tab by P', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - let body = await session.findElementByCSS('body'); - - await clipboard.write(`http://127.0.0.1:${port}/#open_to_new_tab`); - await body.sendKeys(Key.Shift, 'p'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.deepEqual(tabs.map(t => t.url), [ - `http://127.0.0.1:${port}/`, - `http://127.0.0.1:${port}/#open_to_new_tab`, - ]); - }); - }); - - it('should open search result with keywords in clipboard by p', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - let body = await session.findElementByCSS('body'); - - await clipboard.write(`an apple`); - await body.sendKeys('p'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs[0].url, `http://127.0.0.1:${port}/google?q=an%20apple`); - }); - }); - - it('should open search result with keywords in clipboard to new tabby P', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - let body = await session.findElementByCSS('body'); - - await clipboard.write(`an apple`); - await body.sendKeys(Key.Shift, 'p'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.deepEqual(tabs.map(t => t.url), [ - `http://127.0.0.1:${port}/`, - `http://127.0.0.1:${port}/google?q=an%20apple`, - ]); - }); - }); -}); diff --git a/e2e/clipboard.test.ts b/e2e/clipboard.test.ts new file mode 100644 index 0000000..2b71ade --- /dev/null +++ b/e2e/clipboard.test.ts @@ -0,0 +1,110 @@ +import * as assert from 'assert'; +import * as path from 'path'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import * as clipboard from './lib/clipboard'; +import settings from './settings'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("clipboard test", () => { + let server = new TestServer(12321).receiveContent('/happy', 'ok'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + }) + + it('should copy current URL by y', async () => { + let page = await Page.navigateTo(webdriver, server.url('/#should_copy_url')); + await page.sendKeys('y'); + + await eventually(async() => { + let data = await clipboard.read(); + assert.strictEqual(data, server.url('/#should_copy_url')); + }); + }); + + it('should open an URL from clipboard by p', async () => { + await clipboard.write(server.url('/#open_from_clipboard')); + + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys('p'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].url, server.url('/#open_from_clipboard')); + }); + }); + + it('should open an URL from clipboard to new tab by P', async () => { + await clipboard.write(server.url('/#open_to_new_tab')); + + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys(Key.SHIFT, 'p'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.deepStrictEqual(tabs.map((t: any) => t.url), [ + server.url(), + server.url('/#open_to_new_tab'), + ]); + }); + }); + + it('should open search result with keywords in clipboard by p', async () => { + await clipboard.write(`an apple`); + + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys(Key.SHIFT, 'p'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].url, server.url('/google?q=an%20apple')); + }); + }); + + it('should open search result with keywords in clipboard to new tabby P', async () => { + await clipboard.write(`an apple`); + + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys(Key.SHIFT, 'p'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.deepStrictEqual(tabs.map((t: any) => t.url), [ + server.url(), + server.url('/google?q=an%20apple'), + ]); + }); + }); +}); diff --git a/e2e/command_addbookmark.test.js b/e2e/command_addbookmark.test.js deleted file mode 100644 index e8995bc..0000000 --- a/e2e/command_addbookmark.test.js +++ /dev/null @@ -1,67 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/happy', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <head> - <title>how to be happy</title> - </head> -</html">`); - }); - return app; -}; - -describe('addbookmark command test', () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}/happy`); - }); - - it('should add a bookmark from the current page', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('addbookmark how to be happy', Key.Enter); - - await eventually(async() => { - var bookmarks = await browser.bookmarks.search({ title: 'how to be happy' }); - assert.equal(bookmarks.length, 1); - assert.equal(bookmarks[0].url, `http://127.0.0.1:${port}/happy`); - }); - }); -}); diff --git a/e2e/command_addbookmark.test.ts b/e2e/command_addbookmark.test.ts new file mode 100644 index 0000000..bcc75ac --- /dev/null +++ b/e2e/command_addbookmark.test.ts @@ -0,0 +1,51 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe('addbookmark command test', () => { + let server = new TestServer().receiveContent('/happy', ` + <!DOCTYPE html> + <html lang="en"><head><title>how to be happy</title></head></html">`, + ); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + await webdriver.navigate().to(server.url('/happy')); + }); + + it('should add a bookmark from the current page', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('addbookmark how to be happy'); + + await eventually(async() => { + var bookmarks = await browser.bookmarks.search({ title: 'how to be happy' }); + assert.strictEqual(bookmarks.length, 1); + assert.strictEqual(bookmarks[0].url, server.url('/happy')); + }); + }); +}); diff --git a/e2e/command_bdelete.test.js b/e2e/command_bdelete.test.js deleted file mode 100644 index 1f416db..0000000 --- a/e2e/command_bdelete.test.js +++ /dev/null @@ -1,203 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/*', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <head> - <title>my_${req.path.slice(1)}</title> - </head> - <body><h1>${req.path}</h1></body> -</html">`); - }); - return app; -}; - -describe('bdelete/bdeletes command test', () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - await browser.tabs.update(tabs[0].id, { url: `http://127.0.0.1:${port}/site1`, pinned: true }); - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site2`, pinned: true }) - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site3`, pinned: true }) - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site4` }) - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site5` }) - - await eventually(async() => { - let handles = await session.getWindowHandles(); - assert.equal(handles.length, 5); - await session.switchToWindow(handles[2]); - await session.findElementByCSS('iframe'); - }); - - await new Promise((resolve) => setTimeout(resolve, 100)); - }); - - it('should delete an unpinned tab by bdelete command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdelete site5', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.deepEqual(tabs.map(t => t.url), [ - `http://127.0.0.1:${port}/site1`, - `http://127.0.0.1:${port}/site2`, - `http://127.0.0.1:${port}/site3`, - `http://127.0.0.1:${port}/site4`, - ]) - }); - }); - - it('should not delete an pinned tab by bdelete command by bdelete command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdelete site1', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 5); - }); - }); - - it('should show an error when no tabs are matched by bdelete command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdelete xyz', Key.Enter); - - await eventually(async() => { - let p = await session.findElementByCSS('.vimvixen-console-error'); - let text = await p.getText(); - assert.equal(text, 'No matching buffer for xyz'); - }); - }); - - it('should show an error when more than one tabs are matched by bdelete command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdelete site', Key.Enter); - - await eventually(async() => { - let p = await session.findElementByCSS('.vimvixen-console-error'); - let text = await p.getText(); - assert.equal(text, 'More than one match for site'); - }); - }); - - it('should delete an unpinned tab by bdelete! command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdelete! site5', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.deepEqual(tabs.map(t => t.url), [ - `http://127.0.0.1:${port}/site1`, - `http://127.0.0.1:${port}/site2`, - `http://127.0.0.1:${port}/site3`, - `http://127.0.0.1:${port}/site4`, - ]) - }); - }); - - it('should delete an pinned tab by bdelete! command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdelete! site1', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.deepEqual(tabs.map(t => t.url), [ - `http://127.0.0.1:${port}/site2`, - `http://127.0.0.1:${port}/site3`, - `http://127.0.0.1:${port}/site4`, - `http://127.0.0.1:${port}/site5`, - ]) - }); - }); - - it('should delete unpinned tabs by bdeletes command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdeletes site', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.deepEqual(tabs.map(t => t.url), [ - `http://127.0.0.1:${port}/site1`, - `http://127.0.0.1:${port}/site2`, - `http://127.0.0.1:${port}/site3`, - ]) - }); - }); - - it('should delete both pinned and unpinned tabs by bdeletes! command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('bdeletes! site', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 1); - }); - }); -}); diff --git a/e2e/command_bdelete.test.ts b/e2e/command_bdelete.test.ts new file mode 100644 index 0000000..c96034d --- /dev/null +++ b/e2e/command_bdelete.test.ts @@ -0,0 +1,157 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe('bdelete/bdeletes command test', () => { + let server = new TestServer().receiveContent('/*', 'ok'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + await browser.tabs.update(tabs[0].id, { url: server.url('/site1'), pinned: true }); + await browser.tabs.create({ url: server.url('/site2'), pinned: true }) + await browser.tabs.create({ url: server.url('/site3'), pinned: true }) + await browser.tabs.create({ url: server.url('/site4'), }) + await browser.tabs.create({ url: server.url('/site5'), }) + + await eventually(async() => { + let handles = await webdriver.getAllWindowHandles(); + assert.strictEqual(handles.length, 5); + await webdriver.switchTo().window(handles[2]); + }); + }); + + it('should delete an unpinned tab by bdelete command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdelete site5'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.deepStrictEqual(tabs.map((t: any) => t.url), [ + server.url('/site1'), + server.url('/site2'), + server.url('/site3'), + server.url('/site4'), + ]) + }); + }); + + it('should not delete an pinned tab by bdelete command by bdelete command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdelete site1'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 5); + }); + }); + + it('should show an error when no tabs are matched by bdelete command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdelete xyz'); + + await eventually(async() => { + let text = await console.getErrorMessage(); + assert.strictEqual(text, 'No matching buffer for xyz'); + }); + }); + + it('should show an error when more than one tabs are matched by bdelete command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdelete site'); + + await eventually(async() => { + let text = await console.getErrorMessage(); + assert.strictEqual(text, 'More than one match for site'); + }); + }); + + it('should delete an unpinned tab by bdelete! command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdelete! site5'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.deepStrictEqual(tabs.map((t: any) => t.url), [ + server.url('/site1'), + server.url('/site2'), + server.url('/site3'), + server.url('/site4'), + ]) + }); + }); + + it('should delete an pinned tab by bdelete! command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdelete! site1'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.deepStrictEqual(tabs.map((t: any) => t.url), [ + server.url('/site2'), + server.url('/site3'), + server.url('/site4'), + server.url('/site5'), + ]) + }); + }); + + it('should delete unpinned tabs by bdeletes command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdeletes site'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.deepStrictEqual(tabs.map((t: any) => t.url), [ + server.url('/site1'), + server.url('/site2'), + server.url('/site3'), + ]) + }); + }); + + it('should delete both pinned and unpinned tabs by bdeletes! command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('bdeletes! site'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 1); + }); + }); +}); diff --git a/e2e/command_buffer.test.js b/e2e/command_buffer.test.js deleted file mode 100644 index bf94428..0000000 --- a/e2e/command_buffer.test.js +++ /dev/null @@ -1,202 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/*', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <head> - <title>my_${req.path.slice(1)}</title> - </head> - <body><h1>${req.path}</h1></body> -</html">`); - }); - return app; -}; - -describe('buffer command test', () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - await browser.tabs.update(tabs[0].id, { url: `http://127.0.0.1:${port}/site1` }); - for (let i = 2; i <= 5; ++i) { - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site${i}`}) - } - - await eventually(async() => { - let handles = await session.getWindowHandles(); - assert.equal(handles.length, 5); - await session.switchToWindow(handles[2]); - await session.findElementByCSS('iframe'); - }); - - await new Promise((resolve) => setTimeout(resolve, 100)); - }); - - it('should do nothing by buffer command with no parameters', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 2); - }); - }); - - it('should select a tab by buffer command with a number', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 2); - }); - }); - - it('should should an out of range error by buffer commands', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer 0', Key.Enter); - - await eventually(async() => { - let p = await session.findElementByCSS('.vimvixen-console-error'); - let text = await p.getText(); - assert.equal(text, 'tab 0 does not exist'); - }); - - await session.switchToParentFrame(); - body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - input = await session.findElementByCSS('input'); - await input.sendKeys('buffer 9', Key.Enter); - - await eventually(async() => { - let p = await session.findElementByCSS('.vimvixen-console-error'); - let text = await p.getText(); - assert.equal(text, 'tab 9 does not exist'); - }); - }); - - it('should select a tab by buffer command with a title', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer my_site1', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 0); - }); - }); - - it('should select a tab by buffer command with an URL', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer /site1', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 0); - }); - }); - - it('should select tabs rotately', async() => { - let handles = await session.getWindowHandles(); - await session.switchToWindow(handles[4]); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer site', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 0); - }); - }); - - it('should do nothing by ":buffer %"', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer %', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 2); - }); - }); - - it('should selects last selected tab by ":buffer #"', async() => { - let handles = await session.getWindowHandles(); - await session.switchToWindow(handles[1]); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('buffer #', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - assert.equal(tabs[0].index, 2); - }); - }); -}); diff --git a/e2e/command_buffer.test.ts b/e2e/command_buffer.test.ts new file mode 100644 index 0000000..0036839 --- /dev/null +++ b/e2e/command_buffer.test.ts @@ -0,0 +1,162 @@ +import * as path from 'path'; +import * as assert from 'assert'; +import { Request, Response } from 'express'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe('buffer command test', () => { + let server = new TestServer().handle('/*', (req: Request, res: Response) => { + res.send(` + <!DOCTYPE html> + <html lang="en"> + <head> + <title>my_${req.path.slice(1)}</title> + </head> + </html">`); + }); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + await browser.tabs.update(tabs[0].id, { url: server.url('/site1') }); + for (let i = 2; i <= 5; ++i) { + await browser.tabs.create({ url: server.url('/site' + i) }); + } + + await eventually(async() => { + let handles = await webdriver.getAllWindowHandles(); + assert.strictEqual(handles.length, 5); + await webdriver.switchTo().window(handles[2]); + }); + }); + + it('should do nothing by buffer command with no parameters', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 2); + }); + }); + + it('should select a tab by buffer command with a number', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer 1'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 0); + }); + }); + + it('should should an out of range error by buffer commands', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer 0'); + + await eventually(async() => { + let text = await console.getErrorMessage(); + assert.strictEqual(text, 'tab 0 does not exist'); + }); + + await (webdriver.switchTo() as any).parentFrame(); + + console = await page.showConsole(); + await console.execCommand('buffer 9'); + + await eventually(async() => { + let text = await console.getErrorMessage(); + assert.strictEqual(text, 'tab 9 does not exist'); + }); + }); + + it('should select a tab by buffer command with a title', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer my_site1'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 0); + }); + }); + + it('should select a tab by buffer command with an URL', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer /site1'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 0); + }); + }); + + it('should select tabs rotately', async() => { + let handles = await webdriver.getAllWindowHandles(); + await webdriver.switchTo().window(handles[4]); + + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer site'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 0); + }); + }); + + it('should do nothing by ":buffer %"', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer %'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 2); + }); + }); + + it('should selects last selected tab by ":buffer #"', async() => { + let handles = await webdriver.getAllWindowHandles(); + await webdriver.switchTo().window(handles[1]); + + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('buffer #'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + assert.strictEqual(tabs[0].index, 2); + }); + }); +}); diff --git a/e2e/command_open.test.js b/e2e/command_open.test.js deleted file mode 100644 index 0d41f96..0000000 --- a/e2e/command_open.test.js +++ /dev/null @@ -1,149 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); - -const Key = lanthan.Key; - -const newApp = () => { - - let app = express(); - for (let name of ['google', 'yahoo', 'bing', 'duckduckgo', 'twitter', 'wikipedia']) { - app.get('/' + name, (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><h1>${name.charAt(0).toUpperCase() + name.slice(1)}</h1></body> -</html">`); - }); - } - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><h1>home</h1></body> -</html">`); - }); - return app; -}; - -describe("open command test", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }) - - it('should open default search for keywords by open command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('open an apple', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }); - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/google?q=an%20apple`) - }); - }); - - it('should open certain search page for keywords by open command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('open yahoo an apple', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }) - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/yahoo?q=an%20apple`) - }); - }); - - it('should open default engine with empty keywords by open command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('open', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }) - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/google?q=`) - }); - }); - - it('should open certain search page for empty keywords by open command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('open yahoo', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }) - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/yahoo?q=`) - }); - }); - - it('should open a site with domain by open command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('open i-beam.org', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }) - let url = new URL(tabs[0].url); - assert.equal(url.href, 'https://i-beam.org/') - }); - }); - - it('should open a site with URL by open command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('open https://i-beam.org', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({ active: true }) - let url = new URL(tabs[0].url); - assert.equal(url.href, 'https://i-beam.org/') - }); - }); -}); diff --git a/e2e/command_open.test.ts b/e2e/command_open.test.ts new file mode 100644 index 0000000..6fb2645 --- /dev/null +++ b/e2e/command_open.test.ts @@ -0,0 +1,112 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import settings from './settings'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("open command test", () => { + let server = new TestServer(12321) + .receiveContent('/google', 'google') + .receiveContent('/yahoo', 'yahoo'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + await webdriver.switchTo().defaultContent(); + page = await Page.navigateTo(webdriver, server.url()); + }) + + it('should open default search for keywords by open command ', async() => { + let console = await page.showConsole(); + await console.execCommand('open an apple'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/google?q=an%20apple')) + }); + }); + + it('should open certain search page for keywords by open command ', async() => { + let console = await page.showConsole(); + await console.execCommand('open yahoo an apple'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }) + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple')) + }); + }); + + it('should open default engine with empty keywords by open command ', async() => { + let console = await page.showConsole(); + await console.execCommand('open'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }) + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/google?q=')) + }); + }); + + it('should open certain search page for empty keywords by open command ', async() => { + let console = await page.showConsole(); + await console.execCommand('open yahoo'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }) + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/yahoo?q=')) + }); + }); + + it('should open a site with domain by open command ', async() => { + let console = await page.showConsole(); + await console.execCommand('open example.com'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }) + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, 'http://example.com/') + }); + }); + + it('should open a site with URL by open command ', async() => { + let console = await page.showConsole(); + await console.execCommand('open https://example.com/'); + + await eventually(async() => { + let tabs = await browser.tabs.query({ active: true }) + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, 'https://example.com/') + }); + }); +}); diff --git a/e2e/command_quit.test.js b/e2e/command_quit.test.js deleted file mode 100644 index ee4c2d8..0000000 --- a/e2e/command_quit.test.js +++ /dev/null @@ -1,125 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/*', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <head> - <title>my_${req.path.slice(1)}</title> - </head> - <body><h1>${req.path}</h1></body> -</html">`); - }); - return app; -}; - -describe('quit/quitall command test', () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - await browser.tabs.update(tabs[0].id, { url: `http://127.0.0.1:${port}/site1` }); - for (let i = 2; i <= 5; ++i) { - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site${i}`}) - } - - await eventually(async() => { - let handles = await session.getWindowHandles(); - assert.equal(handles.length, 5); - await session.switchToWindow(handles[2]); - await session.findElementByCSS('iframe'); - }); - - await new Promise((resolve) => setTimeout(resolve, 100)); - }); - - it('should current tab by q command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('q', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 4) - }); - }); - - it('should current tab by quit command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('quit', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 4) - }); - }); - - it('should current tab by qa command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('qa', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 1) - }); - }); - - it('should current tab by quitall command', async() => { - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - await input.sendKeys('quitall', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 1) - }); - }); -}); diff --git a/e2e/command_quit.test.ts b/e2e/command_quit.test.ts new file mode 100644 index 0000000..239d880 --- /dev/null +++ b/e2e/command_quit.test.ts @@ -0,0 +1,93 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe('quit/quitall command test', () => { + let server = new TestServer().receiveContent('/*', 'ok'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + await browser.tabs.update(tabs[0].id, { url: server.url('/site1') }); + for (let i = 2; i <= 5; ++i) { + await browser.tabs.create({ url: server.url('/site' + i) }) + } + + await eventually(async() => { + let handles = await webdriver.getAllWindowHandles(); + assert.strictEqual(handles.length, 5); + await webdriver.switchTo().window(handles[2]); + }); + }); + + it('should current tab by q command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('q'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 4) + }); + }); + + it('should current tab by quit command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('quit'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 4) + }); + }); + + it('should current tab by qa command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('qa'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 1) + }); + }); + + it('should current tab by quitall command', async() => { + let page = await Page.currentContext(webdriver); + let console = await page.showConsole(); + await console.execCommand('quitall'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 1) + }); + }); +}); diff --git a/e2e/command_tabopen.test.js b/e2e/command_tabopen.test.js deleted file mode 100644 index 9c5cf3a..0000000 --- a/e2e/command_tabopen.test.js +++ /dev/null @@ -1,160 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); - -const Key = lanthan.Key; - -const newApp = () => { - - let app = express(); - for (let name of ['google', 'yahoo', 'bing', 'duckduckgo', 'twitter', 'wikipedia']) { - app.get('/' + name, (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><h1>${name.charAt(0).toUpperCase() + name.slice(1)}</h1></body> -</html">`); - }); - } - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><h1>home</h1></body> -</html">`); - }); - return app; -}; - -describe("tabopen command test", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }) - - it('should open default search for keywords by tabopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('tabopen an apple', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - let url = new URL(tabs[1].url); - assert.equal(url.href, `http://127.0.0.1:${port}/google?q=an%20apple`) - }); - }); - - it('should open certain search page for keywords by tabopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('tabopen yahoo an apple', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - let url = new URL(tabs[1].url); - assert.equal(url.href, `http://127.0.0.1:${port}/yahoo?q=an%20apple`) - }); - }); - - it('should open default engine with empty keywords by tabopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('tabopen', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - let url = new URL(tabs[1].url); - assert.equal(url.href, `http://127.0.0.1:${port}/google?q=`) - }); - }); - - it('should open certain search page for empty keywords by tabopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('tabopen yahoo', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - let url = new URL(tabs[1].url); - assert.equal(url.href, `http://127.0.0.1:${port}/yahoo?q=`) - }); - }); - - it('should open a site with domain by tabopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('tabopen i-beam.org', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - let url = new URL(tabs[1].url); - assert.equal(url.href, 'https://i-beam.org/') - }); - }); - - it('should open a site with URL by tabopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('tabopen https://i-beam.org', Key.Enter); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - let url = new URL(tabs[1].url); - assert.equal(url.href, 'https://i-beam.org/') - }); - }); -}); diff --git a/e2e/command_tabopen.test.ts b/e2e/command_tabopen.test.ts new file mode 100644 index 0000000..9d3da9a --- /dev/null +++ b/e2e/command_tabopen.test.ts @@ -0,0 +1,122 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import settings from './settings'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("tabopen command test", () => { + let server = new TestServer(12321) + .receiveContent('/google', 'google') + .receiveContent('/yahoo', 'yahoo'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + + page = await Page.navigateTo(webdriver, server.url()); + }) + + it('should open default search for keywords by tabopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('tabopen an apple'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + let url = new URL(tabs[1].url); + assert.strictEqual(url.href, server.url('/google?q=an%20apple') ) + }); + }); + + it('should open certain search page for keywords by tabopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('tabopen yahoo an apple'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + let url = new URL(tabs[1].url); + assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple')) + }); + }); + + it('should open default engine with empty keywords by tabopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('tabopen'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + let url = new URL(tabs[1].url); + assert.strictEqual(url.href, server.url('/google?q=')) + }); + }); + + it('should open certain search page for empty keywords by tabopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('tabopen yahoo'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + let url = new URL(tabs[1].url); + assert.strictEqual(url.href, server.url('/yahoo?q=')) + }); + }); + + it('should open a site with domain by tabopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('tabopen example.com'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + let url = new URL(tabs[1].url); + assert.strictEqual(url.href, 'http://example.com/') + }); + }); + + it('should open a site with URL by tabopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('tabopen https://example.com/'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + let url = new URL(tabs[1].url); + assert.strictEqual(url.href, 'https://example.com/') + }); + }); +}); diff --git a/e2e/command_winopen.test.js b/e2e/command_winopen.test.js deleted file mode 100644 index 536d759..0000000 --- a/e2e/command_winopen.test.js +++ /dev/null @@ -1,172 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); - -const Key = lanthan.Key; - -const newApp = () => { - - let app = express(); - for (let name of ['google', 'yahoo', 'bing', 'duckduckgo', 'twitter', 'wikipedia']) { - app.get('/' + name, (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><h1>${name.charAt(0).toUpperCase() + name.slice(1)}</h1></body> -</html">`); - }); - } - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><h1>home</h1></body> -</html">`); - }); - return app; -}; - -describe("winopen command test", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - let wins = await browser.windows.getAll(); - for (let win of wins.slice(1)) { - await browser.windows.remove(win.id); - } - - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }) - - it('should open default search for keywords by winopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('winopen an apple', Key.Enter); - - await eventually(async() => { - let wins = await browser.windows.getAll(); - assert.equal(wins.length, 2); - - let tabs = await browser.tabs.query({ windowId: wins[1].id }); - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/google?q=an%20apple`) - }); - }); - - it('should open certain search page for keywords by winopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('winopen yahoo an apple', Key.Enter); - - await eventually(async() => { - let wins = await browser.windows.getAll(); - assert.equal(wins.length, 2); - - let tabs = await browser.tabs.query({ windowId: wins[1].id }); - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/yahoo?q=an%20apple`) - }); - }); - - it('should open default engine with empty keywords by winopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('winopen', Key.Enter); - - await eventually(async() => { - let wins = await browser.windows.getAll(); - assert.equal(wins.length, 2); - - let tabs = await browser.tabs.query({ windowId: wins[1].id }); - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/google?q=`) - }); - }); - - it('should open certain search page for empty keywords by winopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('winopen yahoo', Key.Enter); - - await eventually(async() => { - let wins = await browser.windows.getAll(); - assert.equal(wins.length, 2); - - let tabs = await browser.tabs.query({ windowId: wins[1].id }); - let url = new URL(tabs[0].url); - assert.equal(url.href, `http://127.0.0.1:${port}/yahoo?q=`) - }); - }); - - it('should open a site with domain by winopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('winopen i-beam.org', Key.Enter); - - await eventually(async() => { - let wins = await browser.windows.getAll(); - assert.equal(wins.length, 2); - - let tabs = await browser.tabs.query({ windowId: wins[1].id }); - let url = new URL(tabs[0].url); - assert.equal(url.href, 'https://i-beam.org/') - }); - }); - - it('should open a site with URL by winopen command ', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys('winopen https://i-beam.org', Key.Enter); - - await eventually(async() => { - let wins = await browser.windows.getAll(); - assert.equal(wins.length, 2); - - let tabs = await browser.tabs.query({ windowId: wins[1].id }); - let url = new URL(tabs[0].url); - assert.equal(url.href, 'https://i-beam.org/') - }); - }); -}); diff --git a/e2e/command_winopen.test.ts b/e2e/command_winopen.test.ts new file mode 100644 index 0000000..95a0b6a --- /dev/null +++ b/e2e/command_winopen.test.ts @@ -0,0 +1,133 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import settings from './settings'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("winopen command test", () => { + let server = new TestServer(12321) + .receiveContent('/google', 'google') + .receiveContent('/yahoo', 'yahoo'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await browser.storage.local.set({ + settings, + }); + + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let wins = await browser.windows.getAll(); + for (let win of wins.slice(1)) { + await browser.windows.remove(win.id); + } + + page = await Page.navigateTo(webdriver, server.url()); + }) + + it('should open default search for keywords by winopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('winopen an apple'); + + await eventually(async() => { + let wins = await browser.windows.getAll(); + assert.strictEqual(wins.length, 2); + + let tabs = await browser.tabs.query({ windowId: wins[1].id }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/google?q=an%20apple')) + }); + }); + + it('should open certain search page for keywords by winopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('winopen yahoo an apple'); + + await eventually(async() => { + let wins = await browser.windows.getAll(); + assert.strictEqual(wins.length, 2); + + let tabs = await browser.tabs.query({ windowId: wins[1].id }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple')) + }); + }); + + it('should open default engine with empty keywords by winopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('winopen'); + + await eventually(async() => { + let wins = await browser.windows.getAll(); + assert.strictEqual(wins.length, 2); + + let tabs = await browser.tabs.query({ windowId: wins[1].id }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/google?q=')) + }); + }); + + it('should open certain search page for empty keywords by winopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('winopen yahoo'); + + await eventually(async() => { + let wins = await browser.windows.getAll(); + assert.strictEqual(wins.length, 2); + + let tabs = await browser.tabs.query({ windowId: wins[1].id }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, server.url('/yahoo?q=')) + }); + }); + + it('should open a site with domain by winopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('winopen example.com'); + + await eventually(async() => { + let wins = await browser.windows.getAll(); + assert.strictEqual(wins.length, 2); + + let tabs = await browser.tabs.query({ windowId: wins[1].id }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, 'http://example.com/') + }); + }); + + it('should open a site with URL by winopen command ', async() => { + let console = await page.showConsole(); + await console.execCommand('winopen https://example.com/'); + + await eventually(async() => { + let wins = await browser.windows.getAll(); + assert.strictEqual(wins.length, 2); + + let tabs = await browser.tabs.query({ windowId: wins[1].id }); + let url = new URL(tabs[0].url); + assert.strictEqual(url.href, 'https://example.com/') + }); + }); +}); diff --git a/e2e/completion.test.js b/e2e/completion.test.js deleted file mode 100644 index 5d910c6..0000000 --- a/e2e/completion.test.js +++ /dev/null @@ -1,136 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); -const Console = require('./lib/Console'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body>ok</body> -</html">`); - }); - return app; -}; - -describe("general completion test", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }); - - it('should all commands on empty line', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 10); - assert.deepEqual(items[0], { type: 'title', text: 'Console Command' }); - assert(items[1].text.startsWith('set')) - assert(items[2].text.startsWith('open')) - assert(items[3].text.startsWith('tabopen')) - }); - }); - - it('should only commands filtered by prefix', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('b'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 4); - assert.deepEqual(items[0], { type: 'title', text: 'Console Command' }); - assert(items[1].text.startsWith('buffer')) - assert(items[2].text.startsWith('bdelete')) - assert(items[3].text.startsWith('bdeletes')) - }); - }); - - it('selects completion items by <Tab>/<S-Tab> keys', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('b'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 4); - }); - - await c.sendKeys(Key.Tab); - await eventually(async() => { - let items = await c.getCompletions(); - assert(items[1].highlight) - - let v = await c.currentValue(); - assert.equal(v, 'buffer'); - }); - - await c.sendKeys(Key.Tab, Key.Tab); - await eventually(async() => { - let items = await c.getCompletions(); - assert(items[3].highlight) - - let v = await c.currentValue(); - assert.equal(v, 'bdeletes'); - }); - - await c.sendKeys(Key.Tab); - await eventually(async() => { - let v = await c.currentValue(); - assert.equal(v, 'b'); - }); - - await c.sendKeys(Key.Shift, Key.Tab); - await eventually(async() => { - let items = await c.getCompletions(); - assert(items[3].highlight) - - let v = await c.currentValue(); - assert.equal(v, 'bdeletes'); - }); - }); -}); diff --git a/e2e/completion.test.ts b/e2e/completion.test.ts new file mode 100644 index 0000000..28c1913 --- /dev/null +++ b/e2e/completion.test.ts @@ -0,0 +1,100 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import eventually from './eventually'; +import settings from './settings'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("general completion test", () => { + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + }); + + after(async() => { + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + page = await Page.navigateTo(webdriver, 'about:blank'); + }); + + it('should all commands on empty line', async() => { + let console = await page.showConsole(); + + let items = await console.getCompletions(); + assert.strictEqual(items.length, 10); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Console Command' }); + assert.ok(items[1].text.startsWith('set')) + assert.ok(items[2].text.startsWith('open')) + assert.ok(items[3].text.startsWith('tabopen')) + }); + + it('should only commands filtered by prefix', async() => { + let console = await page.showConsole(); + await console.inputKeys('b'); + + let items = await console.getCompletions(); + assert.strictEqual(items.length, 4); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Console Command' }); + assert.ok(items[1].text.startsWith('buffer')) + assert.ok(items[2].text.startsWith('bdelete')) + assert.ok(items[3].text.startsWith('bdeletes')) + }); + + // > byffer + // > bdelete + // > bdeletes + // : b + it('selects completion items by <Tab>/<S-Tab> keys', async() => { + let console = await page.showConsole(); + await console.inputKeys('b'); + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 4); + }); + + await console.sendKeys(Key.TAB); + await eventually(async() => { + let items = await console.getCompletions(); + assert.ok(items[1].highlight) + assert.strictEqual(await console.currentValue(), 'buffer'); + }); + + await console.sendKeys(Key.TAB, Key.TAB); + await eventually(async() => { + let items = await console.getCompletions(); + assert.ok(items[3].highlight) + assert.strictEqual(await console.currentValue(), 'bdeletes'); + }); + + await console.sendKeys(Key.TAB); + await eventually(async() => { + assert.strictEqual(await console.currentValue(), 'b'); + }); + + await console.sendKeys(Key.SHIFT, Key.TAB); + await eventually(async() => { + let items = await console.getCompletions(); + assert.ok(items[3].highlight) + assert.strictEqual(await console.currentValue(), 'bdeletes'); + }); + }); +}); diff --git a/e2e/completion_buffers.test.js b/e2e/completion_buffers.test.js deleted file mode 100644 index de26747..0000000 --- a/e2e/completion_buffers.test.js +++ /dev/null @@ -1,214 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); -const Console = require('./lib/Console'); - -const Key = lanthan.Key; - -const newApp = () => { - - let app = express(); - app.get('/*', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <head> - <title>title_${req.path.slice(1)}</title> - </head> - <body><h1>home</h1></body> -</html">`); - }); - return app; -}; - -describe("completion on buffer/bdelete/bdeletes", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - - await browser.tabs.update(tabs[0].id, { url: `http://127.0.0.1:${port}/site1`, pinned: true }); - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site2`, pinned: true }) - for (let i = 3; i <= 5; ++i) { - await browser.tabs.create({ url: `http://127.0.0.1:${port}/site${i}` }) - } - - await eventually(async() => { - let handles = await session.getWindowHandles(); - assert.equal(handles.length, 5); - await session.switchToWindow(handles[2]); - await session.findElementByCSS('iframe'); - }); - body = await session.findElementByCSS('body'); - - await new Promise((resolve) => setTimeout(resolve, 100)); - }); - - it('should all tabs by "buffer" command with empty params', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('buffer '); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 6); - assert.deepEqual(items[0], { type: 'title', text: 'Buffers' }); - assert(items[1].text.startsWith('1:')); - assert(items[2].text.startsWith('2:')); - assert(items[3].text.startsWith('3:')); - assert(items[4].text.startsWith('4:')); - assert(items[5].text.startsWith('5:')); - - assert(items[3].text.includes('%')); - assert(items[5].text.includes('#')); - }); - }) - - it('should filter items with URLs by keywords on "buffer" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('buffer title_site2'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.deepEqual(items[0], { type: 'title', text: 'Buffers' }); - assert(items[1].text.startsWith('2:')); - assert(items[1].text.includes('title_site2')); - assert(items[1].text.includes(`http://127.0.0.1:${port}/site2`)); - }); - }) - - it('should filter items with titles by keywords on "buffer" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('buffer /site2'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.deepEqual(items[0], { type: 'title', text: 'Buffers' }); - assert(items[1].text.startsWith('2:')); - }); - }) - - it('should show one item by number on "buffer" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('buffer 2'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 2); - assert.deepEqual(items[0], { type: 'title', text: 'Buffers' }); - assert(items[1].text.startsWith('2:')); - }); - }) - - it('should show unpinned tabs "bdelete" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('bdelete site'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 4); - assert(items[1].text.includes('site3')); - assert(items[2].text.includes('site4')); - assert(items[3].text.includes('site5')); - }); - }) - - it('should show unpinned tabs "bdeletes" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('bdelete site'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 4); - assert(items[1].text.includes('site3')); - assert(items[2].text.includes('site4')); - assert(items[3].text.includes('site5')); - }); - }) - - it('should show both pinned and unpinned tabs "bdelete!" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('bdelete! site'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 6); - assert(items[1].text.includes('site1')); - assert(items[2].text.includes('site2')); - assert(items[3].text.includes('site3')); - assert(items[4].text.includes('site4')); - assert(items[5].text.includes('site5')); - }); - }) - - it('should show both pinned and unpinned tabs "bdeletes!" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('bdeletes! site'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 6); - assert(items[1].text.includes('site1')); - assert(items[2].text.includes('site2')); - assert(items[3].text.includes('site3')); - assert(items[4].text.includes('site4')); - assert(items[5].text.includes('site5')); - }); - }) -}); diff --git a/e2e/completion_buffers.test.ts b/e2e/completion_buffers.test.ts new file mode 100644 index 0000000..b2d4201 --- /dev/null +++ b/e2e/completion_buffers.test.ts @@ -0,0 +1,180 @@ +import * as assert from 'assert'; +import * as path from 'path'; + +import { Request, Response } from 'express' +import TestServer from './lib/TestServer'; +import settings from './settings'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("completion on buffer/bdelete/bdeletes", () => { + let server = new TestServer().handle('/*', (req: Request, res: Response) => { + res.send(` + <!DOCTYPE html> + <html lang="en"> + <head> + <title>title_${req.path.slice(1)}</title> + </head> + </html">`); + }); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + + await browser.tabs.update(tabs[0].id, { url: server.url('/site1'), pinned: true }); + await browser.tabs.create({ url:server.url('/site2'), pinned: true }) + for (let i = 3; i <= 5; ++i) { + await browser.tabs.create({ url: server.url('/site' + i) }); + } + + await eventually(async() => { + let handles = await webdriver.getAllWindowHandles(); + assert.strictEqual(handles.length, 5); + await webdriver.switchTo().window(handles[2]); + }); + + page = await Page.currentContext(webdriver); + }); + + it('should all tabs by "buffer" command with empty params', async() => { + let console = await page.showConsole(); + await console.inputKeys('buffer '); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 6); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' }); + assert.ok(items[1].text.startsWith('1:')); + assert.ok(items[2].text.startsWith('2:')); + assert.ok(items[3].text.startsWith('3:')); + assert.ok(items[4].text.startsWith('4:')); + assert.ok(items[5].text.startsWith('5:')); + + assert.ok(items[3].text.includes('%')); + assert.ok(items[5].text.includes('#')); + }); + }) + + it('should filter items with URLs by keywords on "buffer" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('buffer title_site2'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' }); + assert.ok(items[1].text.startsWith('2:')); + assert.ok(items[1].text.includes('title_site2')); + assert.ok(items[1].text.includes(server.url('/site2'))); + }); + }) + + it('should filter items with titles by keywords on "buffer" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('buffer /site2'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' }); + assert.ok(items[1].text.startsWith('2:')); + }); + }) + + it('should show one item by number on "buffer" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('buffer 2'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 2); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' }); + assert.ok(items[1].text.startsWith('2:')); + }); + }) + + it('should show unpinned tabs "bdelete" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('bdelete site'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 4); + assert.ok(items[1].text.includes('site3')); + assert.ok(items[2].text.includes('site4')); + assert.ok(items[3].text.includes('site5')); + }); + }) + + it('should show unpinned tabs "bdeletes" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('bdeletes site'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 4); + assert.ok(items[1].text.includes('site3')); + assert.ok(items[2].text.includes('site4')); + assert.ok(items[3].text.includes('site5')); + }); + }) + + it('should show both pinned and unpinned tabs "bdelete!" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('bdelete! site'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 6); + assert.ok(items[1].text.includes('site1')); + assert.ok(items[2].text.includes('site2')); + assert.ok(items[3].text.includes('site3')); + assert.ok(items[4].text.includes('site4')); + assert.ok(items[5].text.includes('site5')); + }); + }) + + it('should show both pinned and unpinned tabs "bdeletes!" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('bdeletes! site'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 6); + assert.ok(items[1].text.includes('site1')); + assert.ok(items[2].text.includes('site2')); + assert.ok(items[3].text.includes('site3')); + assert.ok(items[4].text.includes('site4')); + assert.ok(items[5].text.includes('site5')); + }); + }) +}); diff --git a/e2e/completion_open.test.js b/e2e/completion_open.test.js deleted file mode 100644 index 5828768..0000000 --- a/e2e/completion_open.test.js +++ /dev/null @@ -1,255 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); -const Console = require('./lib/Console'); - -const Key = lanthan.Key; - -const newApp = () => { - - let app = express(); - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body>ok</body> -</html">`); - }); - return app; -}; - -describe("completion on open/tabopen/winopen commands", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - - await browser.storage.local.set({ - settings, - }); - - // Add item into hitories - await session.navigateTo(`https://i-beam.org/404`); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }); - - it('should show completions from search engines, bookmarks, and histories by "open" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('open '); - - await eventually(async() => { - let completions = await c.getCompletions(); - assert(completions.find(x => x.type === 'title' && x.text === 'Search Engines')); - assert(completions.find(x => x.type === 'title' && x.text === 'Bookmarks')); - assert(completions.find(x => x.type === 'title' && x.text === 'History')); - }); - }); - - it('should filter items with URLs by keywords on "open" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('open https://'); - - await eventually(async() => { - let completions = await c.getCompletions(); - let items = completions.filter(x => x.type === 'item').map(x => x.text); - assert(items.every(x => x.includes('https://'))); - }); - }) - - it('should filter items with titles by keywords on "open" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('open getting'); - - await eventually(async() => { - let completions = await c.getCompletions(); - let items = completions.filter(x => x.type === 'item').map(x => x.text); - assert(items.every(x => x.toLowerCase().includes('getting'))); - }); - }) - - it('should filter items with titles by keywords on "tabopen" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('tabopen https://'); - - await eventually(async() => { - let completions = await c.getCompletions(); - let items = completions.filter(x => x.type === 'item').map(x => x.text); - assert(items.every(x => x.includes('https://'))); - }); - }) - - it('should filter items with titles by keywords on "winopen" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('winopen https://'); - - await eventually(async() => { - let completions = await c.getCompletions(); - let items = completions.filter(x => x.type === 'item').map(x => x.text); - assert(items.every(x => x.includes('https://'))); - }); - }) - - it('should display only specified items in "complete" property by set command', async() => { - let c = new Console(session); - - const execCommand = async(line) => { - await body.sendKeys(':'); - await session.switchToFrame(0); - await c.sendKeys(line, Key.Enter); - await session.switchToParentFrame(); - } - - const typeCommand = async(...keys) => { - await body.sendKeys(':'); - await session.switchToFrame(0); - await c.sendKeys(...keys); - } - - const cancel = async() => { - await c.sendKeys(Key.Escape); - await session.switchToParentFrame(); - } - - await execCommand('set complete=sbh'); - await typeCommand('open '); - - await eventually(async() => { - let completions = await c.getCompletions(); - let titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepEqual(titles, ['Search Engines', 'Bookmarks', 'History']) - }); - - await cancel(); - await execCommand('set complete=bss'); - await typeCommand('open '); - - await eventually(async() => { - let completions = await c.getCompletions(); - let titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines']) - }); - }) - - it('should display only specified items in "complete" property by setting', async() => { - const settings = { - source: 'json', - json: `{ - "keymaps": { - ":": { "type": "command.show" } - }, - "search": { - "default": "google", - "engines": { "google": "https://google.com/search?q={}" } - }, - "properties": { - "complete": "sbh" - } - }`, - }; - await browser.storage.local.set({ settings, }); - - let c = new Console(session); - - const typeCommand = async(...keys) => { - await body.sendKeys(':'); - await session.switchToFrame(0); - await c.sendKeys(...keys); - } - - const cancel = async() => { - await c.sendKeys(Key.Escape); - await session.switchToParentFrame(); - } - - await browser.storage.local.set({ settings: { - source: 'json', - json: `{ - "keymaps": { - ":": { "type": "command.show" } - }, - "search": { - "default": "google", - "engines": { "google": "https://google.com/search?q={}" } - }, - "properties": { - "complete": "sbh" - } - }`, - }}); - await typeCommand('open '); - - await eventually(async() => { - let completions = await c.getCompletions(); - let titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepEqual(titles, ['Search Engines', 'Bookmarks', 'History']) - }); - - await cancel(); - - await browser.storage.local.set({ settings: { - source: 'json', - json: `{ - "keymaps": { - ":": { "type": "command.show" } - }, - "search": { - "default": "google", - "engines": { "google": "https://google.com/search?q={}" } - }, - "properties": { - "complete": "bss" - } - }`, - }}); - await typeCommand('open '); - - await eventually(async() => { - let completions = await c.getCompletions(); - let titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines']) - }); - - - }) -}); diff --git a/e2e/completion_open.test.ts b/e2e/completion_open.test.ts new file mode 100644 index 0000000..c957e2e --- /dev/null +++ b/e2e/completion_open.test.ts @@ -0,0 +1,186 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import settings from './settings'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("completion on open/tabopen/winopen commands", () => { + let server = new TestServer().receiveContent('/*', 'ok'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + await server.start(); + + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + + // Add item into hitories + await webdriver.navigate().to(('https://i-beam.org/404')); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + page = await Page.navigateTo(webdriver, server.url()); + }); + + it('should show completions from search engines, bookmarks, and histories by "open" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('open '); + + await eventually(async() => { + let completions = await console.getCompletions(); + assert.ok(completions.find(x => x.type === 'title' && x.text === 'Search Engines')); + assert.ok(completions.find(x => x.type === 'title' && x.text === 'Bookmarks')); + assert.ok(completions.find(x => x.type === 'title' && x.text === 'History')); + }); + }); + + it('should filter items with URLs by keywords on "open" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('open https://'); + + await eventually(async() => { + let completions = await console.getCompletions(); + let items = completions.filter(x => x.type === 'item').map(x => x.text); + assert.ok(items.every(x => x.includes('https://'))); + }); + }) + + it('should filter items with titles by keywords on "open" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('open getting'); + + await eventually(async() => { + let completions = await console.getCompletions(); + let items = completions.filter(x => x.type === 'item').map(x => x.text); + assert.ok(items.every(x => x.toLowerCase().includes('getting'))); + }); + }) + + it('should filter items with titles by keywords on "tabopen" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('tabopen getting'); + + await eventually(async() => { + let completions = await console.getCompletions(); + let items = completions.filter(x => x.type === 'item').map(x => x.text); + assert.ok(items.every(x => x.includes('https://'))); + }); + }) + + it('should filter items with titles by keywords on "winopen" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('winopen https://'); + + await eventually(async() => { + let completions = await console.getCompletions(); + let items = completions.filter(x => x.type === 'item').map(x => x.text); + assert.ok(items.every(x => x.includes('https://'))); + }); + }) + + it('should display only specified items in "complete" property by set command', async() => { + let console = await page.showConsole(); + await console.execCommand('set complete=sbh'); + await (webdriver.switchTo() as any).parentFrame(); + + console = await page.showConsole(); + await console.inputKeys('open '); + + await eventually(async() => { + let completions = await console.getCompletions(); + let titles = completions.filter(x => x.type === 'title').map(x => x.text); + assert.deepStrictEqual(titles, ['Search Engines', 'Bookmarks', 'History']) + }); + + await console.close(); + console = await page.showConsole(); + await console.execCommand('set complete=bss'); + await (webdriver.switchTo() as any).parentFrame(); + + console = await page.showConsole(); + await console.inputKeys('open '); + + await eventually(async() => { + let completions = await console.getCompletions(); + let titles = completions.filter(x => x.type === 'title').map(x => x.text); + assert.deepStrictEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines']) + }); + }) + + it('should display only specified items in "complete" property by setting', async() => { + await browser.storage.local.set({ settings: { + source: 'json', + json: `{ + "keymaps": { + ":": { "type": "command.show" } + }, + "search": { + "default": "google", + "engines": { "google": "https://google.com/search?q={}" } + }, + "properties": { + "complete": "sbh" + } + }`, + }}); + + let console = await page.showConsole(); + await console.inputKeys('open '); + + await eventually(async() => { + let completions = await console.getCompletions(); + let titles = completions.filter(x => x.type === 'title').map(x => x.text); + assert.deepStrictEqual(titles, ['Search Engines', 'Bookmarks', 'History']) + }); + + await console.close(); + await (webdriver.switchTo() as any).parentFrame(); + + await browser.storage.local.set({ settings: { + source: 'json', + json: `{ + "keymaps": { + ":": { "type": "command.show" } + }, + "search": { + "default": "google", + "engines": { "google": "https://google.com/search?q={}" } + }, + "properties": { + "complete": "bss" + } + }`, + }}); + + console = await page.showConsole(); + await console.inputKeys('open '); + + await eventually(async() => { + let completions = await console.getCompletions(); + let titles = completions.filter(x => x.type === 'title').map(x => x.text); + assert.deepStrictEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines']) + }); + }) +}); diff --git a/e2e/completion_set.test.js b/e2e/completion_set.test.js deleted file mode 100644 index cf5ff5b..0000000 --- a/e2e/completion_set.test.js +++ /dev/null @@ -1,75 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const settings = require('./settings'); -const Console = require('./lib/Console'); - -const Key = lanthan.Key; - -describe("completion on set commands", () => { - const port = 12321; - let firefox; - let session; - let browser; - let body; - - before(async() => { - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - - await browser.storage.local.set({ - settings, - }); - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo(`about:blank`); - body = await session.findElementByCSS('body'); - }); - - it('should show all property names by "set" command with empty params', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('set '); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 5); - assert.deepEqual(items[0], { type: 'title', text: 'Properties' }); - assert(items[1].text.startsWith('hintchars')) - assert(items[2].text.startsWith('smoothscroll')) - assert(items[3].text.startsWith('nosmoothscroll')) - assert(items[4].text.startsWith('complete')) - }); - }); - - it('should show filtered property names by "set" command', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - let c = new Console(session); - await c.sendKeys('set no'); - - await eventually(async() => { - let items = await c.getCompletions(); - assert.equal(items.length, 2); - assert(items[1].text.includes('nosmoothscroll')) - }); - }); -}); diff --git a/e2e/completion_set.test.ts b/e2e/completion_set.test.ts new file mode 100644 index 0000000..2a14b2c --- /dev/null +++ b/e2e/completion_set.test.ts @@ -0,0 +1,64 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import settings from './settings'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("completion on set commands", () => { + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ + settings, + }); + }); + + after(async() => { + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + page = await Page.navigateTo(webdriver, `about:blank`); + }); + + it('should show all property names by "set" command with empty params', async() => { + let console = await page.showConsole(); + await console.inputKeys('set '); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 5); + assert.deepStrictEqual(items[0], { type: 'title', text: 'Properties' }); + assert.ok(items[1].text.startsWith('hintchars')) + assert.ok(items[2].text.startsWith('smoothscroll')) + assert.ok(items[3].text.startsWith('nosmoothscroll')) + assert.ok(items[4].text.startsWith('complete')) + }); + }); + + it('should show filtered property names by "set" command', async() => { + let console = await page.showConsole(); + await console.inputKeys('set no'); + + await eventually(async() => { + let items = await console.getCompletions(); + assert.strictEqual(items.length, 2); + assert.ok(items[1].text.includes('nosmoothscroll')) + }); + }); +}); diff --git a/e2e/console.test.js b/e2e/console.test.js deleted file mode 100644 index 6f6341f..0000000 --- a/e2e/console.test.js +++ /dev/null @@ -1,125 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <head> - <title>Hello, world!</title> - </head> -</html">`); - }); - return app; -}; - - -describe("console test", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - let tab; - let body; - - before(async() => { - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }); - - it('open console with :', async() => { - await body.sendKeys(':'); - - await session.switchToFrame(0); - - let input = await session.findElementByCSS('input'); - assert.equal(await input.isDisplayed(), true); - }); - - it('open console with open command by o', async() => { - await body.sendKeys('o'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, 'open '); - }); - - it('open console with open command and current URL by O', async() => { - await body.sendKeys(Key.Shift, 'o'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, `open http://127.0.0.1:${port}/`); - }); - - it('open console with tabopen command by t', async() => { - await body.sendKeys('t'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, 'tabopen '); - }); - - it('open console with tabopen command and current URL by T', async() => { - await body.sendKeys(Key.Shift, 't'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, `tabopen http://127.0.0.1:${port}/`); - }); - - it('open console with winopen command by w', async() => { - await body.sendKeys('w'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, 'winopen '); - }); - - it('open console with winopen command and current URL by W', async() => { - await body.sendKeys(Key.Shift, 'W'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, `winopen http://127.0.0.1:${port}/`); - }); - - it('open console with buffer command by b', async() => { - await body.sendKeys('b'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, `buffer `); - }); - - it('open console with addbookmark command with title by a', async() => { - await body.sendKeys('a'); - - await session.switchToFrame(0); - let value = await session.executeScript(() => document.querySelector('input').value); - assert.equal(value, `addbookmark Hello, world!`); - }); -}); - diff --git a/e2e/console.test.ts b/e2e/console.test.ts new file mode 100644 index 0000000..583580a --- /dev/null +++ b/e2e/console.test.ts @@ -0,0 +1,90 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("console test", () => { + let server = new TestServer().receiveContent('/', + `<!DOCTYPE html><html lang="en"><head><title>Hello, world!</title></head></html">`, + ); + let lanthan: Lanthan; + let webdriver: WebDriver; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + page = await Page.navigateTo(webdriver, server.url()); + }); + + it('open console with :', async() => { + await page.sendKeys(':'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), ''); + }); + + it('open console with open command by o', async() => { + await page.sendKeys('o'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), 'open '); + }); + + it('open console with open command and current URL by O', async() => { + await page.sendKeys(Key.SHIFT, 'o'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), `open ${server.url()}`); + }); + + it('open console with tabopen command by t', async() => { + await page.sendKeys('t'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), 'tabopen '); + }); + + it('open console with tabopen command and current URL by T', async() => { + await page.sendKeys(Key.SHIFT, 't'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), `tabopen ${server.url()}`); + }); + + it('open console with winopen command by w', async() => { + await page.sendKeys('w'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), `winopen `); + }); + + it('open console with winopen command and current URL by W', async() => { + await page.sendKeys(Key.SHIFT, 'W'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), `winopen ${server.url()}`); + }); + + it('open console with buffer command by b', async() => { + await page.sendKeys('b'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), `buffer `); + }); + + it('open console with addbookmark command with title by a', async() => { + await page.sendKeys('a'); + let console = await page.getConsole(); + assert.strictEqual(await console.currentValue(), `addbookmark Hello, world!`); + }); +}); diff --git a/e2e/eventually.js b/e2e/eventually.js deleted file mode 100644 index ab0ae25..0000000 --- a/e2e/eventually.js +++ /dev/null @@ -1,23 +0,0 @@ -let defaultInterval = 100; -let defaultTimeout = 2000; - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -const eventually = async (fn, timeout = defaultTimeout, interval = defaultInterval) => { - let start = Date.now(); - let loop = async() => { - try { - await fn(); - } catch (err) { - if (Date.now() - start > timeout) { - throw err; - } - await new Promise((resolve) => setTimeout(resolve, interval)) - await loop(); - } - }; - await loop(); -}; -module.exports = eventually; diff --git a/e2e/eventually.ts b/e2e/eventually.ts new file mode 100644 index 0000000..12c4552 --- /dev/null +++ b/e2e/eventually.ts @@ -0,0 +1,30 @@ +const defaultInterval = 100; +const defaultTimeout = 2000; + +type Handler = () => void + +const sleep = (ms: number): Promise<void> => { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +const eventually = async ( + fn: Handler, + timeout = defaultTimeout, + interval = defaultInterval, +): Promise<void> => { + let start = Date.now(); + let loop = async() => { + try { + await fn(); + } catch (err) { + if (Date.now() - start > timeout) { + throw err; + } + await sleep(interval); + await loop(); + } + }; + await loop(); +}; + +export default eventually; diff --git a/e2e/follow.test.js b/e2e/follow.test.js deleted file mode 100644 index 7e49119..0000000 --- a/e2e/follow.test.js +++ /dev/null @@ -1,257 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><a href="hello">hello</a></body> -</html">`); - }); - - app.get('/follow-input', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><input></body> -</html">`); - }); - - app.get('/area', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body> - <img - width="256" height="256" usemap="#map" - src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" - > - <map name="map"> - <area shape="rect" coords="0,0,64,64" href="/"> - <area shape="rect" coords="64,64,64,64" href="/"> - <area shape="rect" coords="128,128,64,64" href="/"> - </map> - </body> -</html">`); - }); - - /* - * test case: link2 is out of the viewport - * +-----------------+ - * | [link1] |<--- window - * | | - * |=================|<--- viewport - * | [link2] | - * | | - * +-----------------+ - */ - app.get('/test1', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body> - <div><a href="link1">link1</a></div> - <div style="min-height:3000px"></div> - <div><a href="link2">link2</a></div> - </body> -</html">`); - }); - -/* - * test case 2: link2 and link3 are out of window of the frame - * +-----------------+ - * | +-----------+ | - * | | [link1] | | - * |=================| - * | | [link2] | | - * | +-----------+ | - * | | - * +-----------------+ - */ - app.get('/test2', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><iframe height="5000" src='/test2-frame'></body> -</html">`); - }); - app.get('/test2-frame', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body> - <div><a href="link1">link1</a></div> - <div style="min-height:3000px"></div> - <div><a href="link2">link2</a></div> - </body> -</html">`); - }); - -/* test case 3: link2 is out of window of the frame - * +-----------------+ - * | +-----------+ | - * | | [link1] | | - * | +-----------+ | - * | : [link2] : | - * | + - - - - - + | - * | | - * +-----------------+ - */ - app.get('/test3', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body><iframe src='/test3-frame'></body> -</html">`); - }); - app.get('/test3-frame', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body> - <div><a href="link1">link1</a></div> - <div style="min-height:3000px"></div> - <div><a href="link2">link2</a></div> - </body> -</html">`); - }); - - return app; -}; - -const waitForHints = async(session) => { - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert(hints.length > 0); - }); -}; - -describe('follow test', () => { - - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - afterEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - }); - - it('should focus an input by f', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/follow-input`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('f'); - await waitForHints(session); - await body.sendKeys('a'); - - let tagName = await session.executeScript(() => document.activeElement.tagName); - assert.equal(tagName.toLowerCase(), 'input'); - }); - - it('should open a link by f', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('f', 'a'); - - let hash = await session.executeScript('location.pathname'); - await body.sendKeys(hash, '/hello'); - }); - - it('should focus an input by F', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/follow-input`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'f'); - await waitForHints(session); - await body.sendKeys('a'); - - let tagName = await session.executeScript(() => document.activeElement.tagName); - assert.equal(tagName.toLowerCase(), 'input'); - }); - - it('should open a link to new tab by F', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'f'); - await waitForHints(session); - await body.sendKeys('a'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - assert.equal(new URL(tabs[1].url).pathname, '/hello'); - assert.equal(tabs[1].openerTabId, tabs[0].id); - }); - }); - - it('should show hints of links in area', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/area`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'f'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 3); - }); - }); - - it('should shows hints only in viewport', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/test1`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'f'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 1); - }); - }); - - it('should shows hints only in window of the frame', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/test2`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'f'); - - await session.switchToFrame(0); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 1); - }); - }); - - it('should shows hints only in the frame', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/test3`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'f'); - - await session.switchToFrame(0); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 1); - }); - }); -}); diff --git a/e2e/follow.test.ts b/e2e/follow.test.ts new file mode 100644 index 0000000..fd741ef --- /dev/null +++ b/e2e/follow.test.ts @@ -0,0 +1,216 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +const newApp = () => { + let server = new TestServer(); + + server.receiveContent('/', ` + <!DOCTYPE html> + <html lang="en"><body> + <a href="hello">hello</a> + </body></html">`); + + server.receiveContent('/follow-input', ` + <!DOCTYPE html> + <html lang="en"><body> + <input> + </body></html">`); + + server.receiveContent('/area', ` + <!DOCTYPE html> + <html lang="en"><body> + <img + width="256" height="256" usemap="#map" + src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" + > + <map name="map"> + <area shape="rect" coords="0,0,64,64" href="/"> + <area shape="rect" coords="64,64,64,64" href="/"> + <area shape="rect" coords="128,128,64,64" href="/"> + </map> + </body></html">`); + + /* + * test case: link2 is out of the viewport + * +-----------------+ + * | [link1] |<--- window + * | | + * |=================|<--- viewport + * | [link2] | + * | | + * +-----------------+ + */ + server.receiveContent('/test1', ` + <!DOCTYPE html> + <html lang="en"><body> + <div><a href="link1">link1</a></div> + <div style="min-height:3000px"></div> + <div><a href="link2">link2</a></div> + </body></html">`); + +/* + * test case 2: link2 and link3 are out of window of the frame + * +-----------------+ + * | +-----------+ | + * | | [link1] | | + * |=================| + * | | [link2] | | + * | +-----------+ | + * | | + * +-----------------+ + */ + server.receiveContent('/test2', ` + <!DOCTYPE html> + <html lang="en"><body> + <iframe height="5000" src='/test2-frame'> + </body></html">`); + server.receiveContent('/test2-frame', ` + <!DOCTYPE html> + <html lang="en"><body> + <div><a href="link1">link1</a></div> + <div style="min-height:3000px"></div> + <div><a href="link2">link2</a></div> + </body></html">`); + +/* test case 3: link2 is out of window of the frame + * +-----------------+ + * | +-----------+ | + * | | [link1] | | + * | +-----------+ | + * | : [link2] : | + * | + - - - - - + | + * | | + * +-----------------+ + */ + server.receiveContent('/test3', ` + <!DOCTYPE html> + <html lang="en"><body> + <iframe src='/test3-frame'> + </body></html">`); + server.receiveContent('/test3-frame', ` + <!DOCTYPE html> + <html lang="en"><body> + <div><a href="link1">link1</a></div> + <div style="min-height:3000px"></div> + <div><a href="link2">link2</a></div> + </body></html">`); + + return server; +}; + +describe('follow test', () => { + let server = newApp(); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + afterEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + }); + + it('should focus an input by f', async () => { + let page = await Page.navigateTo(webdriver, server.url('/follow-input')); + await page.sendKeys('f'); + await page.waitAndGetHints(); + await page.sendKeys('a'); + + let tagName = await webdriver.executeScript(() => document.activeElement!!.tagName) as string; + assert.strictEqual(tagName.toLowerCase(), 'input'); + }); + + it('should open a link by f', async () => { + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys('f'); + await page.waitAndGetHints(); + await page.sendKeys('a'); + + await eventually(async() => { + let hash = await webdriver.executeScript('return location.pathname'); + assert.strictEqual(hash, '/hello'); + }); + }); + + it('should focus an input by F', async () => { + let page = await Page.navigateTo(webdriver, server.url('/follow-input')); + await page.sendKeys(Key.SHIFT, 'f'); + await page.waitAndGetHints(); + await page.sendKeys('a'); + + let tagName = await webdriver.executeScript(() => document.activeElement!!.tagName) as string; + assert.strictEqual(tagName.toLowerCase(), 'input'); + }); + + it('should open a link to new tab by F', async () => { + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys(Key.SHIFT, 'f'); + await page.waitAndGetHints(); + await page.sendKeys('a'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + assert.strictEqual(new URL(tabs[1].url).pathname, '/hello'); + assert.strictEqual(tabs[1].openerTabId, tabs[0].id); + }); + }); + + it('should show hints of links in area', async () => { + let page = await Page.navigateTo(webdriver, server.url('/area')); + await page.sendKeys(Key.SHIFT, 'f'); + + let hints = await page.waitAndGetHints(); + assert.strictEqual(hints.length, 3); + }); + + it('should shows hints only in viewport', async () => { + let page = await Page.navigateTo(webdriver, server.url('/test1')); + await page.sendKeys(Key.SHIFT, 'f'); + + let hints = await page.waitAndGetHints(); + assert.strictEqual(hints.length, 1); + }); + + it('should shows hints only in window of the frame', async () => { + let page = await Page.navigateTo(webdriver, server.url('/test2')); + await page.sendKeys(Key.SHIFT, 'f'); + + await webdriver.switchTo().frame(0); + let hints = await page.waitAndGetHints(); + assert.strictEqual(hints.length, 1); + }); + + it('should shows hints only in the frame', async () => { + let page = await Page.navigateTo(webdriver, server.url('/test3')); + await page.sendKeys(Key.SHIFT, 'f'); + + await webdriver.switchTo().frame(0); + let hints = await page.waitAndGetHints(); + assert.strictEqual(hints.length, 1); + }); +}); diff --git a/e2e/follow_properties.test.js b/e2e/follow_properties.test.js deleted file mode 100644 index 223923e..0000000 --- a/e2e/follow_properties.test.js +++ /dev/null @@ -1,182 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); -const Console = require('./lib/Console'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body> - <a href="/">link1</a> - <a href="/">link2</a> - <a href="/">link3</a> - <a href="/">link4</a> - <a href="/">link5</a> - </body> -</html">`); - }); - return app; -}; - -const waitForHints = async(session) => { - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert(hints.length > 0); - }); -}; - -describe('follow properties test', () => { - - const port = 12321; - let http; - let firefox; - let session; - let browser; - let body; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - }, - }); - session = firefox.session; - browser = firefox.browser; - - await browser.storage.local.set({ settings: { - source: 'json', - json: `{ - "keymaps": { - ":": { "type": "command.show" }, - "f": { "type": "follow.start", "newTab": false }, - "F": { "type": "follow.start", "newTab": true, "background": false }, - "<C-F>": { "type": "follow.start", "newTab": true, "background": true } - }, - "search": { - "default": "google", - "engines": { "google": "https://google.com/search?q={}" } - }, - "properties": { - "hintchars": "jk" - } - }`, - }}); - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}/`); - body = await session.findElementByCSS('body'); - }); - - afterEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - }); - - it('should show hints with hintchars by settings', async () => { - await body.sendKeys('f'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 5); - - assert.equal(await hints[0].getText(), 'J'); - assert.equal(await hints[1].getText(), 'K'); - assert.equal(await hints[2].getText(), 'JJ'); - assert.equal(await hints[3].getText(), 'JK'); - assert.equal(await hints[4].getText(), 'KJ'); - }); - - await body.sendKeys('j'); - - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - - assert.equal(await hints[0].getStyle('display'), 'block'); - assert.equal(await hints[1].getStyle('display'), 'none'); - assert.equal(await hints[2].getStyle('display'), 'block'); - assert.equal(await hints[3].getStyle('display'), 'block'); - assert.equal(await hints[4].getStyle('display'), 'none'); - }); - }); - - it('should open tab in background by background:false', async () => { - await body.sendKeys(Key.Shift, 'f'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 5); - }); - await body.sendKeys('jj'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs[0].active, false); - assert.equal(tabs[1].active, true); - }); - }); - - it('should open tab in background by background:true', async () => { - await body.sendKeys(Key.Control, 'f'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 5); - }); - await body.sendKeys('jj'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs[0].active, true); - assert.equal(tabs[1].active, false); - }); - }); - - it('should show hints with hintchars by settings', async () => { - let c = new Console(session); - - await body.sendKeys(':'); - await session.switchToFrame(0); - await c.sendKeys('set hintchars=abc', Key.Enter); - await session.switchToParentFrame(); - - await body.sendKeys('f'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - assert.equal(hints.length, 5); - - assert.equal(await hints[0].getText(), 'A'); - assert.equal(await hints[1].getText(), 'B'); - assert.equal(await hints[2].getText(), 'C'); - assert.equal(await hints[3].getText(), 'AA'); - assert.equal(await hints[4].getText(), 'AB'); - }); - - await body.sendKeys('a'); - await eventually(async() => { - let hints = await session.findElementsByCSS('.vimvixen-hint'); - - assert.equal(await hints[0].getStyle('display'), 'block'); - assert.equal(await hints[1].getStyle('display'), 'none'); - assert.equal(await hints[2].getStyle('display'), 'none'); - assert.equal(await hints[3].getStyle('display'), 'block'); - assert.equal(await hints[4].getStyle('display'), 'block'); - }); - }); -}); diff --git a/e2e/follow_properties.test.ts b/e2e/follow_properties.test.ts new file mode 100644 index 0000000..75a1d77 --- /dev/null +++ b/e2e/follow_properties.test.ts @@ -0,0 +1,142 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe('follow properties test', () => { + let server = new TestServer().receiveContent('/', ` + <!DOCTYPE html> + <html lang="en"><body> + <a href="/">link1</a> + <a href="/">link2</a> + <a href="/">link3</a> + <a href="/">link4</a> + <a href="/">link5</a> + </body></html">`); + + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await browser.storage.local.set({ settings: { + source: 'json', + json: `{ + "keymaps": { + ":": { "type": "command.show" }, + "f": { "type": "follow.start", "newTab": false }, + "F": { "type": "follow.start", "newTab": true, "background": false }, + "<C-F>": { "type": "follow.start", "newTab": true, "background": true } + }, + "search": { + "default": "google", + "engines": { "google": "https://google.com/search?q={}" } + }, + "properties": { + "hintchars": "jk" + } + }`, + }}); + + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + page = await Page.navigateTo(webdriver, server.url()); + }); + + afterEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + }); + + it('should show hints with hintchars by settings', async () => { + await page.sendKeys('f'); + + let hints = await page.waitAndGetHints(); + assert.strictEqual(hints.length, 5); + + assert.strictEqual(hints[0].text, 'J'); + assert.strictEqual(hints[1].text, 'K'); + assert.strictEqual(hints[2].text, 'JJ'); + assert.strictEqual(hints[3].text, 'JK'); + assert.strictEqual(hints[4].text, 'KJ'); + + await page.sendKeys('j'); + hints = await page.waitAndGetHints(); + + assert.strictEqual(hints[0].displayed, true); + assert.strictEqual(hints[1].displayed, false); + assert.strictEqual(hints[2].displayed, true); + assert.strictEqual(hints[3].displayed, true); + assert.strictEqual(hints[4].displayed, false); + }); + + it('should open tab in background by background:false', async () => { + await page.sendKeys(Key.SHIFT, 'f'); + await page.waitAndGetHints(); + await page.sendKeys('jj'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs[0].active, false); + assert.strictEqual(tabs[1].active, true); + }); + }); + + it('should open tab in background by background:true', async () => { + await page.sendKeys(Key.CONTROL, 'f'); + await page.waitAndGetHints(); + await page.sendKeys('jj'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs[0].active, true); + assert.strictEqual(tabs[1].active, false); + }); + }); + + it('should show hints with hintchars by settings', async () => { + let console = await page.showConsole(); + await console.execCommand('set hintchars=abc'); + await (webdriver.switchTo() as any).parentFrame(); + + await page.sendKeys('f'); + let hints = await page.waitAndGetHints(); + assert.strictEqual(hints.length, 5); + assert.strictEqual(hints[0].text, 'A'); + assert.strictEqual(hints[1].text, 'B'); + assert.strictEqual(hints[2].text, 'C'); + assert.strictEqual(hints[3].text, 'AA'); + assert.strictEqual(hints[4].text, 'AB'); + + await page.sendKeys('a'); + hints = await page.waitAndGetHints(); + assert.strictEqual(hints[0].displayed, true); + assert.strictEqual(hints[1].displayed, false); + assert.strictEqual(hints[2].displayed, false); + assert.strictEqual(hints[3].displayed, true); + assert.strictEqual(hints[4].displayed, true); + }); +}); diff --git a/e2e/lib/Console.js b/e2e/lib/Console.js deleted file mode 100644 index 3a39b64..0000000 --- a/e2e/lib/Console.js +++ /dev/null @@ -1,41 +0,0 @@ -class Console { - constructor(session) { - this.session = session; - } - - async sendKeys(...keys) { - let input = await this.session.findElementByCSS('input'); - input.sendKeys(...keys); - } - - async currentValue() { - return await this.session.executeScript(() => { - let input = document.querySelector('input'); - return input.value; - }); - } - - async getCompletions() { - return await this.session.executeScript(() => { - let items = document.querySelectorAll('.vimvixen-console-completion > li'); - if (items.length === 0) { - throw new Error('completion items not found'); - } - - let objs = []; - for (let li of items) { - if (li.classList.contains('vimvixen-console-completion-title')) { - objs.push({ type: 'title', text: li.textContent.trim() }); - } else if ('vimvixen-console-completion-item') { - let highlight = li.classList.contains('vimvixen-completion-selected'); - objs.push({ type: 'item', text: li.textContent.trim(), highlight }); - } else { - throw new Error(`unexpected class: ${li.className}`); - } - } - return objs; - }); - } -} - -module.exports = Console; diff --git a/e2e/lib/Console.ts b/e2e/lib/Console.ts new file mode 100644 index 0000000..233bf48 --- /dev/null +++ b/e2e/lib/Console.ts @@ -0,0 +1,72 @@ +import { WebDriver, By, Key } from 'selenium-webdriver'; + +export type CompletionItem = { + type: string; + text: string; + highlight: boolean; +} + +export class Console { + constructor(private webdriver: WebDriver) { + } + + async sendKeys(...keys: string[]) { + let input = await this.webdriver.findElement(By.css('input')); + input.sendKeys(...keys); + } + + async currentValue() { + return await this.webdriver.executeScript(() => { + let input = document.querySelector('input'); + if (input === null) { + throw new Error('could not find input element'); + } + return input.value; + }); + } + + async execCommand(command: string): Promise<void> { + let input = await this.webdriver.findElement(By.css('input.vimvixen-console-command-input')); + await input.sendKeys(command, Key.ENTER); + } + + async getErrorMessage(): Promise<string> { + let p = await this.webdriver.findElement(By.css('.vimvixen-console-error')); + return p.getText(); + } + + async inputKeys(...keys: string[]) { + let input = await this.webdriver.findElement(By.css('input')); + await input.sendKeys(...keys); + } + + getCompletions(): Promise<CompletionItem[]> { + return this.webdriver.executeScript(() => { + let items = document.querySelectorAll('.vimvixen-console-completion > li'); + if (items.length === 0) { + throw new Error('completion items not found'); + } + + let objs = []; + for (let li of Array.from(items)) { + if (li.classList.contains('vimvixen-console-completion-title')) { + objs.push({ type: 'title', text: li.textContent!!.trim() }); + } else if ('vimvixen-console-completion-item') { + let highlight = li.classList.contains('vimvixen-completion-selected'); + objs.push({ type: 'item', text: li.textContent!!.trim(), highlight }); + } else { + throw new Error(`unexpected class: ${li.className}`); + } + } + return objs; + }); + } + + async close(): Promise<void> { + let input = await this.webdriver.findElement(By.css('input')); + await input.sendKeys(Key.ESCAPE); + // TODO remove sleep + await new Promise(resolve => setTimeout(resolve, 100)); + await (this.webdriver.switchTo() as any).parentFrame(); + } +} diff --git a/e2e/lib/FormOptionPage.ts b/e2e/lib/FormOptionPage.ts new file mode 100644 index 0000000..c49a44f --- /dev/null +++ b/e2e/lib/FormOptionPage.ts @@ -0,0 +1,68 @@ +import { Lanthan } from 'lanthan'; +import { WebDriver, By, until } from 'selenium-webdriver'; + +export default class FormOptionPage { + private webdriver: WebDriver; + + constructor(lanthan: Lanthan) { + this.webdriver = lanthan.getWebDriver(); + } + + async setBlacklist(nth: number, value: string): Promise<void> { + let selector = '.form-blacklist-form-row > .column-url'; + let inputs = await this.webdriver.findElements(By.css(selector)); + if (inputs.length <= nth) { + throw new RangeError('Index out of range to set a blacklist') + } + await inputs[nth].sendKeys(value); + await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); + } + + async setSearchEngine(nth: number, name: string, url: string) { + let selector = '.form-search-form-row > .column-name'; + let inputs = await this.webdriver.findElements(By.css(selector)); + if (inputs.length <= nth) { + throw new RangeError('Index out of range to set a search engine') + } + await inputs[nth].sendKeys(name); + await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); + + selector = '.form-search-form-row > .column-url'; + inputs = await this.webdriver.findElements(By.css(selector)); + if (inputs.length <= nth) { + throw new RangeError('Index out of range to set a search engine') + } + await inputs[nth].sendKeys(url); + await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); + } + + async addBlacklist(): Promise<void> { + let rows = await this.webdriver.findElements(By.css(`.form-blacklist-form-row`)); + let button = await this.webdriver.findElement(By.css('.form-blacklist-form .ui-add-button')) + await button.click(); + await this.webdriver.wait(until.elementLocated(By.css(`.form-blacklist-form-row:nth-child(${rows.length + 1})`))); + } + + async removeBlackList(nth: number): Promise<void> { + let buttons = await this.webdriver.findElements(By.css('.form-blacklist-form-row .ui-delete-button')); + if (buttons.length <= nth) { + throw new RangeError('Index out of range to remove blacklist') + } + await buttons[nth].click() + } + + async addSearchEngine(): Promise<void> { + let rows = await this.webdriver.findElements(By.css(`.form-search-form-row > .column-name`)); + let button = await this.webdriver.findElement(By.css('.form-search-form > .ui-add-button')) + await button.click(); + await this.webdriver.wait(until.elementLocated(By.css(`.form-search-form-row:nth-child(${rows.length + 1})`))); + } + + async setDefaultSearchEngine(nth: number): Promise<void> { + let radios = await this.webdriver.findElements(By.css('.form-search-form-row input[type=radio]')); + if (radios.length <= nth) { + throw new RangeError('Index out of range to set a default search engine'); + } + await radios[nth].click(); + } +} diff --git a/e2e/lib/JSONOptionPage.ts b/e2e/lib/JSONOptionPage.ts new file mode 100644 index 0000000..ac1ae3d --- /dev/null +++ b/e2e/lib/JSONOptionPage.ts @@ -0,0 +1,22 @@ +import { Lanthan } from 'lanthan'; +import { WebDriver, By } from 'selenium-webdriver'; + +export default class JSONOptionPage { + private webdriver: WebDriver; + + constructor(lanthan: Lanthan) { + this.webdriver = lanthan.getWebDriver(); + } + + async updateSettings(value: string): Promise<void> { + let textarea = await this.webdriver.findElement(By.css('textarea')); + await this.webdriver.executeScript(`document.querySelector('textarea').value = '${value}'`) + await textarea.sendKeys(' '); + await this.webdriver.executeScript(() => document.querySelector('textarea')!!.blur()); + } + + async getErrorMessage(): Promise<string> { + let error = await this.webdriver.findElement(By.css('.settings-ui-input-error')); + return error.getText(); + } +} diff --git a/e2e/lib/OptionPage.ts b/e2e/lib/OptionPage.ts new file mode 100644 index 0000000..c183b06 --- /dev/null +++ b/e2e/lib/OptionPage.ts @@ -0,0 +1,39 @@ +import { Lanthan } from 'lanthan'; +import { WebDriver, By } from 'selenium-webdriver'; +import JSONOptionPage from './JSONOptionPage'; +import FormOptionPage from './FormOptionPage'; + +export default class OptionPage { + private webdriver: WebDriver; + + constructor(private lanthan: Lanthan) { + this.webdriver = lanthan.getWebDriver(); + } + + static async open(lanthan: Lanthan) { + let url = await lanthan.getWebExtBrowser().runtime.getURL("build/settings.html") + await lanthan.getWebDriver().navigate().to(url); + return new OptionPage(lanthan); + } + + async switchToForm(): Promise<FormOptionPage> { + let useFormInput = await this.webdriver.findElement(By.css('#setting-source-form')); + await useFormInput.click(); + await this.webdriver.switchTo().alert().accept(); + return new FormOptionPage(this.lanthan); + } + + async asFormOptionPage(): Promise<FormOptionPage> { + // TODO validate current page + return new FormOptionPage(this.lanthan); + } + + async asJSONOptionPage(): Promise<JSONOptionPage> { + // TODO validate current page + return new JSONOptionPage(this.lanthan); + } + + scrollTo(x: number, y: number): Promise<void> { + return this.webdriver.executeScript(`window.scrollTo(${x}, ${y})`); + } +} diff --git a/e2e/lib/Page.ts b/e2e/lib/Page.ts new file mode 100644 index 0000000..7a5dd7a --- /dev/null +++ b/e2e/lib/Page.ts @@ -0,0 +1,93 @@ +import { WebDriver, By, until } from 'selenium-webdriver'; +import { Console } from './Console'; + +type Hint = { + displayed: boolean, + text: string, +}; + +export default class Page { + private constructor(private webdriver: WebDriver) { + } + + static async currentContext(webdriver: WebDriver): Promise<Page> { + await Page.waitForConsoleLoaded(webdriver); + return new Page(webdriver); + } + + static async navigateTo(webdriver: WebDriver, url: string): Promise<Page> { + await webdriver.navigate().to(url); + await Page.waitForConsoleLoaded(webdriver); + return new Page(webdriver); + } + + async sendKeys(...keys: Array<string|number|Promise<string|number>>): Promise<void> { + let body = await this.webdriver.findElement(By.css('body')); + await body.sendKeys(...keys); + } + + async navigateTo(url: string): Promise<Page> { + await this.webdriver.navigate().to(url); + await Page.waitForConsoleLoaded(this.webdriver); + return new Page(this.webdriver); + } + + async showConsole(): Promise<Console> { + let iframe = this.webdriver.findElement(By.css('#vimvixen-console-frame')); + + await this.sendKeys(':'); + await this.webdriver.wait(until.elementIsVisible(iframe)); + await this.webdriver.switchTo().frame(0); + await this.webdriver.wait(until.elementLocated(By.css('input.vimvixen-console-command-input'))); + return new Console(this.webdriver); + } + + async getConsole(): Promise<Console> { + let iframe = this.webdriver.findElement(By.css('#vimvixen-console-frame')); + + await this.webdriver.wait(until.elementIsVisible(iframe)); + await this.webdriver.switchTo().frame(0); + return new Console(this.webdriver); + } + + async getScrollX(): Promise<number> { + return await this.webdriver.executeScript(() => window.pageXOffset); + } + + getScrollY(): Promise<number> { + return this.webdriver.executeScript(() => window.pageYOffset); + } + + scrollTo(x: number, y: number): Promise<void> { + return this.webdriver.executeScript(`window.scrollTo(${x}, ${y})`); + } + + pageHeight(): Promise<number> { + return this.webdriver.executeScript(() => window.document.documentElement.clientHeight); + } + + async waitAndGetHints(): Promise<Hint[]> { + await this.webdriver.wait(until.elementsLocated(By.css('.vimvixen-hint'))); + + let elements = await this.webdriver.findElements(By.css(`.vimvixen-hint`)); + let hints = []; + for (let e of elements) { + let display = await e.getCssValue('display'); + let text = await e.getText(); + hints.push({ + displayed: display !== 'none', + text: text, + }); + } + return hints; + } + + private static async waitForConsoleLoaded(webdriver: WebDriver) { + let topFrame = await webdriver.executeScript(() => window.top === window); + if (!topFrame) { + return; + } + await webdriver.wait(until.elementLocated(By.css('iframe.vimvixen-console-frame'))); + await new Promise(resolve => setTimeout(resolve, 100)); + } +} diff --git a/e2e/lib/TestServer.ts b/e2e/lib/TestServer.ts new file mode 100644 index 0000000..c010e37 --- /dev/null +++ b/e2e/lib/TestServer.ts @@ -0,0 +1,64 @@ +import * as http from 'http'; +import * as net from 'net' +import express from 'express'; + +type HandlerFunc = (req: express.Request, res: express.Response) => void; + +export default class TestServer { + private http?: http.Server; + + private app: express.Application; + + constructor( + private port = 0, + private address = '127.0.0.1', + ){ + this.app = express(); + } + + handle(path: string, f: HandlerFunc): TestServer { + this.app.get(path, f); + return this; + } + + receiveContent(path: string, content: string): TestServer { + this.app.get(path, (_req: express.Request, res: express.Response) => { + res.status(200).send(content) + }); + return this; + } + + url(path: string = '/'): string { + if (!this.http) { + throw new Error('http server not started'); + } + + let addr = this.http.address() as net.AddressInfo; + return `http://${addr.address}:${addr.port}${path}` + } + + start(): Promise<void> { + if (this.http) { + throw new Error('http server already started'); + } + + this.http = http.createServer(this.app) + return new Promise((resolve) => { + this.http!!.listen(this.port, this.address, () => { + resolve(); + }) + }); + } + + stop(): Promise<void> { + if (!this.http) { + return Promise.resolve(); + } + return new Promise((resolve) => { + this.http!!.close(() => { + this.http = undefined; + resolve(); + }); + }) + } +} diff --git a/e2e/lib/clipboard.js b/e2e/lib/clipboard.js deleted file mode 100644 index 4061dbd..0000000 --- a/e2e/lib/clipboard.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -const { spawn } = require('child_process'); - -const readLinux = () => { - let stdout = '', stderr = ''; - return new Promise((resolve, reject) => { - let xsel = spawn('xsel', ['--clipboard', '--output']); - xsel.stdout.on('data', (data) => { - stdout += data; - }); - xsel.stderr.on('data', (data) => { - stderr += data; - }); - xsel.on('close', (code) => { - if (code !== 0) { - throw new Error(`xsel returns ${code}: ${stderr}`) - } - resolve(stdout); - }); - }); -}; - -const writeLinux = (data) => { - let stdout = '', stderr = ''; - return new Promise((resolve, reject) => { - let xsel = spawn('xsel', ['--clipboard', '--input']); - xsel.stderr.on('data', (data) => { - stderr += data; - }); - xsel.on('close', (code) => { - if (code !== 0) { - throw new Error(`xsel returns ${code}: ${stderr}`) - } - resolve(); - }); - xsel.stdin.write(data); - xsel.stdin.end(); - }); -}; - -const unsupported = (os) => { - return () => { - throw new Error(`Unsupported os: ${os}`); - }; -}; - -const detect = () => { - switch (process.platform) { - case 'linux': - return { - read: readLinux, - write: writeLinux, - }; - default: - return { - read: unsupported(process.platform), - write: unsupported(process.platform), - }; - } -} - -module.exports = detect(); diff --git a/e2e/lib/clipboard.ts b/e2e/lib/clipboard.ts new file mode 100644 index 0000000..c1eddbb --- /dev/null +++ b/e2e/lib/clipboard.ts @@ -0,0 +1,107 @@ +import { spawn } from 'child_process'; + +const readLinux = (): Promise<string> => { + let stdout = '', stderr = ''; + return new Promise((resolve) => { + let xsel = spawn('xsel', ['--clipboard', '--output']); + xsel.stdout.on('data', (data) => { + stdout += data; + }); + xsel.stderr.on('data', (data) => { + stderr += data; + }); + xsel.on('close', (code) => { + if (code !== 0) { + throw new Error(`xsel returns ${code}: ${stderr}`) + } + resolve(stdout); + }); + }); +}; + +const writeLinux = (data: string): Promise<string> => { + let stderr = ''; + return new Promise((resolve) => { + let xsel = spawn('xsel', ['--clipboard', '--input']); + xsel.stderr.on('data', (data) => { + stderr += data; + }); + xsel.on('close', (code) => { + if (code !== 0) { + throw new Error(`xsel returns ${code}: ${stderr}`) + } + resolve(); + }); + xsel.stdin.write(data); + xsel.stdin.end(); + }); +}; + +const readDarwin = (): Promise<string> => { + let stdout = '', stderr = ''; + return new Promise((resolve) => { + let pbpaste = spawn('pbpaste'); + pbpaste.stdout.on('data', (data) => { + stdout += data; + }); + pbpaste.stderr.on('data', (data) => { + stderr += data; + }); + pbpaste.on('close', (code) => { + if (code !== 0) { + throw new Error(`pbpaste returns ${code}: ${stderr}`) + } + resolve(stdout); + }); + }); +}; + +const writeDarwin = (data: string): Promise<string> => { + let stderr = ''; + return new Promise((resolve) => { + let pbcopy = spawn('pbcopy'); + pbcopy.stderr.on('data', (data) => { + stderr += data; + }); + pbcopy.on('close', (code) => { + if (code !== 0) { + throw new Error(`pbcopy returns ${code}: ${stderr}`) + } + resolve(); + }); + pbcopy.stdin.write(data); + pbcopy.stdin.end(); + }); +}; + +class UnsupportedError extends Error { + constructor(platform: string) { + super(); + this.message = `Unsupported platform: ${platform}`; + } +} + +const read = () => { + switch (process.platform) { + case 'linux': + return readLinux(); + case 'darwin': + return readDarwin(); + } + throw new UnsupportedError(process.platform); +} + +const write = (data: string) => { + switch (process.platform) { + case 'linux': + return writeLinux(data); + case 'darwin': + return writeDarwin(data); + } + throw new UnsupportedError(process.platform); +} + +export { + read, + write, +}; diff --git a/e2e/mark.test.js b/e2e/mark.test.js deleted file mode 100644 index 8716c1e..0000000 --- a/e2e/mark.test.js +++ /dev/null @@ -1,121 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body style="width:10000px; height:10000px"></body> -</html">`); - }); - return app; -}; - -describe("mark test", () => { - - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - it('should set a local mark and jump to it', async () => { - await session.navigateTo(`http://127.0.0.1:${port}`); - let body = await session.findElementByCSS('body'); - - await session.executeScript(() => window.scrollTo(200, 200)); - await body.sendKeys('m', 'a'); - await session.executeScript(() => window.scrollTo(500, 500)); - await body.sendKeys('\'', 'a'); - - await eventually(async() => { - let pageXOffset = await session.executeScript(() => window.pageXOffset); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageXOffset, 200); - assert.equal(pageYOffset, 200); - }); - }); - - it('should set a global mark and jump to it', async () => { - await session.navigateTo(`http://127.0.0.1:${port}#first`); - let body = await session.findElementByCSS('body'); - - await session.executeScript(() => window.scrollTo(200, 200)); - await body.sendKeys('m', 'A'); - await session.executeScript(() => window.scrollTo(500, 500)); - await body.sendKeys('\'', 'A'); - - await eventually(async() => { - let pageXOffset = await session.executeScript(() => window.pageXOffset); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageXOffset, 200); - assert.equal(pageYOffset, 200); - }); - - await browser.tabs.create({ url: `http://127.0.0.1:${port}#second` }); - body = await session.findElementByCSS('body'); - await body.sendKeys('\'', 'A'); - - await eventually(async() => { - let tab = (await browser.tabs.query({ active: true }))[0]; - let url = new URL(tab.url); - assert.equal(url.hash, '#first'); - - let pageXOffset = await session.executeScript(() => window.pageXOffset); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageXOffset, 200); - assert.equal(pageYOffset, 200); - }); - }); - - it('set a global mark and creates new tab from gone', async () => { - await session.navigateTo(`http://127.0.0.1:${port}#first`); - await session.executeScript(() => window.scrollTo(500, 500)); - let body = await session.findElementByCSS('body'); - await body.sendKeys('m', 'A'); - - let tab = (await browser.tabs.query({ active: true }))[0]; - await browser.tabs.create({ url: `http://127.0.0.1:${port}#second` }); - await browser.tabs.remove(tab.id); - - let handles; - await eventually(async() => { - handles = await session.getWindowHandles(); - assert.equal(handles.length, 2); - }); - await session.switchToWindow(handles[0]); - await session.navigateTo(`http://127.0.0.1:${port}#second`); - body = await session.findElementByCSS('body'); - await body.sendKeys('\'', 'A'); - - await eventually(async() => { - let tab = (await browser.tabs.query({ active: true }))[0]; - let url = new URL(tab.url); - assert.equal(url.hash, '#first'); - }); - }); -}); - - diff --git a/e2e/mark.test.ts b/e2e/mark.test.ts new file mode 100644 index 0000000..57a8fa6 --- /dev/null +++ b/e2e/mark.test.ts @@ -0,0 +1,102 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("mark test", () => { + let server = new TestServer().receiveContent('/', + `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html">`, + ); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await server.start() + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + it('should set a local mark and jump to it', async () => { + let page = await Page.navigateTo(webdriver, server.url()); + await page.scrollTo(200, 200); + await page.sendKeys('m', 'a'); + await page.scrollTo(500, 500); + await page.sendKeys('\'', 'a'); + + await eventually(async() => { + assert.strictEqual(await page.getScrollX(), 200); + assert.strictEqual(await page.getScrollY(), 200); + }); + }); + + it('should set a global mark and jump to it', async () => { + let page = await Page.navigateTo(webdriver, server.url('/#first')); + await page.scrollTo(200, 200); + await page.sendKeys('m', 'A'); + await page.scrollTo(500, 500); + await page.sendKeys('\'', 'A'); + + await eventually(async() => { + assert.strictEqual(await page.getScrollX(), 200); + assert.strictEqual(await page.getScrollY(), 200); + }); + + await browser.tabs.create({ url: server.url('/#second') }); + page = await Page.currentContext(webdriver); + await page.sendKeys('\'', 'A'); + + await eventually(async() => { + let tab = (await browser.tabs.query({ active: true }))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.hash, '#first'); + + assert.strictEqual(await page.getScrollX(), 200); + assert.strictEqual(await page.getScrollY(), 200); + }); + }); + + it('set a global mark and creates new tab from gone', async () => { + let page = await Page.navigateTo(webdriver, server.url('/#first')); + await page.scrollTo(500, 500); + await page.sendKeys('m', 'A'); + + let tab = (await browser.tabs.query({ active: true }))[0]; + await browser.tabs.create({ url: server.url('/#second') }); + await browser.tabs.remove(tab.id); + + let handles: string[]; + await eventually(async() => { + handles = await webdriver.getAllWindowHandles(); + assert.strictEqual(handles.length, 2); + }); + await webdriver.switchTo().window(handles!![0]); + + page = await Page.navigateTo(webdriver, server.url('/#second')); + await page.sendKeys('\'', 'A'); + + await eventually(async() => { + let tab = (await browser.tabs.query({ active: true }))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.hash, '#first'); + }); + }); +}); + + diff --git a/e2e/navigate.test.js b/e2e/navigate.test.js deleted file mode 100644 index 17552e5..0000000 --- a/e2e/navigate.test.js +++ /dev/null @@ -1,274 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/pagenation-a/:page', (req, res) => { - res.status(200).send(` -<html lang="en"> - <a href="/pagenation-a/${Number(req.params.page) - 1}">prev</a> - <a href="/pagenation-a/${Number(req.params.page) + 1}">next</a> -</html">`); - }); - app.get('/pagenation-link/:page', (req, res) => { - res.status(200).send(` -<html lang="en"> - <head> - <link rel="prev" href="/pagenation-link/${Number(req.params.page) - 1}"></link> - <link rel="next" href="/pagenation-link/${Number(req.params.page) + 1}"></link> - </head> -</html">`); - }); - app.get('/reload', (req, res) => { - res.status(200).send(` -<html lang="en"> - <head> - <script>window.location.hash = Date.now()</script> - </head> - <body style="width:10000px; height:10000px"></body> -</html">`); - }); - - app.get('/*', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - ${req.path} -</html">`); - }); - return app; -}; - -describe("navigate test", () => { - - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - prefs: { - 'browser.startup.homepage': `http://127.0.0.1:${port}#home`, - } - }); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - }) - - it('should go to parent path without hash by gu', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/a/b/c`); - let body = await session.findElementByCSS('body'); - - await body.sendKeys('g', 'u'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, `/a/b/`) - }); - }); - - it('should remove hash by gu', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/a/b/c#hash`); - let body = await session.findElementByCSS('body'); - - await body.sendKeys('g', 'u'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.hash, '') - assert.equal(url.pathname, `/a/b/c`) - }); - }); - - it('should go to root path by gU', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/a/b/c#hash`); - let body = await session.findElementByCSS('body'); - - await body.sendKeys('g', Key.Shift, 'u'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, `/`) - }); - }); - - it('should go back and forward in history by H and L', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/first`); - await session.navigateTo(`http://127.0.0.1:${port}/second`); - let body = await session.findElementByCSS('body'); - - await body.sendKeys(Key.Shift, 'h'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, `/first`) - }); - - body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'l'); - - await eventually(async() => { - tab = (await browser.tabs.query({}))[0]; - url = new URL(tab.url); - assert.equal(url.pathname, `/second`) - }); - }); - - it('should go previous and next page in <a> by [[ and ]]', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/pagenation-a/10`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('[', '['); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, '/pagenation-a/9'); - }); - }); - - it('should go next page in <a> by ]]', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/pagenation-a/10`); - let body = await session.findElementByCSS('body'); - await body.sendKeys(']', ']'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, '/pagenation-a/11'); - }); - }); - - it('should go previous page in <link> by ]]', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/pagenation-link/10`); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('[', '['); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, '/pagenation-link/9'); - }); - }); - - it('should go next page by in <link> by [[', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/pagenation-link/10`); - let body = await session.findElementByCSS('body'); - await body.sendKeys(']', ']'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.pathname, '/pagenation-link/11'); - }); - }); - - it('should go to home page into current tab by gh', async () => { - await session.navigateTo(`http://127.0.0.1:${port}`); - let body = await session.findElementByCSS('body'); - await body.sendKeys('g', 'h'); - - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - let url = new URL(tab.url); - assert.equal(url.hash, '#home'); - }); - }); - - it('should go to home page into current tab by gH', async () => { - await session.navigateTo(`http://127.0.0.1:${port}`); - let body = await session.findElementByCSS('body'); - await body.sendKeys('g', Key.Shift, 'H'); - - await eventually(async() => { - let tabs = await browser.tabs.query({}); - assert.equal(tabs.length, 2); - assert.equal(new URL(tabs[0].url).hash, ''); - assert.equal(new URL(tabs[1].url).hash, '#home'); - assert.equal(tabs[1].active, true); - }); - }); - - it('should reload current tab by r', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/reload`); - await session.executeScript(() => window.scrollTo(500, 500)); - let before - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - before = Number(new URL(tab.url).hash.split('#')[1]); - assert(before > 0); - }); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('r'); - - let after - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - after = Number(new URL(tab.url).hash.split('#')[1]); - assert(after > before); - }); - - await eventually(async() => { - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 500); - }); - }); - - it('should reload current tab without cache by R', async () => { - await session.navigateTo(`http://127.0.0.1:${port}/reload`); - await session.executeScript(() => window.scrollTo(500, 500)); - let before - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - before = Number(new URL(tab.url).hash.split('#')[1]); - assert(before > 0); - }); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'R'); - - let after - await eventually(async() => { - let tab = (await browser.tabs.query({}))[0]; - after = Number(new URL(tab.url).hash.split('#')[1]); - assert(after > before); - }); - - // assert that the page offset is reset to 0, and 'eventually' is timed-out. - await assert.rejects(async () => { - await eventually(async() => { - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 500); - }); - }); - }); -}); diff --git a/e2e/navigate.test.ts b/e2e/navigate.test.ts new file mode 100644 index 0000000..8ee209b --- /dev/null +++ b/e2e/navigate.test.ts @@ -0,0 +1,254 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import { Options as FirefoxOptions } from 'selenium-webdriver/firefox'; +import Page from './lib/Page'; + +const newApp = () => { + let server = new TestServer(); + server.handle('/pagenation-a/:page', (req, res) => { + res.status(200).send(` + <!DOCTYPE html> + <html lang="en"> + <a href="/pagenation-a/${Number(req.params.page) - 1}">prev</a> + <a href="/pagenation-a/${Number(req.params.page) + 1}">next</a> + </html">`); + }); + + server.handle('/pagenation-link/:page', (req, res) => { + res.status(200).send(` + <!DOCTYPE html> + <html lang="en"> + <head> + <link rel="prev" href="/pagenation-link/${Number(req.params.page) - 1}"></link> + <link rel="next" href="/pagenation-link/${Number(req.params.page) + 1}"></link> + </head> + </html">`); + }); + server.receiveContent('/reload', ` + <!DOCTYPE html> + <html lang="en"> + <head> + <script>window.location.hash = Date.now()</script> + </head> + <body style="width:10000px; height:10000px"></body> + </html">`); + + server.receiveContent('/*', `ok`); + + return server; +}; + +describe("navigate test", () => { + let server = newApp(); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + await server.start(); + + let opts = (new FirefoxOptions() as any) + .setPreference('browser.startup.homepage', server.url('/#home')); + lanthan = await Builder + .forBrowser('firefox') + .setOptions(opts) + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + }) + + it('should go to parent path without hash by gu', async () => { + let page = await Page.navigateTo(webdriver, server.url('/a/b/c')); + await page.sendKeys('g', 'u'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, `/a/b/`) + }); + }); + + it('should remove hash by gu', async () => { + let page = await Page.navigateTo(webdriver, server.url('/a/b/c#hash')); + await page.sendKeys('g', 'u'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.hash, '') + assert.strictEqual(url.pathname, `/a/b/c`) + }); + }); + + it('should go to root path by gU', async () => { + let page = await Page.navigateTo(webdriver, server.url('/a/b/c#hash')); + await page.sendKeys('g', Key.SHIFT, 'u'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, `/`) + }); + }); + + it('should go back and forward in history by H and L', async () => { + let page = await Page.navigateTo(webdriver, server.url('/first')); + await page.navigateTo(server.url('/second')); + await page.sendKeys(Key.SHIFT, 'h'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, `/first`) + }); + + page = await Page.currentContext(webdriver); + page.sendKeys(Key.SHIFT, 'l'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, `/second`) + }); + }); + + it('should go previous and next page in <a> by [[ and ]]', async () => { + let page = await Page.navigateTo(webdriver, server.url('/pagenation-a/10')); + await page.sendKeys('[', '['); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, '/pagenation-a/9'); + }); + }); + + it('should go next page in <a> by ]]', async () => { + let page = await Page.navigateTo(webdriver, server.url('/pagenation-a/10')); + await page.sendKeys(']', ']'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, '/pagenation-a/11'); + }); + }); + + it('should go previous page in <link> by ]]', async () => { + let page = await Page.navigateTo(webdriver, server.url('/pagenation-link/10')); + await page.sendKeys('[', '['); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, '/pagenation-link/9'); + }); + }); + + it('should go next page by in <link> by [[', async () => { + let page = await Page.navigateTo(webdriver, server.url('/pagenation-link/10')); + await page.sendKeys(']', ']'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.pathname, '/pagenation-link/11'); + }); + }); + + it('should go to home page into current tab by gh', async () => { + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys('g', 'h'); + + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + let url = new URL(tab.url); + assert.strictEqual(url.hash, '#home'); + }); + }); + + it('should go to home page into current tab by gH', async () => { + let page = await Page.navigateTo(webdriver, server.url()); + await page.sendKeys('g', Key.SHIFT, 'H'); + + await eventually(async() => { + let tabs = await browser.tabs.query({}); + assert.strictEqual(tabs.length, 2); + assert.strictEqual(new URL(tabs[0].url).hash, ''); + assert.strictEqual(new URL(tabs[1].url).hash, '#home'); + assert.strictEqual(tabs[1].active, true); + }); + }); + + it('should reload current tab by r', async () => { + let page = await Page.navigateTo(webdriver, server.url('/reload')); + await page.scrollTo(500, 500); + + let before: number; + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + before = Number(new URL(tab.url).hash.split('#')[1]); + assert.ok(before > 0); + }); + + await page.sendKeys('r'); + + let after + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + after = Number(new URL(tab.url).hash.split('#')[1]); + assert.ok(after > before); + }); + + await eventually(async() => { + let page = await Page.currentContext(webdriver); + assert.strictEqual(await page.getScrollX(), 500); + }); + }); + + it('should reload current tab without cache by R', async () => { + let page = await Page.navigateTo(webdriver, server.url('/reload')); + await page.scrollTo(500, 500); + + let before: number; + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + before = Number(new URL(tab.url).hash.split('#')[1]); + assert.ok(before > 0); + }); + + await page.sendKeys(Key.SHIFT, 'R'); + + let after + await eventually(async() => { + let tab = (await browser.tabs.query({}))[0]; + after = Number(new URL(tab.url).hash.split('#')[1]); + assert.ok(after > before); + }); + + await eventually(async() => { + let page = await Page.currentContext(webdriver); + assert.strictEqual(await page.getScrollY(), 0); + }); + }); +}); diff --git a/e2e/options.test.js b/e2e/options.test.js deleted file mode 100644 index e8045c2..0000000 --- a/e2e/options.test.js +++ /dev/null @@ -1,99 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body style="width:10000px; height:10000px"></body> -</html">`); - }); - return app; -}; - -describe("options page", () => { - const port = 12321; - let http; - let firefox; - let session; - let browser; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - builder.addFile('build/settings.html'); - }, - }); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - - http.close(); - }); - - beforeEach(async() => { - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - }) - - const updateTextarea = async(value) => { - let textarea = await session.findElementByCSS('textarea'); - await session.executeScript(`document.querySelector('textarea').value = '${value}'`) - await textarea.sendKeys(' '); - await session.executeScript(() => document.querySelector('textarea').blur()); - } - - it('saves current config on blur', async () => { - let url = await browser.runtime.getURL("build/settings.html") - await session.navigateTo(url); - - await updateTextarea(`{ "blacklist": [ "https://example.com" ] }`); - - let { settings } = await browser.storage.local.get('settings'); - assert.equal(settings.source, 'json') - assert.equal(settings.json, '{ "blacklist": [ "https://example.com" ] } ') - - await updateTextarea(`invalid json`); - - settings = (await browser.storage.local.get('settings')).settings; - assert.equal(settings.source, 'json') - assert.equal(settings.json, '{ "blacklist": [ "https://example.com" ] } ') - - let error = await session.findElementByCSS('.settings-ui-input-error'); - let text = await error.getText(); - assert.ok(text.startsWith('SyntaxError:')) - }); - - it('updates keymaps without reloading', async () => { - await browser.tabs.create({ url: `http://127.0.0.1:${port}`, active: false }); - let url = await browser.runtime.getURL("build/settings.html") - await session.navigateTo(url); - - let handles = await session.getWindowHandles(); - await updateTextarea(`{ "keymaps": { "zz": { "type": "scroll.vertically", "count": 10 } } }`); - - await session.switchToWindow(handles[1]); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('zz') - - let y = await session.executeScript(() => window.pageYOffset); - assert.equal(y, 640); - }) -}); diff --git a/e2e/options.test.ts b/e2e/options.test.ts new file mode 100644 index 0000000..8d5023f --- /dev/null +++ b/e2e/options.test.ts @@ -0,0 +1,81 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; +import OptionPage from './lib/OptionPage'; + +describe("options page", () => { + let server = new TestServer().receiveContent('/', + `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html">`, + ); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + + await server.start(); + }); + + after(async() => { + if (lanthan) { + await lanthan.quit(); + } + await server.stop(); + }); + + beforeEach(async() => { + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + }) + + it('saves current config on blur', async () => { + let page = await OptionPage.open(lanthan); + let jsonPage = await page.asJSONOptionPage(); + await jsonPage.updateSettings(`{ "blacklist": [ "https://example.com" ] }`) + + let { settings } = await browser.storage.local.get('settings'); + assert.strictEqual(settings.source, 'json') + assert.strictEqual(settings.json, '{ "blacklist": [ "https://example.com" ] } ') + + await jsonPage.updateSettings(`invalid json`); + + settings = (await browser.storage.local.get('settings')).settings; + assert.strictEqual(settings.source, 'json') + assert.strictEqual(settings.json, '{ "blacklist": [ "https://example.com" ] } ') + + let message = await jsonPage.getErrorMessage(); + assert.ok(message.startsWith('SyntaxError:')) + }); + + it('updates keymaps without reloading', async () => { + let optionPage = await OptionPage.open(lanthan); + let jsonPage = await optionPage.asJSONOptionPage(); + await jsonPage.updateSettings(`{ "keymaps": { "zz": { "type": "scroll.vertically", "count": 10 } } }`); + + await browser.tabs.create({ url: server.url(), active: false }); + await new Promise((resolve) => setTimeout(resolve, 100)); + let handles = await webdriver.getAllWindowHandles(); + await webdriver.switchTo().window(handles[1]); + + let page = await Page.currentContext(webdriver); + await page.sendKeys('zz'); + + await eventually(async() => { + let y = await page.getScrollY(); + assert.strictEqual(y, 640); + }); + }) +}); diff --git a/e2e/options_form.test.js b/e2e/options_form.test.js deleted file mode 100644 index f86d995..0000000 --- a/e2e/options_form.test.js +++ /dev/null @@ -1,125 +0,0 @@ -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); - -describe("options form page", () => { - let firefox; - let session; - let browser; - - beforeEach(async() => { - firefox = await lanthan.firefox({ - spy: path.join(__dirname, '..'), - builderf: (builder) => { - builder.addFile('build/settings.js'); - builder.addFile('build/settings.html'); - }, - }); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - - let tabs = await browser.tabs.query({}); - for (let tab of tabs.slice(1)) { - await browser.tabs.remove(tab.id); - } - }) - - afterEach(async() => { - if (firefox) { - await firefox.close(); - } - }) - - const setBlacklistValue = async(nth, value) => { - let selector = '.form-blacklist-form .column-url'; - let input = (await session.findElementsByCSS(selector))[nth]; - await input.sendKeys(value); - await session.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); - } - - const setSearchEngineValue = async(nth, name, url) => { - let selector = '.form-search-form input.column-name'; - let input = (await session.findElementsByCSS(selector))[nth]; - await input.sendKeys(name); - await session.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); - - selector = '.form-search-form input.column-url'; - input = (await session.findElementsByCSS(selector))[nth]; - await input.sendKeys(url); - await session.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); - } - - it('switch to form settings', async () => { - let url = await browser.runtime.getURL("build/settings.html") - await session.navigateTo(url); - - let useFormInput = await session.findElementByCSS('#setting-source-form'); - await useFormInput.click(); - await session.acceptAlert(); - - let { settings } = await browser.storage.local.get('settings'); - assert.equal(settings.source, 'form') - }) - - it('add blacklist', async () => { - let url = await browser.runtime.getURL("build/settings.html") - await session.navigateTo(url); - - let useFormInput = await session.findElementByCSS('#setting-source-form'); - await useFormInput.click(); - await session.acceptAlert(); - await session.executeScript(() => window.scrollBy(0, 1000)); - - // assert default - let settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.blacklist, []) - - // add blacklist items - let addButton = await session.findElementByCSS('.form-blacklist-form .ui-add-button'); - await addButton.click(); - await setBlacklistValue(0, 'google.com') - - settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.blacklist, ['google.com']) - - await addButton.click(); - await setBlacklistValue(1, 'yahoo.com') - - settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.blacklist, ['google.com', 'yahoo.com']) - - // delete first item - let deleteButton = (await session.findElementsByCSS('.form-blacklist-form .ui-delete-button'))[0]; - await deleteButton.click() - - settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.blacklist, ['yahoo.com']) - }); - - it('add search engines', async () => { - let url = await browser.runtime.getURL("build/settings.html") - await session.navigateTo(url); - - let useFormInput = await session.findElementByCSS('#setting-source-form'); - await useFormInput.click(); - await session.acceptAlert(); - - // assert default - let settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.search.default, 'google'); - - // change default - let radio = (await session.findElementsByCSS('.form-search-form input[type=radio]'))[2]; - await radio.click(); - settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.search.default, 'bing'); - - let addButton = await session.findElementByCSS('.form-search-form .ui-add-button'); - await addButton.click(); - await setSearchEngineValue(6, 'yippy', 'https://www.yippy.com/search?query={}'); - - settings = (await browser.storage.local.get('settings')).settings; - assert.deepEqual(settings.form.search.engines[6], ['yippy', 'https://www.yippy.com/search?query={}']); - }); -}); diff --git a/e2e/options_form.test.ts b/e2e/options_form.test.ts new file mode 100644 index 0000000..af53791 --- /dev/null +++ b/e2e/options_form.test.ts @@ -0,0 +1,86 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import { Builder, Lanthan } from 'lanthan'; +import OptionPage from './lib/OptionPage'; + +describe("options form page", () => { + let lanthan: Lanthan; + let browser: any; + + beforeEach(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + browser = lanthan.getWebExtBrowser(); + + let tabs = await browser.tabs.query({}); + for (let tab of tabs.slice(1)) { + await browser.tabs.remove(tab.id); + } + }) + + afterEach(async() => { + if (lanthan) { + await lanthan.quit(); + } + }) + + it('switch to form settings', async () => { + let page = await OptionPage.open(lanthan); + await page.switchToForm(); + + let { settings } = await browser.storage.local.get('settings'); + assert.strictEqual(settings.source, 'form') + }) + + it('add blacklist', async () => { + let page = await OptionPage.open(lanthan); + let forms = await page.switchToForm(); + // Scroll is required to click a button on Firefox 60 + await page.scrollTo(0, 1000); + + // assert default + let settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.blacklist, []) + + // add blacklist items + await forms.addBlacklist(); + await forms.setBlacklist(0, 'google.com') + + settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.blacklist, ['google.com']) + + await forms.addBlacklist(); + await forms.setBlacklist(1, 'yahoo.com') + + settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.blacklist, ['google.com', 'yahoo.com']) + + // delete first item + await forms.removeBlackList(0); + settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.blacklist, ['yahoo.com']) + }); + + it('add search engines', async () => { + let page = await OptionPage.open(lanthan); + let forms = await page.switchToForm(); + + // assert default + let settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.search.default, 'google'); + + // change default + await forms.setDefaultSearchEngine(2); + settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.search.default, 'bing'); + + await forms.addSearchEngine(); + await forms.setSearchEngine(6, 'yippy', 'https://www.yippy.com/search?query={}'); + + settings = (await browser.storage.local.get('settings')).settings; + assert.deepStrictEqual(settings.form.search.engines[6], ['yippy', 'https://www.yippy.com/search?query={}']); + }); +}); diff --git a/e2e/repeat.test.js b/e2e/repeat.test.js deleted file mode 100644 index 4072005..0000000 --- a/e2e/repeat.test.js +++ /dev/null @@ -1,92 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send('ok'); - }); - return app; -}; - -describe("tab test", () => { - - const port = 12321; - const url = `http://127.0.0.1:${port}/`; - - let http; - let firefox; - let session; - let browser; - let tabs; - - before(async() => { - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - - await session.navigateTo(`${url}`); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - it('repeats last operation', async () => { - let before = await browser.tabs.query({}); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(':'); - - await session.switchToFrame(0); - let input = await session.findElementByCSS('input'); - input.sendKeys(`tabopen ${url}newtab`, Key.Enter); - - await eventually(async() => { - let current = await browser.tabs.query({ url: `*://*/newtab` }); - assert.equal(current.length, 1); - }); - - body = await session.findElementByCSS('body'); - await body.sendKeys('.'); - - await eventually(async() => { - let current = await browser.tabs.query({ url: `*://*/newtab` }); - assert.equal(current.length, 2); - }); - }); - - it('repeats last operation', async () => { - for (let i = 1; i < 5; ++i) { - await browser.tabs.create({ url: `${url}#${i}` }); - } - let before = await browser.tabs.query({}); - - let body = await session.findElementByCSS('body'); - await body.sendKeys('d'); - - await eventually(async() => { - let current = await browser.tabs.query({}); - assert.equal(current.length, before.length - 1); - }); - - await browser.tabs.update(before[2].id, { active: true }); - body = await session.findElementByCSS('body'); - await body.sendKeys('.'); - - await eventually(async() => { - let current = await browser.tabs.query({}); - assert.equal(current.length, before.length - 2); - }); - }); -}); diff --git a/e2e/repeat.test.ts b/e2e/repeat.test.ts new file mode 100644 index 0000000..b62272f --- /dev/null +++ b/e2e/repeat.test.ts @@ -0,0 +1,75 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("tab test", () => { + let server = new TestServer().receiveContent('/*', 'ok'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + it('repeats last command', async () => { + let page = await Page.navigateTo(webdriver, server.url()); + let console = await page.showConsole(); + await console.execCommand(`tabopen ${server.url('/newtab')}`); + + await eventually(async() => { + let current = await browser.tabs.query({ url: `*://*/newtab` }); + assert.strictEqual(current.length, 1); + }); + + page = await Page.currentContext(webdriver); + await page.sendKeys('.'); + + await eventually(async() => { + let current = await browser.tabs.query({ url: `*://*/newtab` }); + assert.strictEqual(current.length, 2); + }); + }); + + it('repeats last operation', async () => { + for (let i = 1; i < 5; ++i) { + await browser.tabs.create({ url: server.url('/#' + i) }); + } + let before = await browser.tabs.query({}); + + let page = await Page.currentContext(webdriver); + await page.sendKeys('d'); + + await eventually(async() => { + let current = await browser.tabs.query({}); + assert.strictEqual(current.length, before.length - 1); + }); + + await browser.tabs.update(before[2].id, { active: true }); + page = await Page.currentContext(webdriver); + await page.sendKeys('.'); + + await eventually(async() => { + let current = await browser.tabs.query({}); + assert.strictEqual(current.length, before.length - 2); + }); + }); +}); diff --git a/e2e/scroll.test.js b/e2e/scroll.test.js deleted file mode 100644 index 0ce3ec6..0000000 --- a/e2e/scroll.test.js +++ /dev/null @@ -1,150 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send(`<!DOCTYPEhtml> -<html lang="en"> - <body style="width:10000px; height:10000px"></body> -</html">`); - }); - return app; -}; - -describe("scroll test", () => { - - const port = 12321; - let http; - let firefox; - let session; - let body; - - before(async() => { - http = newApp().listen(port); - - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - http.close(); - }); - - beforeEach(async() => { - await session.navigateTo(`http://127.0.0.1:${port}`); - body = await session.findElementByCSS('body'); - }); - - - it('scrolls up by k', async () => { - await body.sendKeys('j'); - - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 64); - }); - - it('scrolls down by j', async () => { - await session.executeScript(() => window.scrollTo(0, 200)); - await body.sendKeys('k'); - - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 136); - }); - - it('scrolls left by h', async () => { - await session.executeScript(() => window.scrollTo(100, 100)); - await body.sendKeys('h'); - - let pageXOffset = await session.executeScript(() => window.pageXOffset); - assert.equal(pageXOffset, 36); - }); - - it('scrolls left by l', async () => { - await session.executeScript(() => window.scrollTo(100, 100)); - await body.sendKeys('l'); - - let pageXOffset = await session.executeScript(() => window.pageXOffset); - assert.equal(pageXOffset, 164); - }); - - it('scrolls top by gg', async () => { - await session.executeScript(() => window.scrollTo(0, 100)); - await body.sendKeys('g', 'g'); - - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert.equal(pageYOffset, 0); - }); - - it('scrolls bottom by G', async () => { - await session.executeScript(() => window.scrollTo(0, 100)); - await body.sendKeys(Key.Shift, 'g'); - - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert(pageYOffset > 5000); - }); - - it('scrolls bottom by 0', async () => { - await session.executeScript(() => window.scrollTo(0, 100)); - await body.sendKeys(Key.Shift, '0'); - - let pageXOffset = await session.executeScript(() => window.pageXOffset); - assert(pageXOffset === 0); - }); - - it('scrolls bottom by $', async () => { - await session.executeScript(() => window.scrollTo(0, 100)); - await body.sendKeys(Key.Shift, '$'); - - let pageXOffset = await session.executeScript(() => window.pageXOffset); - assert(pageXOffset > 5000); - }); - - it('scrolls bottom by <C-U>', async () => { - await session.executeScript(() => window.scrollTo(0, 1000)); - await body.sendKeys(Key.Control, 'u'); - - let pageHeight = - await session.executeScript(() => window.document.documentElement.clientHeight); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert(Math.abs(pageYOffset - (1000 - Math.floor(pageHeight / 2))) < 5); - }); - - it('scrolls bottom by <C-D>', async () => { - await session.executeScript(() => window.scrollTo(0, 1000)); - await body.sendKeys(Key.Control, 'd'); - - let pageHeight = - await session.executeScript(() => window.document.documentElement.clientHeight); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert(Math.abs(pageYOffset - (1000 + Math.floor(pageHeight / 2))) < 5); - }); - - it('scrolls bottom by <C-B>', async () => { - await session.executeScript(() => window.scrollTo(0, 1000)); - await body.sendKeys(Key.Control, 'b'); - - let pageHeight = - await session.executeScript(() => window.document.documentElement.clientHeight); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert(Math.abs(pageYOffset - (1000 - pageHeight)) < 5); - }); - - it('scrolls bottom by <C-F>', async () => { - await session.executeScript(() => window.scrollTo(0, 1000)); - await body.sendKeys(Key.Control, 'f'); - - let pageHeight = - await session.executeScript(() => window.document.documentElement.clientHeight); - let pageYOffset = await session.executeScript(() => window.pageYOffset); - assert(Math.abs(pageYOffset - (1000 + pageHeight)) < 5); - }); -}); diff --git a/e2e/scroll.test.ts b/e2e/scroll.test.ts new file mode 100644 index 0000000..5145265 --- /dev/null +++ b/e2e/scroll.test.ts @@ -0,0 +1,137 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("scroll test", () => { + let server = new TestServer().receiveContent('/', + `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + ); + let lanthan: Lanthan; + let webdriver: WebDriver; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + await webdriver.navigate().to(server.url()); + page = await Page.currentContext(webdriver); + }); + + + it('scrolls up by j', async () => { + await page.sendKeys('j'); + + let scrollY = await page.getScrollY(); + assert.strictEqual(scrollY, 64); + }); + + it('scrolls down by k', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 200)); + await page.sendKeys('k'); + + let scrollY = await page.getScrollY(); + assert.strictEqual(scrollY, 136); + }); + + it('scrolls left by h', async () => { + await webdriver.executeScript(() => window.scrollTo(100, 100)); + await page.sendKeys('h'); + + let pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + assert.strictEqual(pageXOffset, 36); + }); + + it('scrolls left by l', async () => { + await webdriver.executeScript(() => window.scrollTo(100, 100)); + await page.sendKeys('l'); + + let pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + assert.strictEqual(pageXOffset, 164); + }); + + it('scrolls top by gg', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 100)); + await page.sendKeys('g', 'g'); + + let scrollY = await page.getScrollY(); + assert.strictEqual(scrollY, 0); + }); + + it('scrolls bottom by G', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 100)); + await page.sendKeys(Key.SHIFT, 'g'); + + let scrollY = await page.getScrollY(); + assert.ok(scrollY > 5000); + }); + + it('scrolls bottom by 0', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 100)); + await page.sendKeys(Key.SHIFT, '0'); + + let pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + assert.ok(pageXOffset === 0); + }); + + it('scrolls bottom by $', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 100)); + await page.sendKeys(Key.SHIFT, '$'); + + let pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + assert.ok(pageXOffset > 5000); + }); + + it('scrolls bottom by <C-U>', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 1000)); + await page.sendKeys(Key.CONTROL, 'u'); + + let pageHeight = await page.pageHeight(); + let scrollY = await page.getScrollY(); + assert.ok(Math.abs(scrollY - (1000 - Math.floor(pageHeight / 2))) < 5); + }); + + it('scrolls bottom by <C-D>', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 1000)); + await page.sendKeys(Key.CONTROL, 'd'); + + let pageHeight = await page.pageHeight(); + let scrollY = await page.getScrollY(); + assert.ok(Math.abs(scrollY - (1000 + Math.floor(pageHeight / 2))) < 5); + }); + + it('scrolls bottom by <C-B>', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 1000)); + await page.sendKeys(Key.CONTROL, 'b'); + + let pageHeight = await page.pageHeight(); + let scrollY = await page.getScrollY(); + assert.ok(Math.abs(scrollY - (1000 - pageHeight)) < 5); + }); + + it('scrolls bottom by <C-F>', async () => { + await webdriver.executeScript(() => window.scrollTo(0, 1000)); + await page.sendKeys(Key.CONTROL, 'f'); + + let pageHeight = await page.pageHeight(); + let scrollY = await page.getScrollY(); + assert.ok(Math.abs(scrollY - (1000 + pageHeight)) < 5); + }); +}); diff --git a/e2e/settings.js b/e2e/settings.ts index e78add0..b88caf0 100644 --- a/e2e/settings.js +++ b/e2e/settings.ts @@ -1,4 +1,4 @@ -module.exports = { +export default { source: 'json', json: `{ "keymaps": { @@ -83,4 +83,4 @@ module.exports = { "blacklist": [ ] }`, -} +}; diff --git a/e2e/tab.test.js b/e2e/tab.test.js deleted file mode 100644 index 99f0374..0000000 --- a/e2e/tab.test.js +++ /dev/null @@ -1,218 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -const newApp = () => { - let app = express(); - app.get('/', (req, res) => { - res.send('ok'); - }); - return app; -}; - -describe("tab test", () => { - - const port = 12321; - const url = `http://127.0.0.1:${port}/`; - - let http; - let firefox; - let session; - let browser; - let win; - let tabs; - - before(async() => { - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - http = newApp().listen(port); - }); - - after(async() => { - http.close(); - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - win = await browser.windows.create({ url: `${url}#0` }); - for (let i = 1; i < 5; ++i) { - await browser.tabs.create({ url: `${url}#${i}`, windowId: win.id }); - await session.navigateTo(`${url}#${i}`); - } - tabs = await browser.tabs.query({ windowId: win.id }); - tabs.sort((t1, t2) => t1.index - t2.index); - }); - - afterEach(async() => { - await browser.windows.remove(win.id); - }); - - it('deletes tab and selects right by d', async () => { - await browser.tabs.update(tabs[3].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('d'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === tabs.length - 1); - assert(current[3].active); - assert(current[3].url === tabs[4].url); - }); - - it('deletes tab and selects left by D', async () => { - await browser.tabs.update(tabs[3].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'D'); - - await eventually(async() => { - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === tabs.length - 1); - assert(current[2].active); - assert(current[2].url === tabs[2].url); - }) - }); - - it('deletes all tabs to the right by x$', async () => { - await browser.tabs.update(tabs[1].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('x', '$'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === 2); - }); - - it('duplicates tab by zd', async () => { - await browser.tabs.update(tabs[0].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('z', 'd'); - - await eventually(async() => { - let current = await browser.tabs.query({ windowId: win.id }); - current.sort((t1, t2) => t1.index - t2.index); - assert(current.length === tabs.length + 1); - assert(current[0].url === current[1].url); - }); - }); - - it('makes pinned by zp', async () => { - await browser.tabs.update(tabs[0].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('z', 'p'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[0].pinned); - }); - - it('selects previous tab by K', async () => { - await browser.tabs.update(tabs[2].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'K'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[1].active); - }); - - it('selects previous tab by K rotatory', async () => { - await browser.tabs.update(tabs[0].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'K'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[current.length - 1].active) - }); - - it('selects next tab by J', async () => { - await browser.tabs.update(tabs[2].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'J'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[3].active); - }); - - it('selects previous tab by J rotatory', async () => { - await browser.tabs.update(tabs[tabs.length - 1].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Shift, 'J'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[0].active) - }); - - it('selects first tab by g0', async () => { - await browser.tabs.update(tabs[2].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('g', '0'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[0].active) - }); - - it('selects last tab by g$', async () => { - await browser.tabs.update(tabs[2].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('g', '$'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[current.length - 1].active) - }); - - it('selects last selected tab by <C-6>', async () => { - await browser.tabs.update(tabs[1].id, { active: true }); - await browser.tabs.update(tabs[4].id, { active: true }); - - let body = await session.findElementByCSS('body'); - await body.sendKeys(Key.Control, '6'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current[1].active) - }); - - // browser.sessions.getRecentlyClosed() sometime throws "An unexpected error occurred" - // This might be a bug in Firefox. - it.skip('reopen tab by u', async () => { - await browser.tabs.remove(tabs[1].id); - let body = await session.findElementByCSS('body'); - await body.sendKeys('u'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === tabs.length); - }); - - it('does not delete pinned tab by d', async () => { - await browser.tabs.update(tabs[0].id, { active: true, pinned: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('d'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === tabs.length); - }); - - it('deletes pinned tab by !d', async () => { - await browser.tabs.update(tabs[0].id, { active: true, pinned: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('!', 'd'); - - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === tabs.length - 1); - }); - - it('opens view-source by gf', async () => { - await browser.tabs.update(tabs[0].id, { active: true }); - let body = await session.findElementByCSS('body'); - await body.sendKeys('g', 'f'); - - await eventually(async() => { - let current = await browser.tabs.query({ windowId: win.id }); - assert(current.length === tabs.length + 1); - assert(current[current.length - 1].url === `view-source:${url}#0`); - }); - }); -}); diff --git a/e2e/tab.test.ts b/e2e/tab.test.ts new file mode 100644 index 0000000..1a5dd5c --- /dev/null +++ b/e2e/tab.test.ts @@ -0,0 +1,211 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import TestServer from './lib/TestServer'; +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver, Key } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("tab test", () => { + let server = new TestServer().receiveContent('/*', 'ok'); + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let win: any; + let tabs: any[]; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + await server.start(); + }); + + after(async() => { + await server.stop(); + if (lanthan) { + await lanthan.quit(); + } + }); + + beforeEach(async() => { + win = await browser.windows.create({ url: server.url('/#0') }); + for (let i = 1; i < 5; ++i) { + await browser.tabs.create({ url: server.url('/#' + i), windowId: win.id }); + await webdriver.navigate().to(server.url('/#' + i)); + } + tabs = await browser.tabs.query({ windowId: win.id }); + tabs.sort((t1: any, t2: any) => t1.index - t2.index); + }); + + afterEach(async() => { + await browser.windows.remove(win.id); + }); + + it('deletes tab and selects right by d', async () => { + await browser.tabs.update(tabs[3].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('d'); + + await eventually(async() => { + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, tabs.length - 1); + assert.strictEqual(current[3].active, true); + assert.strictEqual(current[3].id, tabs[4].id); + }); + }); + + it('deletes tab and selects left by D', async () => { + await browser.tabs.update(tabs[3].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys(Key.SHIFT, 'D'); + + await eventually(async() => { + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, tabs.length - 1); + assert.strictEqual(current[2].active, true); + assert.strictEqual(current[2].id, tabs[2].id); + }) + }); + + it('deletes all tabs to the right by x$', async () => { + await browser.tabs.update(tabs[1].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('x', '$'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, 2); + }); + + it('duplicates tab by zd', async () => { + await browser.tabs.update(tabs[0].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('z', 'd'); + + await eventually(async() => { + let current = await browser.tabs.query({ windowId: win.id }); + current.sort((t1: any, t2: any) => t1.index - t2.index); + assert.strictEqual(current.length, tabs.length + 1); + assert.strictEqual(current[0].url, current[1].url); + }); + }); + + it('makes pinned by zp', async () => { + await browser.tabs.update(tabs[0].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('z', 'p'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[0].pinned, true); + }); + + it('selects previous tab by K', async () => { + await browser.tabs.update(tabs[2].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys(Key.SHIFT, 'K'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[1].active, true); + }); + + it('selects previous tab by K rotatory', async () => { + await browser.tabs.update(tabs[0].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys(Key.SHIFT, 'K'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[current.length - 1].active, true) + }); + + it('selects next tab by J', async () => { + await browser.tabs.update(tabs[2].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys(Key.SHIFT, 'J'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[3].active, true); + }); + + it('selects previous tab by J rotatory', async () => { + await browser.tabs.update(tabs[tabs.length - 1].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys(Key.SHIFT, 'J'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[0].active, true) + }); + + it('selects first tab by g0', async () => { + await browser.tabs.update(tabs[2].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('g', '0'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[0].active, true) + }); + + it('selects last tab by g$', async () => { + await browser.tabs.update(tabs[2].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('g', '$'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[current.length - 1].active, true) + }); + + it('selects last selected tab by <C-6>', async () => { + await browser.tabs.update(tabs[1].id, { active: true }); + await browser.tabs.update(tabs[4].id, { active: true }); + + let page = await Page.currentContext(webdriver); + await page.sendKeys(Key.CONTROL, '6'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current[1].active, true) + }); + + // browser.sessions.getRecentlyClosed() sometime throws "An unexpected error occurred" + // This might be a bug in Firefox. + it.skip('reopen tab by u', async () => { + await browser.tabs.remove(tabs[1].id); + let page = await Page.currentContext(webdriver); + await page.sendKeys('u'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, tabs.length); + }); + + it('does not delete pinned tab by d', async () => { + await browser.tabs.update(tabs[0].id, { active: true, pinned: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('d'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, tabs.length); + }); + + it('deletes pinned tab by !d', async () => { + await browser.tabs.update(tabs[0].id, { active: true, pinned: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('!', 'd'); + + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, tabs.length - 1); + }); + + it('opens view-source by gf', async () => { + await browser.tabs.update(tabs[0].id, { active: true }); + let page = await Page.currentContext(webdriver); + await page.sendKeys('g', 'f'); + + await eventually(async() => { + let current = await browser.tabs.query({ windowId: win.id }); + assert.strictEqual(current.length, tabs.length + 1); + assert.strictEqual(current[current.length - 1].url, `view-source:${server.url('/#0')}`); + }); + }); +}); diff --git a/e2e/zoom.test.js b/e2e/zoom.test.js deleted file mode 100644 index 186f67f..0000000 --- a/e2e/zoom.test.js +++ /dev/null @@ -1,66 +0,0 @@ -const express = require('express'); -const lanthan = require('lanthan'); -const path = require('path'); -const assert = require('assert'); -const eventually = require('./eventually'); - -const Key = lanthan.Key; - -describe("zoom test", () => { - - let firefox; - let session; - let browser; - let tab; - let body; - - before(async() => { - firefox = await lanthan.firefox(); - await firefox.session.installAddonFromPath(path.join(__dirname, '..')); - session = firefox.session; - browser = firefox.browser; - tab = (await browser.tabs.query({}))[0] - }); - - after(async() => { - if (firefox) { - await firefox.close(); - } - }); - - beforeEach(async() => { - await session.navigateTo('about:blank'); - body = await session.findElementByCSS('body'); - }); - - it('should zoom in by zi', async () => { - let before = await browser.tabs.getZoom(tab.id); - await body.sendKeys('z', 'i'); - - await eventually(async() => { - let actual = await browser.tabs.getZoom(tab.id); - assert(before < actual); - }); - }); - - it('should zoom out by zo', async () => { - let before = await browser.tabs.getZoom(tab.id); - await body.sendKeys('z', 'o'); - - await eventually(async() => { - let actual = await browser.tabs.getZoom(tab.id); - assert(before > actual); - }); - }); - - it('scrolls left by h', async () => { - await browser.tabs.setZoom(tab.id, 2); - await body.sendKeys('z', 'z'); - - await eventually(async() => { - let actual = await browser.tabs.getZoom(tab.id); - assert(actual === 1); - }); - }); -}); - diff --git a/e2e/zoom.test.ts b/e2e/zoom.test.ts new file mode 100644 index 0000000..396ddd2 --- /dev/null +++ b/e2e/zoom.test.ts @@ -0,0 +1,65 @@ +import * as path from 'path'; +import * as assert from 'assert'; + +import eventually from './eventually'; +import { Builder, Lanthan } from 'lanthan'; +import { WebDriver } from 'selenium-webdriver'; +import Page from './lib/Page'; + +describe("zoom test", () => { + let lanthan: Lanthan; + let webdriver: WebDriver; + let browser: any; + let tab: any; + let page: Page; + + before(async() => { + lanthan = await Builder + .forBrowser('firefox') + .spyAddon(path.join(__dirname, '..')) + .build(); + webdriver = lanthan.getWebDriver(); + browser = lanthan.getWebExtBrowser(); + tab = (await browser.tabs.query({}))[0] + page = await Page.currentContext(webdriver); + }); + + after(async() => { + await lanthan.quit(); + }); + + beforeEach(async() => { + await webdriver.navigate().to('about:blank'); + }); + + it('should zoom in by zi', async () => { + let before = await browser.tabs.getZoom(tab.id); + await page.sendKeys('zi'); + + await eventually(async() => { + let actual = await browser.tabs.getZoom(tab.id); + assert.ok(before < actual); + }); + }); + + it('should zoom out by zo', async () => { + let before = await browser.tabs.getZoom(tab.id); + await page.sendKeys('zo'); + + await eventually(async() => { + let actual = await browser.tabs.getZoom(tab.id); + assert.ok(before > actual); + }); + }); + + it('should reset zoom by zz', async () => { + await browser.tabs.setZoom(tab.id, 2); + await page.sendKeys('zz'); + + await eventually(async() => { + let actual = await browser.tabs.getZoom(tab.id); + assert.strictEqual(actual, 1); + }); + }); +}); + diff --git a/karma.conf.js b/karma.conf.js index b422605..92f67ea 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -19,8 +19,6 @@ module.exports = function (config) { 'test/**/*.html': ['html2js'] }, - reporters: ['progress'], - port: 9876, colors: true, logLevel: config.LOG_INFO, diff --git a/package-lock.json b/package-lock.json index 07869a7..b0b1265 100644 --- a/package-lock.json +++ b/package-lock.json @@ -113,18 +113,64 @@ "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", "dev": true }, + "@types/assert": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.4.3.tgz", + "integrity": "sha512-491hfOvNr0+BGOHT2m36xJ+LK68IuOshvxV0VIrKOnzBDL11WlDa3PwO+drTYkwCdfzJRN9REcDPZVVcrx1ucw==", + "dev": true + }, + "@types/body-parser": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", + "integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, "@types/chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.0.tgz", "integrity": "sha512-zw8UvoBEImn392tLjxoavuonblX/4Yb9ha4KBU10FirCfwgzhKO0dvyJSF9ByxV1xK1r2AgnAi/tvQaLgxQqxA==", "dev": true }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", "dev": true }, + "@types/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.1.tgz", + "integrity": "sha512-VfH/XCP0QbQk5B5puLqTLEeFgR8lfCJHZJKkInZ9mkYd+u8byX0kztXEQxEk4wZXJs8HI+7km2ALXjn4YKcX9w==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.16.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.9.tgz", + "integrity": "sha512-GqpaVWR0DM8FnRUJYKlWgyARoBUAVfRIeVDZQKOttLFp5SmhhF9YFIYeTPwMd/AXfxlP7xVO2dj1fGu0Q+krKQ==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, "@types/hoist-non-react-statics": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", @@ -141,18 +187,36 @@ "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", "dev": true }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", + "dev": true + }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", "dev": true }, + "@types/node": { + "version": "12.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", + "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", + "dev": true + }, "@types/prop-types": { "version": "15.7.1", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz", "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==", "dev": true }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, "@types/react": { "version": "16.9.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.2.tgz", @@ -207,6 +271,22 @@ } } }, + "@types/selenium-webdriver": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-4.0.2.tgz", + "integrity": "sha512-N8u76LXU6KmxdfKEhOvK/dNtWUg7aeXrQVRRhVqO1V4gYN7zL6SPPJC3GmauyxYnJtsG1BCegQK77pRwieLVhw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "@types/sinon": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.13.tgz", @@ -591,6 +671,12 @@ "readable-stream": "^2.0.6" } }, + "arg": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", + "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1606,10 +1692,13 @@ "dev": true }, "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } }, "content-type": { "version": "1.0.4", @@ -2677,69 +2766,171 @@ } }, "express": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", - "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "dev": true, "requires": { - "accepts": "~1.3.5", + "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.18.3", - "content-disposition": "0.5.2", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", "content-type": "~1.0.4", - "cookie": "0.3.1", + "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.1.1", + "finalhandler": "~1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "~1.1.2", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.4", - "qs": "6.5.2", - "range-parser": "~1.2.0", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", "safe-buffer": "5.1.2", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "~1.4.0", - "type-is": "~1.6.16", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { - "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.4.0", - "unpipe": "~1.0.0" + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" } }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", "dev": true }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } } } }, @@ -4496,9 +4687,9 @@ "dev": true }, "ipaddr.js": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", - "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", "dev": true }, "is-accessor-descriptor": { @@ -5169,128 +5360,16 @@ } }, "lanthan": { - "version": "git+https://github.com/ueokande/lanthan.git#d7f92eb4c1c6eee3f747b4a76bdf39062b4cb58f", - "from": "git+https://github.com/ueokande/lanthan.git#master", + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/lanthan/-/lanthan-0.0.2.tgz", + "integrity": "sha512-+nWapmVfFCprRE39Z6pKyf5KCclJJvSyAU0o3G2Tl+yZc77xDtqL2JfBADVHk7UNQBrqyg62FPtLq4NeQsFdVA==", "dev": true, "requires": { - "commander": "^2.20.0", - "express": "^4.16.4", - "jszip": "^3.2.1", + "express": "^4.17.1", + "jszip": "^3.2.2", "request": "^2.88.0", - "request-promise-native": "^1.0.7" - }, - "dependencies": { - "ajv": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", - "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "mime-db": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", - "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", - "dev": true - }, - "mime-types": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", - "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", - "dev": true, - "requires": { - "mime-db": "~1.38.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true - } + "request-promise-native": "^1.0.7", + "selenium-webdriver": "^4.0.0-alpha.5" } }, "lcid": { @@ -5558,6 +5637,12 @@ } } }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, "mamacro": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", @@ -6948,9 +7033,9 @@ } }, "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, "pascalcase": { @@ -7278,13 +7363,13 @@ } }, "proxy-addr": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", - "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", "dev": true, "requires": { "forwarded": "~0.1.2", - "ipaddr.js": "1.8.0" + "ipaddr.js": "1.9.0" } }, "prr": { @@ -7991,6 +8076,12 @@ } } }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "scheduler": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz", @@ -8033,6 +8124,52 @@ } } }, + "selenium-webdriver": { + "version": "4.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.5.tgz", + "integrity": "sha512-hktl3DSrhzM59yLhWzDGHIX9o56DvA+cVK7Dw6FcJR6qQ4CGzkaHeXQPcdrslkWMTeq0Ci9AmCxq0EMOvm2Rkg==", + "dev": true, + "requires": { + "jszip": "^3.1.5", + "rimraf": "^2.6.3", + "tmp": "0.0.30", + "xml2js": "^0.4.19" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", @@ -8040,9 +8177,9 @@ "dev": true }, "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", "dev": true, "requires": { "debug": "2.6.9", @@ -8052,24 +8189,55 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.4.0" + "range-parser": "~1.2.1", + "statuses": "~1.5.0" }, "dependencies": { + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true } } @@ -8081,15 +8249,15 @@ "dev": true }, "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.2" + "parseurl": "~1.3.3", + "send": "0.17.1" } }, "set-blocking": { @@ -9096,6 +9264,12 @@ } } }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, "toposort": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", @@ -9228,6 +9402,27 @@ } } }, + "ts-node": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", + "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + }, + "dependencies": { + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + } + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -10102,6 +10297,23 @@ "ultron": "~1.1.0" } }, + "xml2js": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", @@ -10304,6 +10516,12 @@ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index 2306396..4fee0e8 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "lint": "eslint --ext .js,.jsx,.ts,.tsx src", "type-checks": "tsc --noEmit", "test": "karma start", - "test:e2e": "mocha --timeout 10000 --retries 5 e2e" + "test:e2e": "mocha --timeout 10000 --retries 10 --require ts-node/register --extension ts e2e" }, "repository": { "type": "git", @@ -21,13 +21,17 @@ }, "homepage": "https://github.com/ueokande/vim-vixen", "devDependencies": { + "@types/assert": "^1.4.3", "@types/chai": "^4.2.0", + "@types/express": "^4.17.1", "@types/mocha": "^5.2.7", + "@types/node": "^12.7.5", "@types/prop-types": "^15.7.1", "@types/react": "^16.9.2", "@types/react-dom": "^16.9.0", "@types/react-redux": "^7.1.2", "@types/redux-promise": "^0.5.28", + "@types/selenium-webdriver": "^4.0.2", "@types/sinon": "^7.0.13", "@typescript-eslint/eslint-plugin": "^2.0.0", "@typescript-eslint/parser": "^2.0.0", @@ -35,6 +39,7 @@ "css-loader": "^3.2.0", "eslint": "^6.2.2", "eslint-plugin-react": "^7.14.3", + "express": "^4.17.1", "html-webpack-plugin": "^3.2.0", "jsonwebtoken": "^8.5.1", "jszip": "^3.2.2", @@ -46,7 +51,7 @@ "karma-sinon": "^1.0.5", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^4.0.2", - "lanthan": "git+https://github.com/ueokande/lanthan.git#master", + "lanthan": "0.0.2", "mocha": "^6.2.0", "node-sass": "^4.12.0", "react": "^16.9.0", @@ -62,6 +67,7 @@ "sinon-chrome": "^3.0.1", "style-loader": "^1.0.0", "ts-loader": "^6.0.4", + "ts-node": "^8.4.1", "tsyringe": "^3.3.0", "typescript": "^3.6.2", "web-ext-types": "^3.2.1", |