diff options
249 files changed, 7369 insertions, 6265 deletions
@@ -9,10 +9,7 @@ "extends": [ "plugin:@typescript-eslint/recommended", "plugin:react/recommended", - "prettier", - "prettier/@typescript-eslint", - "prettier/react", - "prettier/standard" + "plugin:prettier/recommended" ], "plugins": [ "@typescript-eslint", diff --git a/e2e/blacklist.test.ts b/e2e/blacklist.test.ts index 79cdb47..db82726 100644 --- a/e2e/blacklist.test.ts +++ b/e2e/blacklist.test.ts @@ -1,57 +1,59 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +import TestServer from "./lib/TestServer"; +import { Builder, Lanthan } from "lanthan"; +import { WebDriver } from "selenium-webdriver"; +import Page from "./lib/Page"; import SettingRepository from "./lib/SettingRepository"; import Settings from "../src/shared/settings/Settings"; describe("blacklist test", () => { - const server = new TestServer().receiveContent('/*', - `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); - const url = server.url('/a').replace('http://', ''); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - keymaps: { - j: { type: "scroll.vertically", count: 1 }, - }, - blacklist: [ url ], - })); + const url = server.url("/a").replace("http://", ""); + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + keymaps: { + j: { type: "scroll.vertically", count: 1 }, + }, + blacklist: [url], + }) + ); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - it('should disable add-on if the URL is in the blacklist', async () => { - const page = await Page.navigateTo(webdriver, server.url('/a')); - await page.sendKeys('j'); + it("should disable add-on if the URL is in the blacklist", async () => { + const page = await Page.navigateTo(webdriver, server.url("/a")); + await page.sendKeys("j"); const scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 0); }); - it('should enabled add-on if the URL is not in the blacklist', async () => { - const page = await Page.navigateTo(webdriver, server.url('/ab')); - await page.sendKeys('j'); + it("should enabled add-on if the URL is not in the blacklist", async () => { + const page = await Page.navigateTo(webdriver, server.url("/ab")); + await page.sendKeys("j"); const scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 64); diff --git a/e2e/clipboard.test.ts b/e2e/clipboard.test.ts index 0a09c77..63a20a8 100644 --- a/e2e/clipboard.test.ts +++ b/e2e/clipboard.test.ts @@ -1,116 +1,120 @@ -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 { Builder, Lanthan } from 'lanthan'; -import { WebDriver, Key } from 'selenium-webdriver'; -import Page from './lib/Page'; +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 { Builder, Lanthan } from "lanthan"; +import { WebDriver, Key } from "selenium-webdriver"; +import Page from "./lib/Page"; import SettingRepository from "./lib/SettingRepository"; import Settings from "../src/shared/settings/Settings"; describe("clipboard test", () => { - const server = new TestServer(12321).receiveContent('/happy', 'ok'); + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - search: { - default: "google", - engines: { - "google": "http://127.0.0.1:12321/google?q={}", + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + search: { + default: "google", + engines: { + google: "http://127.0.0.1:12321/google?q={}", + }, }, - }, - })); + }) + ); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } }); - it('should copy current URL by y', async () => { - const page = await Page.navigateTo(webdriver, server.url('/#should_copy_url')); - await page.sendKeys('y'); + it("should copy current URL by y", async () => { + const page = await Page.navigateTo( + webdriver, + server.url("/#should_copy_url") + ); + await page.sendKeys("y"); - await eventually(async() => { + await eventually(async () => { const data = await clipboard.read(); - assert.strictEqual(data, server.url('/#should_copy_url')); + 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')); + it("should open an URL from clipboard by p", async () => { + await clipboard.write(server.url("/#open_from_clipboard")); const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('p'); + await page.sendKeys("p"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); - assert.strictEqual(tabs[0].url, server.url('/#open_from_clipboard')); + 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')); + it("should open an URL from clipboard to new tab by P", async () => { + await clipboard.write(server.url("/#open_to_new_tab")); const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys(Key.SHIFT, 'p'); + await page.sendKeys(Key.SHIFT, "p"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.deepStrictEqual(tabs.map((t: any) => t.url), [ - server.url(), - server.url('/#open_to_new_tab'), - ]); + 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 () => { + it("should open search result with keywords in clipboard by p", async () => { await clipboard.write(`an apple`); const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys(Key.SHIFT, 'p'); + await page.sendKeys(Key.SHIFT, "p"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); - assert.strictEqual(tabs[0].url, server.url('/google?q=an%20apple')); + 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 () => { + it("should open search result with keywords in clipboard to new tabby P", async () => { await clipboard.write(`an apple`); const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys(Key.SHIFT, 'p'); + await page.sendKeys(Key.SHIFT, "p"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.deepStrictEqual(tabs.map((t: any) => t.url), [ - server.url(), - server.url('/google?q=an%20apple'), - ]); + assert.deepStrictEqual( + tabs.map((t: any) => t.url), + [server.url(), server.url("/google?q=an%20apple")] + ); }); }); }); diff --git a/e2e/command_addbookmark.test.ts b/e2e/command_addbookmark.test.ts index a54c103..4142e68 100644 --- a/e2e/command_addbookmark.test.ts +++ b/e2e/command_addbookmark.test.ts @@ -1,51 +1,54 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 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', () => { - const server = new TestServer().receiveContent('/happy', ` +describe("addbookmark command test", () => { + const server = new TestServer().receiveContent( + "/happy", + ` <!DOCTYPE html> - <html lang="en"><head><title>how to be happy</title></head></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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { - await webdriver.navigate().to(server.url('/happy')); + beforeEach(async () => { + await webdriver.navigate().to(server.url("/happy")); }); - it('should add a bookmark from the current page', async() => { + it("should add a bookmark from the current page", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('addbookmark how to be happy'); + await console.execCommand("addbookmark how to be happy"); - await eventually(async() => { - const bookmarks = await browser.bookmarks.search({ title: 'how to be happy' }); + await eventually(async () => { + const bookmarks = await browser.bookmarks.search({ + title: "how to be happy", + }); assert.strictEqual(bookmarks.length, 1); - assert.strictEqual(bookmarks[0].url, server.url('/happy')); + assert.strictEqual(bookmarks[0].url, server.url("/happy")); }); }); }); diff --git a/e2e/command_bdelete.test.ts b/e2e/command_bdelete.test.ts index c1f27ae..a85ce50 100644 --- a/e2e/command_bdelete.test.ts +++ b/e2e/command_bdelete.test.ts @@ -1,155 +1,165 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 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', () => { - const server = new TestServer().receiveContent('/*', 'ok'); +describe("bdelete/bdeletes command test", () => { + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const 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 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() => { + await eventually(async () => { const 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() => { + it("should delete an unpinned tab by bdelete command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdelete site5'); + await console.execCommand("bdelete site5"); - await eventually(async() => { + await eventually(async () => { const 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'), - ]) + 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() => { + it("should not delete an pinned tab by bdelete command by bdelete command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdelete site1'); + await console.execCommand("bdelete site1"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 5); }); }); - it('should show an error when no tabs are matched by bdelete command', async() => { + it("should show an error when no tabs are matched by bdelete command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdelete xyz'); + await console.execCommand("bdelete xyz"); - await eventually(async() => { + await eventually(async () => { const text = await console.getErrorMessage(); - assert.strictEqual(text, 'No matching buffer for xyz'); + assert.strictEqual(text, "No matching buffer for xyz"); }); }); - it('should show an error when more than one tabs are matched by bdelete command', async() => { + it("should show an error when more than one tabs are matched by bdelete command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdelete site'); + await console.execCommand("bdelete site"); - await eventually(async() => { + await eventually(async () => { const text = await console.getErrorMessage(); - assert.strictEqual(text, 'More than one match for site'); + assert.strictEqual(text, "More than one match for site"); }); }); - it('should delete an unpinned tab by bdelete! command', async() => { + it("should delete an unpinned tab by bdelete! command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdelete! site5'); + await console.execCommand("bdelete! site5"); - await eventually(async() => { + await eventually(async () => { const 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'), - ]) + 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() => { + it("should delete an pinned tab by bdelete! command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdelete! site1'); + await console.execCommand("bdelete! site1"); - await eventually(async() => { + await eventually(async () => { const 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'), - ]) + 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() => { + it("should delete unpinned tabs by bdeletes command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdeletes site'); + await console.execCommand("bdeletes site"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.deepStrictEqual(tabs.map((t: any) => t.url), [ - server.url('/site1'), - server.url('/site2'), - server.url('/site3'), - ]) + 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() => { + it("should delete both pinned and unpinned tabs by bdeletes! command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('bdeletes! site'); + await console.execCommand("bdeletes! site"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 1); }); diff --git a/e2e/command_buffer.test.ts b/e2e/command_buffer.test.ts index 3fa67ba..114f4b4 100644 --- a/e2e/command_buffer.test.ts +++ b/e2e/command_buffer.test.ts @@ -1,160 +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', () => { - const server = new TestServer().handle('/*', (req: Request, res: Response) => { - res.send(` +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", () => { + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } - await browser.tabs.update(tabs[0].id, { url: server.url('/site1') }); + 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 browser.tabs.create({ url: server.url("/site" + i) }); } - await eventually(async() => { + await eventually(async () => { const 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() => { + it("should do nothing by buffer command with no parameters", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer'); + await console.execCommand("buffer"); - await eventually(async() => { + await eventually(async () => { const 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() => { + it("should select a tab by buffer command with a number", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer 1'); + await console.execCommand("buffer 1"); - await eventually(async() => { + await eventually(async () => { const 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() => { + it("should should an out of range error by buffer commands", async () => { const page = await Page.currentContext(webdriver); let console = await page.showConsole(); - await console.execCommand('buffer 0'); + await console.execCommand("buffer 0"); - await eventually(async() => { + await eventually(async () => { const text = await console.getErrorMessage(); - assert.strictEqual(text, 'tab 0 does not exist'); + assert.strictEqual(text, "tab 0 does not exist"); }); await (webdriver.switchTo() as any).parentFrame(); console = await page.showConsole(); - await console.execCommand('buffer 9'); + await console.execCommand("buffer 9"); - await eventually(async() => { + await eventually(async () => { const text = await console.getErrorMessage(); - assert.strictEqual(text, 'tab 9 does not exist'); + assert.strictEqual(text, "tab 9 does not exist"); }); }); - it('should select a tab by buffer command with a title', async() => { + it("should select a tab by buffer command with a title", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer my_site1'); + await console.execCommand("buffer my_site1"); - await eventually(async() => { + await eventually(async () => { const 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() => { + it("should select a tab by buffer command with an URL", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer /site1'); + await console.execCommand("buffer /site1"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); assert.strictEqual(tabs[0].index, 0); }); }); - it('should select tabs rotately', async() => { + it("should select tabs rotately", async () => { const handles = await webdriver.getAllWindowHandles(); await webdriver.switchTo().window(handles[4]); const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer site'); + await console.execCommand("buffer site"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); assert.strictEqual(tabs[0].index, 0); }); }); - it('should do nothing by ":buffer %"', async() => { + it('should do nothing by ":buffer %"', async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer %'); + await console.execCommand("buffer %"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); assert.strictEqual(tabs[0].index, 2); }); }); - it('should selects last selected tab by ":buffer #"', async() => { + it('should selects last selected tab by ":buffer #"', async () => { const handles = await webdriver.getAllWindowHandles(); await webdriver.switchTo().window(handles[1]); const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('buffer #'); + await console.execCommand("buffer #"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); assert.strictEqual(tabs[0].index, 2); }); diff --git a/e2e/command_help.test.ts b/e2e/command_help.test.ts index 9f8a459..40d4dde 100644 --- a/e2e/command_help.test.ts +++ b/e2e/command_help.test.ts @@ -1,11 +1,11 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 TestServer from "./lib/TestServer"; +import eventually from "./eventually"; +import { Builder, Lanthan } from "lanthan"; +import { WebDriver } from "selenium-webdriver"; +import Page from "./lib/Page"; describe("help command test", () => { const server = new TestServer(); @@ -14,10 +14,9 @@ describe("help command test", () => { let browser: any; let page: Page; - before(async() => { - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); @@ -25,25 +24,24 @@ describe("help command test", () => { await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { page = await Page.navigateTo(webdriver, server.url()); }); - it('should open help page by help command ', async() => { + it("should open help page by help command ", async () => { const console = await page.showConsole(); - await console.execCommand('help'); + await console.execCommand("help"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); - assert.strictEqual(tabs[0].url, 'https://ueokande.github.io/vim-vixen/') + assert.strictEqual(tabs[0].url, "https://ueokande.github.io/vim-vixen/"); }); }); }); - diff --git a/e2e/command_open.test.ts b/e2e/command_open.test.ts index f4d2aa1..2db522a 100644 --- a/e2e/command_open.test.ts +++ b/e2e/command_open.test.ts @@ -1,118 +1,119 @@ -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 * 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 SettingRepository from "./lib/SettingRepository"; import Settings from "../src/shared/settings/Settings"; describe("open command test", () => { const server = new TestServer() - .receiveContent('/google', 'google') - .receiveContent('/yahoo', 'yahoo'); + .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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - search: { - default: "google", - engines: { - "google": server.url('/google?q={}'), - "yahoo": server.url('/yahoo?q={}'), + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + search: { + default: "google", + engines: { + google: server.url("/google?q={}"), + yahoo: server.url("/yahoo?q={}"), + }, }, - }, - })); + }) + ); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { await webdriver.switchTo().defaultContent(); page = await Page.navigateTo(webdriver, server.url()); }); - it('should open default search for keywords by open command ', async() => { + it("should open default search for keywords by open command ", async () => { const console = await page.showConsole(); - await console.execCommand('open an apple'); + await console.execCommand("open an apple"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/google?q=an%20apple')) + assert.strictEqual(url.href, server.url("/google?q=an%20apple")); }); }); - it('should open certain search page for keywords by open command ', async() => { + it("should open certain search page for keywords by open command ", async () => { const console = await page.showConsole(); - await console.execCommand('open yahoo an apple'); + await console.execCommand("open yahoo an apple"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple')) + assert.strictEqual(url.href, server.url("/yahoo?q=an%20apple")); }); }); - it('should open default engine with empty keywords by open command ', async() => { + it("should open default engine with empty keywords by open command ", async () => { const console = await page.showConsole(); - await console.execCommand('open'); + await console.execCommand("open"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/google?q=')) + assert.strictEqual(url.href, server.url("/google?q=")); }); }); - it('should open certain search page for empty keywords by open command ', async() => { + it("should open certain search page for empty keywords by open command ", async () => { const console = await page.showConsole(); - await console.execCommand('open yahoo'); + await console.execCommand("open yahoo"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/yahoo?q=')) + assert.strictEqual(url.href, server.url("/yahoo?q=")); }); }); - it('should open a site with domain by open command ', async() => { + it("should open a site with domain by open command ", async () => { const console = await page.showConsole(); - await console.execCommand('open example.com'); + await console.execCommand("open example.com"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, 'http://example.com/') + assert.strictEqual(url.href, "http://example.com/"); }); }); - it('should open a site with URL by open command ', async() => { + it("should open a site with URL by open command ", async () => { const console = await page.showConsole(); - await console.execCommand('open https://example.com/'); + await console.execCommand("open https://example.com/"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({ active: true }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, 'https://example.com/') + assert.strictEqual(url.href, "https://example.com/"); }); }); }); diff --git a/e2e/command_quit.test.ts b/e2e/command_quit.test.ts index 037ad09..d59abfc 100644 --- a/e2e/command_quit.test.ts +++ b/e2e/command_quit.test.ts @@ -1,93 +1,92 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 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', () => { - const server = new TestServer().receiveContent('/*', 'ok'); +describe("quit/quitall command test", () => { + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } - await browser.tabs.update(tabs[0].id, { url: server.url('/site1') }); + 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 browser.tabs.create({ url: server.url("/site" + i) }); } - await eventually(async() => { + await eventually(async () => { const handles = await webdriver.getAllWindowHandles(); assert.strictEqual(handles.length, 5); await webdriver.switchTo().window(handles[2]); }); }); - it('should current tab by q command', async() => { + it("should current tab by q command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('q'); + await console.execCommand("q"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.strictEqual(tabs.length, 4) + assert.strictEqual(tabs.length, 4); }); }); - it('should current tab by quit command', async() => { + it("should current tab by quit command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('quit'); + await console.execCommand("quit"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.strictEqual(tabs.length, 4) + assert.strictEqual(tabs.length, 4); }); }); - it('should current tab by qa command', async() => { + it("should current tab by qa command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('qa'); + await console.execCommand("qa"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.strictEqual(tabs.length, 1) + assert.strictEqual(tabs.length, 1); }); }); - it('should current tab by quitall command', async() => { + it("should current tab by quitall command", async () => { const page = await Page.currentContext(webdriver); const console = await page.showConsole(); - await console.execCommand('quitall'); + await console.execCommand("quitall"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); - assert.strictEqual(tabs.length, 1) + assert.strictEqual(tabs.length, 1); }); }); }); diff --git a/e2e/command_tabopen.test.ts b/e2e/command_tabopen.test.ts index e96c29e..9807a03 100644 --- a/e2e/command_tabopen.test.ts +++ b/e2e/command_tabopen.test.ts @@ -1,51 +1,52 @@ -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 * 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 SettingRepository from "./lib/SettingRepository"; import Settings from "../src/shared/settings/Settings"; describe("tabopen command test", () => { const server = new TestServer() - .receiveContent('/google', 'google') - .receiveContent('/yahoo', 'yahoo'); + .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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - search: { - default: "google", - engines: { - "google": server.url('/google?q={}'), - "yahoo": server.url('/yahoo?q={}'), + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + search: { + default: "google", + engines: { + google: server.url("/google?q={}"), + yahoo: server.url("/yahoo?q={}"), + }, }, - }, - })); + }) + ); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); @@ -54,75 +55,75 @@ describe("tabopen command test", () => { page = await Page.navigateTo(webdriver, server.url()); }); - it('should open default search for keywords by tabopen command ', async() => { + it("should open default search for keywords by tabopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('tabopen an apple'); + await console.execCommand("tabopen an apple"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); const url = new URL(tabs[1].url); - assert.strictEqual(url.href, server.url('/google?q=an%20apple') ) + assert.strictEqual(url.href, server.url("/google?q=an%20apple")); }); }); - it('should open certain search page for keywords by tabopen command ', async() => { + it("should open certain search page for keywords by tabopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('tabopen yahoo an apple'); + await console.execCommand("tabopen yahoo an apple"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); const url = new URL(tabs[1].url); - assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple')) + assert.strictEqual(url.href, server.url("/yahoo?q=an%20apple")); }); }); - it('should open default engine with empty keywords by tabopen command ', async() => { + it("should open default engine with empty keywords by tabopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('tabopen'); + await console.execCommand("tabopen"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); const url = new URL(tabs[1].url); - assert.strictEqual(url.href, server.url('/google?q=')) + assert.strictEqual(url.href, server.url("/google?q=")); }); }); - it('should open certain search page for empty keywords by tabopen command ', async() => { + it("should open certain search page for empty keywords by tabopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('tabopen yahoo'); + await console.execCommand("tabopen yahoo"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); const url = new URL(tabs[1].url); - assert.strictEqual(url.href, server.url('/yahoo?q=')) + assert.strictEqual(url.href, server.url("/yahoo?q=")); }); }); - it('should open a site with domain by tabopen command ', async() => { + it("should open a site with domain by tabopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('tabopen example.com'); + await console.execCommand("tabopen example.com"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); const url = new URL(tabs[1].url); - assert.strictEqual(url.href, 'http://example.com/') + assert.strictEqual(url.href, "http://example.com/"); }); }); - it('should open a site with URL by tabopen command ', async() => { + it("should open a site with URL by tabopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('tabopen https://example.com/'); + await console.execCommand("tabopen https://example.com/"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); const url = new URL(tabs[1].url); - assert.strictEqual(url.href, 'https://example.com/') + assert.strictEqual(url.href, "https://example.com/"); }); }); }); diff --git a/e2e/command_winopen.test.ts b/e2e/command_winopen.test.ts index c9ff8d2..1d13edd 100644 --- a/e2e/command_winopen.test.ts +++ b/e2e/command_winopen.test.ts @@ -1,51 +1,52 @@ -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 * 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 SettingRepository from "./lib/SettingRepository"; import Settings from "../src/shared/settings/Settings"; describe("winopen command test", () => { const server = new TestServer() - .receiveContent('/google', 'google') - .receiveContent('/yahoo', 'yahoo'); + .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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - search: { - default: "google", - engines: { - "google": server.url('/google?q={}'), - "yahoo": server.url('/yahoo?q={}'), + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + search: { + default: "google", + engines: { + google: server.url("/google?q={}"), + yahoo: server.url("/yahoo?q={}"), + }, }, - }, - })); + }) + ); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const wins = await browser.windows.getAll(); for (const win of wins.slice(1)) { await browser.windows.remove(win.id); @@ -54,87 +55,87 @@ describe("winopen command test", () => { page = await Page.navigateTo(webdriver, server.url()); }); - it('should open default search for keywords by winopen command ', async() => { + it("should open default search for keywords by winopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('winopen an apple'); + await console.execCommand("winopen an apple"); - await eventually(async() => { + await eventually(async () => { const wins = await browser.windows.getAll(); assert.strictEqual(wins.length, 2); const tabs = await browser.tabs.query({ windowId: wins[1].id }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/google?q=an%20apple')) + assert.strictEqual(url.href, server.url("/google?q=an%20apple")); }); }); - it('should open certain search page for keywords by winopen command ', async() => { + it("should open certain search page for keywords by winopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('winopen yahoo an apple'); + await console.execCommand("winopen yahoo an apple"); - await eventually(async() => { + await eventually(async () => { const wins = await browser.windows.getAll(); assert.strictEqual(wins.length, 2); const tabs = await browser.tabs.query({ windowId: wins[1].id }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple')) + assert.strictEqual(url.href, server.url("/yahoo?q=an%20apple")); }); }); - it('should open default engine with empty keywords by winopen command ', async() => { + it("should open default engine with empty keywords by winopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('winopen'); + await console.execCommand("winopen"); - await eventually(async() => { + await eventually(async () => { const wins = await browser.windows.getAll(); assert.strictEqual(wins.length, 2); const tabs = await browser.tabs.query({ windowId: wins[1].id }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/google?q=')) + assert.strictEqual(url.href, server.url("/google?q=")); }); }); - it('should open certain search page for empty keywords by winopen command ', async() => { + it("should open certain search page for empty keywords by winopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('winopen yahoo'); + await console.execCommand("winopen yahoo"); - await eventually(async() => { + await eventually(async () => { const wins = await browser.windows.getAll(); assert.strictEqual(wins.length, 2); const tabs = await browser.tabs.query({ windowId: wins[1].id }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, server.url('/yahoo?q=')) + assert.strictEqual(url.href, server.url("/yahoo?q=")); }); }); - it('should open a site with domain by winopen command ', async() => { + it("should open a site with domain by winopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('winopen example.com'); + await console.execCommand("winopen example.com"); - await eventually(async() => { + await eventually(async () => { const wins = await browser.windows.getAll(); assert.strictEqual(wins.length, 2); const tabs = await browser.tabs.query({ windowId: wins[1].id }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, 'http://example.com/') + assert.strictEqual(url.href, "http://example.com/"); }); }); - it('should open a site with URL by winopen command ', async() => { + it("should open a site with URL by winopen command ", async () => { const console = await page.showConsole(); - await console.execCommand('winopen https://example.com/'); + await console.execCommand("winopen https://example.com/"); - await eventually(async() => { + await eventually(async () => { const wins = await browser.windows.getAll(); assert.strictEqual(wins.length, 2); const tabs = await browser.tabs.query({ windowId: wins[1].id }); const url = new URL(tabs[0].url); - assert.strictEqual(url.href, 'https://example.com/') + assert.strictEqual(url.href, "https://example.com/"); }); }); }); diff --git a/e2e/completion.test.ts b/e2e/completion.test.ts index 1ce430e..bc065d3 100644 --- a/e2e/completion.test.ts +++ b/e2e/completion.test.ts @@ -1,93 +1,98 @@ -import * as path from 'path'; -import * as assert from 'assert'; +import * as path from "path"; +import * as assert from "assert"; -import eventually from './eventually'; -import { Builder, Lanthan } from 'lanthan'; -import { WebDriver, Key } from 'selenium-webdriver'; -import Page from './lib/Page'; +import eventually from "./eventually"; +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 page: Page; - before(async() => { - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); }); - after(async() => { + after(async () => { if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { - page = await Page.navigateTo(webdriver, 'about:blank'); + beforeEach(async () => { + page = await Page.navigateTo(webdriver, "about:blank"); }); - it('should all commands on empty line', async() => { + it("should all commands on empty line", async () => { const console = await page.showConsole(); const items = await console.getCompletions(); assert.strictEqual(items.length, 12); - 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')) + 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() => { + it("should only commands filtered by prefix", async () => { const console = await page.showConsole(); - await console.inputKeys('b'); + await console.inputKeys("b"); const 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')) + 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() => { + it("selects completion items by <Tab>/<S-Tab> keys", async () => { const console = await page.showConsole(); - await console.inputKeys('b'); - await eventually(async() => { + await console.inputKeys("b"); + await eventually(async () => { const items = await console.getCompletions(); assert.strictEqual(items.length, 4); }); await console.sendKeys(Key.TAB); - await eventually(async() => { + await eventually(async () => { const items = await console.getCompletions(); assert.ok(items[1].highlight); - assert.strictEqual(await console.currentValue(), 'buffer'); + assert.strictEqual(await console.currentValue(), "buffer"); }); await console.sendKeys(Key.TAB, Key.TAB); - await eventually(async() => { + await eventually(async () => { const items = await console.getCompletions(); assert.ok(items[3].highlight); - assert.strictEqual(await console.currentValue(), 'bdeletes'); + assert.strictEqual(await console.currentValue(), "bdeletes"); }); await console.sendKeys(Key.TAB); - await eventually(async() => { - assert.strictEqual(await console.currentValue(), 'b'); + await eventually(async () => { + assert.strictEqual(await console.currentValue(), "b"); }); await console.sendKeys(Key.SHIFT, Key.TAB); - await eventually(async() => { + await eventually(async () => { const items = await console.getCompletions(); assert.ok(items[3].highlight); - assert.strictEqual(await console.currentValue(), 'bdeletes'); + assert.strictEqual(await console.currentValue(), "bdeletes"); }); }); }); diff --git a/e2e/completion_buffers.test.ts b/e2e/completion_buffers.test.ts index ac24753..57603f6 100644 --- a/e2e/completion_buffers.test.ts +++ b/e2e/completion_buffers.test.ts @@ -1,32 +1,34 @@ -import * as assert from 'assert'; -import * as path from 'path'; +import * as assert from "assert"; +import * as path from "path"; -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'; +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("completion on buffer/bdelete/bdeletes", () => { - const server = new TestServer().handle('/*', (req: Request, res: Response) => { - res.send(` + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); @@ -34,26 +36,29 @@ describe("completion on buffer/bdelete/bdeletes", () => { await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const 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.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 browser.tabs.create({ url: server.url("/site" + i) }); } - await eventually(async() => { + await eventually(async () => { const handles = await webdriver.getAllWindowHandles(); assert.strictEqual(handles.length, 5); await webdriver.switchTo().window(handles[2]); @@ -62,114 +67,114 @@ describe("completion on buffer/bdelete/bdeletes", () => { page = await Page.currentContext(webdriver); }); - it('should all tabs by "buffer" command with empty params', async() => { + it('should all tabs by "buffer" command with empty params', async () => { const console = await page.showConsole(); - await console.inputKeys('buffer '); + await console.inputKeys("buffer "); - await eventually(async() => { + await eventually(async () => { const 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('#')); + 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() => { + it('should filter items with URLs by keywords on "buffer" command', async () => { const console = await page.showConsole(); - await console.inputKeys('buffer title_site2'); + await console.inputKeys("buffer title_site2"); - await eventually(async() => { + await eventually(async () => { const 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'))); + 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() => { + it('should filter items with titles by keywords on "buffer" command', async () => { const console = await page.showConsole(); - await console.inputKeys('buffer /site2'); + await console.inputKeys("buffer /site2"); - await eventually(async() => { + await eventually(async () => { const items = await console.getCompletions(); - assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' }); - assert.ok(items[1].text.startsWith('2:')); + 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() => { + it('should show one item by number on "buffer" command', async () => { const console = await page.showConsole(); - await console.inputKeys('buffer 2'); + await console.inputKeys("buffer 2"); - await eventually(async() => { + await eventually(async () => { const items = await console.getCompletions(); assert.strictEqual(items.length, 2); - assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' }); - assert.ok(items[1].text.startsWith('2:')); + assert.deepStrictEqual(items[0], { type: "title", text: "Buffers" }); + assert.ok(items[1].text.startsWith("2:")); }); }); - it('should show unpinned tabs "bdelete" command', async() => { + it('should show unpinned tabs "bdelete" command', async () => { const console = await page.showConsole(); - await console.inputKeys('bdelete site'); + await console.inputKeys("bdelete site"); - await eventually(async() => { + await eventually(async () => { const 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')); + 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() => { + it('should show unpinned tabs "bdeletes" command', async () => { const console = await page.showConsole(); - await console.inputKeys('bdeletes site'); + await console.inputKeys("bdeletes site"); - await eventually(async() => { + await eventually(async () => { const 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')); + 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() => { + it('should show both pinned and unpinned tabs "bdelete!" command', async () => { const console = await page.showConsole(); - await console.inputKeys('bdelete! site'); + await console.inputKeys("bdelete! site"); - await eventually(async() => { + await eventually(async () => { const 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')); + 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() => { + it('should show both pinned and unpinned tabs "bdeletes!" command', async () => { const console = await page.showConsole(); - await console.inputKeys('bdeletes! site'); + await console.inputKeys("bdeletes! site"); - await eventually(async() => { + await eventually(async () => { const 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')); + 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.ts b/e2e/completion_open.test.ts index 95d4175..cefb44f 100644 --- a/e2e/completion_open.test.ts +++ b/e2e/completion_open.test.ts @@ -1,159 +1,202 @@ -import * as path from 'path'; -import * as assert from 'assert'; +import * as path from "path"; +import * as assert from "assert"; import Settings from "../src/shared/settings/Settings"; -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 TestServer from "./lib/TestServer"; +import eventually from "./eventually"; +import { Builder, Lanthan } from "lanthan"; +import { WebDriver } from "selenium-webdriver"; +import Page from "./lib/Page"; import SettingRepository from "./lib/SettingRepository"; describe("completion on open/tabopen/winopen commands", () => { - const server = new TestServer().receiveContent('/*', 'ok'); + const server = new TestServer().receiveContent("/*", "ok"); let lanthan: Lanthan; let webdriver: WebDriver; let browser: any; let page: Page; - before(async() => { + before(async () => { await server.start(); - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); // Add item into hitories - await webdriver.navigate().to(('https://example.com/')); + await webdriver.navigate().to("https://example.com/"); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { page = await Page.navigateTo(webdriver, server.url()); }); - it('should show completions from search engines, bookmarks, and histories by "open" command', async() => { + it('should show completions from search engines, bookmarks, and histories by "open" command', async () => { const console = await page.showConsole(); - await console.inputKeys('open '); + await console.inputKeys("open "); - await eventually(async() => { + await eventually(async () => { const 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')); + 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() => { + it('should filter items with URLs by keywords on "open" command', async () => { const console = await page.showConsole(); - await console.inputKeys('open https://'); + await console.inputKeys("open https://"); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const items = completions.filter(x => x.type === 'item').map(x => x.text); - assert.ok(items.every(x => x.includes('https://'))); + const 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() => { + it('should filter items with titles by keywords on "open" command', async () => { const console = await page.showConsole(); - await console.inputKeys('open getting'); + await console.inputKeys("open getting"); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const items = completions.filter(x => x.type === 'item').map(x => x.text); - assert.ok(items.every(x => x.toLowerCase().includes('getting'))); + const 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() => { + it('should filter items with titles by keywords on "tabopen" command', async () => { const console = await page.showConsole(); - await console.inputKeys('tabopen getting'); + await console.inputKeys("tabopen getting"); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const items = completions.filter(x => x.type === 'item').map(x => x.text); - assert.ok(items.every(x => x.includes('https://'))); + const 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() => { + it('should filter items with titles by keywords on "winopen" command', async () => { const console = await page.showConsole(); - await console.inputKeys('winopen https://'); + await console.inputKeys("winopen https://"); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const items = completions.filter(x => x.type === 'item').map(x => x.text); - assert.ok(items.every(x => x.includes('https://'))); + const 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() => { + 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 console.execCommand("set complete=sbh"); await (webdriver.switchTo() as any).parentFrame(); console = await page.showConsole(); - await console.inputKeys('open '); + await console.inputKeys("open "); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepStrictEqual(titles, ['Search Engines', 'Bookmarks', 'History']) + const 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 console.execCommand("set complete=bss"); await (webdriver.switchTo() as any).parentFrame(); console = await page.showConsole(); - await console.inputKeys('open '); + await console.inputKeys("open "); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepStrictEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines']) + const 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() => { - new SettingRepository(browser).saveJSON(Settings.fromJSON({ - properties: { complete: "sbh" }, - })); + it('should display only specified items in "complete" property by setting', async () => { + new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + properties: { complete: "sbh" }, + }) + ); let console = await page.showConsole(); - await console.inputKeys('open '); + await console.inputKeys("open "); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepStrictEqual(titles, ['Search Engines', 'Bookmarks', 'History']) + const 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(); - new SettingRepository(browser).saveJSON(Settings.fromJSON({ - properties: { complete: "bss" }, - })); + new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + properties: { complete: "bss" }, + }) + ); console = await page.showConsole(); - await console.inputKeys('open '); + await console.inputKeys("open "); - await eventually(async() => { + await eventually(async () => { const completions = await console.getCompletions(); - const titles = completions.filter(x => x.type === 'title').map(x => x.text); - assert.deepStrictEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines']) + const 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.ts b/e2e/completion_set.test.ts index 7e9714c..3a139fe 100644 --- a/e2e/completion_set.test.ts +++ b/e2e/completion_set.test.ts @@ -1,57 +1,56 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +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 page: Page; - before(async() => { - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); }); - after(async() => { + after(async () => { if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { page = await Page.navigateTo(webdriver, `about:blank`); }); - it('should show all property names by "set" command with empty params', async() => { + it('should show all property names by "set" command with empty params', async () => { const console = await page.showConsole(); - await console.inputKeys('set '); + await console.inputKeys("set "); - await eventually(async() => { + await eventually(async () => { const 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')) + 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() => { + it('should show filtered property names by "set" command', async () => { const console = await page.showConsole(); - await console.inputKeys('set no'); + await console.inputKeys("set no"); - await eventually(async() => { + await eventually(async () => { const items = await console.getCompletions(); assert.strictEqual(items.length, 2); - assert.ok(items[1].text.includes('nosmoothscroll')) + assert.ok(items[1].text.includes("nosmoothscroll")); }); }); }); diff --git a/e2e/console.test.ts b/e2e/console.test.ts index 1d441f9..18b717f 100644 --- a/e2e/console.test.ts +++ b/e2e/console.test.ts @@ -1,90 +1,93 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +import TestServer from "./lib/TestServer"; +import { Builder, Lanthan } from "lanthan"; +import { WebDriver, Key } from "selenium-webdriver"; +import Page from "./lib/Page"; describe("console test", () => { - const server = new TestServer().receiveContent('/', - `<!DOCTYPE html><html lang="en"><head><title>Hello, world!</title></head></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { page = await Page.navigateTo(webdriver, server.url()); }); - it('open console with :', async() => { - await page.sendKeys(':'); + it("open console with :", async () => { + await page.sendKeys(":"); const console = await page.getConsole(); - assert.strictEqual(await console.currentValue(), ''); + assert.strictEqual(await console.currentValue(), ""); }); - it('open console with open command by o', async() => { - await page.sendKeys('o'); + it("open console with open command by o", async () => { + await page.sendKeys("o"); const console = await page.getConsole(); - assert.strictEqual(await console.currentValue(), 'open '); + assert.strictEqual(await console.currentValue(), "open "); }); - it('open console with open command and current URL by O', async() => { - await page.sendKeys(Key.SHIFT, 'o'); + it("open console with open command and current URL by O", async () => { + await page.sendKeys(Key.SHIFT, "o"); const 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'); + it("open console with tabopen command by t", async () => { + await page.sendKeys("t"); const console = await page.getConsole(); - assert.strictEqual(await console.currentValue(), 'tabopen '); + assert.strictEqual(await console.currentValue(), "tabopen "); }); - it('open console with tabopen command and current URL by T', async() => { - await page.sendKeys(Key.SHIFT, 't'); + it("open console with tabopen command and current URL by T", async () => { + await page.sendKeys(Key.SHIFT, "t"); const 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'); + it("open console with winopen command by w", async () => { + await page.sendKeys("w"); const 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'); + it("open console with winopen command and current URL by W", async () => { + await page.sendKeys(Key.SHIFT, "W"); const 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'); + it("open console with buffer command by b", async () => { + await page.sendKeys("b"); const 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'); + it("open console with addbookmark command with title by a", async () => { + await page.sendKeys("a"); const console = await page.getConsole(); - assert.strictEqual(await console.currentValue(), `addbookmark Hello, world!`); + assert.strictEqual( + await console.currentValue(), + `addbookmark Hello, world!` + ); }); }); diff --git a/e2e/eventually.ts b/e2e/eventually.ts index b0a2dfc..9d21022 100644 --- a/e2e/eventually.ts +++ b/e2e/eventually.ts @@ -1,19 +1,19 @@ const defaultInterval = 100; const defaultTimeout = 2000; -type Handler = () => void +type Handler = () => void; const sleep = (ms: number): Promise<void> => { - return new Promise(resolve => setTimeout(resolve, ms)); -} - + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + const eventually = async ( fn: Handler, timeout = defaultTimeout, - interval = defaultInterval, + interval = defaultInterval ): Promise<void> => { const start = Date.now(); - const loop = async() => { + const loop = async () => { try { await fn(); } catch (err) { diff --git a/e2e/find.test.ts b/e2e/find.test.ts index 74097ab..accf37b 100644 --- a/e2e/find.test.ts +++ b/e2e/find.test.ts @@ -1,42 +1,42 @@ -import * as path from 'path'; -import * as assert from 'assert'; +import * as path from "path"; +import * as assert from "assert"; -import eventually from './eventually'; -import TestServer from './lib/TestServer'; -import { Builder, Lanthan } from 'lanthan'; -import { Key, WebDriver } from 'selenium-webdriver'; -import Page from './lib/Page'; +import eventually from "./eventually"; +import TestServer from "./lib/TestServer"; +import { Builder, Lanthan } from "lanthan"; +import { Key, WebDriver } from "selenium-webdriver"; +import Page from "./lib/Page"; describe("find test", () => { - const server = new TestServer().receiveContent('/', - `<!DOCTYPE html><html lang="en"><body>--hello--hello--hello--</body></html>`, + const server = new TestServer().receiveContent( + "/", + `<!DOCTYPE html><html lang="en"><body>--hello--hello--hello--</body></html>` ); let lanthan: Lanthan; let webdriver: WebDriver; let page: Page; - before(async() => { - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { page = await Page.navigateTo(webdriver, server.url()); }); - it('starts searching', async() => { - await page.sendKeys('/'); + it("starts searching", async () => { + await page.sendKeys("/"); const console = await page.getConsole(); await console.execCommand("hello"); await page.switchToTop(); @@ -60,53 +60,53 @@ describe("find test", () => { assert.deepStrictEqual(selection, { from: 16, to: 21 }); }); - it('shows error if pattern not found', async() => { - await page.sendKeys('/'); + it("shows error if pattern not found", async () => { + await page.sendKeys("/"); let console = await page.getConsole(); - await console.execCommand('world'); + await console.execCommand("world"); await page.switchToTop(); const selection = await page.getSelection(); assert.deepStrictEqual(selection, { from: 0, to: 0 }); - await eventually(async() => { + await eventually(async () => { console = await page.getConsole(); const message = await console.getErrorMessage(); - assert.strictEqual(message, 'Pattern not found: world'); + assert.strictEqual(message, "Pattern not found: world"); }); }); - it('search with last keyword if keyword is empty', async() => { - await page.sendKeys('/'); + it("search with last keyword if keyword is empty", async () => { + await page.sendKeys("/"); let console = await page.getConsole(); - await console.execCommand('hello'); + await console.execCommand("hello"); await page.switchToTop(); await page.clearSelection(); let selection = await page.getSelection(); assert.deepStrictEqual(selection, { from: 0, to: 0 }); - await page.sendKeys('/'); + await page.sendKeys("/"); console = await page.getConsole(); - await console.execCommand(''); + await console.execCommand(""); await page.switchToTop(); selection = await page.getSelection(); assert.deepStrictEqual(selection, { from: 2, to: 7 }); }); - it('search with last keyword on new page', async() => { - await page.sendKeys('/'); + it("search with last keyword on new page", async () => { + await page.sendKeys("/"); const console = await page.getConsole(); - await console.execCommand('hello'); + await console.execCommand("hello"); await page.switchToTop(); - await page.sendKeys('n'); + await page.sendKeys("n"); let selection = await page.getSelection(); assert.deepStrictEqual(selection, { from: 9, to: 14 }); page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('n'); + await page.sendKeys("n"); selection = await page.getSelection(); assert.deepStrictEqual(selection, { from: 2, to: 7 }); }); diff --git a/e2e/follow.test.ts b/e2e/follow.test.ts index 62a109f..5fb6c58 100644 --- a/e2e/follow.test.ts +++ b/e2e/follow.test.ts @@ -1,28 +1,36 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +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 = () => { const server = new TestServer(); - server.receiveContent('/', ` + server.receiveContent( + "/", + ` <!DOCTYPE html> <html lang="en"><body> <a href="hello">hello</a> - </body></html>`); + </body></html>` + ); - server.receiveContent('/follow-input', ` + server.receiveContent( + "/follow-input", + ` <!DOCTYPE html> <html lang="en"><body> <input> - </body></html>`); + </body></html>` + ); - server.receiveContent('/area', ` + server.receiveContent( + "/area", + ` <!DOCTYPE html> <html lang="en"><body> <img @@ -34,7 +42,8 @@ const newApp = () => { <area shape="rect" coords="64,64,64,64" href="/"> <area shape="rect" coords="128,128,64,64" href="/"> </map> - </body></html>`); + </body></html>` + ); /* * test case: link2 is out of the viewport @@ -46,168 +55,186 @@ const newApp = () => { * | | * +-----------------+ */ - server.receiveContent('/test1', ` + 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', ` + </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', ` + </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', ` + </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', ` + </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>`); + </body></html>` + ); return server; }; -describe('follow test', () => { +describe("follow test", () => { const server = newApp(); let lanthan: Lanthan; let webdriver: WebDriver; let browser: any; - before(async() => { - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - afterEach(async() => { + afterEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } }); - it('should focus an input by f', async () => { - const page = await Page.navigateTo(webdriver, server.url('/follow-input')); - await page.sendKeys('f'); + it("should focus an input by f", async () => { + const page = await Page.navigateTo(webdriver, server.url("/follow-input")); + await page.sendKeys("f"); await page.waitAndGetHints(); - await page.sendKeys('a'); + await page.sendKeys("a"); - const tagName = await webdriver.executeScript(() => document.activeElement!!.tagName) as string; - assert.strictEqual(tagName.toLowerCase(), 'input'); + const tagName = (await webdriver.executeScript( + () => document.activeElement!!.tagName + )) as string; + assert.strictEqual(tagName.toLowerCase(), "input"); }); - it('should open a link by f', async () => { + it("should open a link by f", async () => { const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('f'); + await page.sendKeys("f"); await page.waitAndGetHints(); - await page.sendKeys('a'); + await page.sendKeys("a"); - await eventually(async() => { - const hash = await webdriver.executeScript('return location.pathname'); - assert.strictEqual(hash, '/hello'); + await eventually(async () => { + const hash = await webdriver.executeScript("return location.pathname"); + assert.strictEqual(hash, "/hello"); }); }); - it('should focus an input by F', async () => { - const page = await Page.navigateTo(webdriver, server.url('/follow-input')); - await page.sendKeys(Key.SHIFT, 'f'); + it("should focus an input by F", async () => { + const page = await Page.navigateTo(webdriver, server.url("/follow-input")); + await page.sendKeys(Key.SHIFT, "f"); await page.waitAndGetHints(); - await page.sendKeys('a'); + await page.sendKeys("a"); - const tagName = await webdriver.executeScript(() => document.activeElement!!.tagName) as string; - assert.strictEqual(tagName.toLowerCase(), 'input'); + const 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 () => { + it("should open a link to new tab by F", async () => { const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys(Key.SHIFT, 'f'); + await page.sendKeys(Key.SHIFT, "f"); await page.waitAndGetHints(); - await page.sendKeys('a'); + await page.sendKeys("a"); - await eventually(async() => { + await eventually(async () => { const tabs = await browser.tabs.query({}); assert.strictEqual(tabs.length, 2); - assert.strictEqual(new URL(tabs[1].url).pathname, '/hello'); + 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 () => { - const page = await Page.navigateTo(webdriver, server.url('/area')); - await page.sendKeys(Key.SHIFT, 'f'); + it("should show hints of links in area", async () => { + const page = await Page.navigateTo(webdriver, server.url("/area")); + await page.sendKeys(Key.SHIFT, "f"); const hints = await page.waitAndGetHints(); assert.strictEqual(hints.length, 3); }); - it('should shows hints only in viewport', async () => { - const page = await Page.navigateTo(webdriver, server.url('/test1')); - await page.sendKeys(Key.SHIFT, 'f'); + it("should shows hints only in viewport", async () => { + const page = await Page.navigateTo(webdriver, server.url("/test1")); + await page.sendKeys(Key.SHIFT, "f"); const hints = await page.waitAndGetHints(); assert.strictEqual(hints.length, 1); }); - it('should shows hints only in window of the frame', async () => { - const page = await Page.navigateTo(webdriver, server.url('/test2')); - await page.sendKeys(Key.SHIFT, 'f'); + it("should shows hints only in window of the frame", async () => { + const page = await Page.navigateTo(webdriver, server.url("/test2")); + await page.sendKeys(Key.SHIFT, "f"); await webdriver.switchTo().frame(0); const hints = await page.waitAndGetHints(); assert.strictEqual(hints.length, 1); }); - it('should shows hints only in the frame', async () => { - const page = await Page.navigateTo(webdriver, server.url('/test3')); - await page.sendKeys(Key.SHIFT, 'f'); + it("should shows hints only in the frame", async () => { + const page = await Page.navigateTo(webdriver, server.url("/test3")); + await page.sendKeys(Key.SHIFT, "f"); await webdriver.switchTo().frame(0); const hints = await page.waitAndGetHints(); diff --git a/e2e/follow_properties.test.ts b/e2e/follow_properties.test.ts index 78597a5..4f2a5b8 100644 --- a/e2e/follow_properties.test.ts +++ b/e2e/follow_properties.test.ts @@ -1,16 +1,18 @@ -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'; +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"; import SettingRepository from "./lib/SettingRepository"; import Settings from "../src/shared/settings/Settings"; -describe('follow properties test', () => { - const server = new TestServer().receiveContent('/', ` +describe("follow properties test", () => { + const server = new TestServer().receiveContent( + "/", + ` <!DOCTYPE html> <html lang="en"><body> <a href="/">link1</a> @@ -18,67 +20,69 @@ describe('follow properties test', () => { <a href="/">link3</a> <a href="/">link4</a> <a href="/">link5</a> - </body></html>`); + </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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - "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 } - }, - "properties": { - "hintchars": "jk" - } - })); + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + 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 }, + }, + properties: { + hintchars: "jk", + }, + }) + ); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { page = await Page.navigateTo(webdriver, server.url()); }); - afterEach(async() => { + afterEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } }); - it('should show hints with hintchars by settings', async () => { - await page.sendKeys('f'); + 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'); + 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'); + await page.sendKeys("j"); hints = await page.waitAndGetHints(); assert.strictEqual(hints[0].displayed, true); @@ -88,45 +92,45 @@ describe('follow properties test', () => { assert.strictEqual(hints[4].displayed, false); }); - it('should open tab in background by background:false', async () => { - await page.sendKeys(Key.SHIFT, 'f'); + it("should open tab in background by background:false", async () => { + await page.sendKeys(Key.SHIFT, "f"); await page.waitAndGetHints(); - await page.sendKeys('jj'); + await page.sendKeys("jj"); - await eventually(async() => { + await eventually(async () => { const 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'); + it("should open tab in background by background:true", async () => { + await page.sendKeys(Key.CONTROL, "f"); await page.waitAndGetHints(); - await page.sendKeys('jj'); + await page.sendKeys("jj"); - await eventually(async() => { + await eventually(async () => { const 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 () => { + it("should show hints with hintchars by settings", async () => { const console = await page.showConsole(); - await console.execCommand('set hintchars=abc'); + await console.execCommand("set hintchars=abc"); await (webdriver.switchTo() as any).parentFrame(); - await page.sendKeys('f'); + 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'); + 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'); + await page.sendKeys("a"); hints = await page.waitAndGetHints(); assert.strictEqual(hints[0].displayed, true); assert.strictEqual(hints[1].displayed, false); diff --git a/e2e/lib/Console.ts b/e2e/lib/Console.ts index e3bd2d6..68c0e10 100644 --- a/e2e/lib/Console.ts +++ b/e2e/lib/Console.ts @@ -1,64 +1,73 @@ -import { WebDriver, By, Key } from 'selenium-webdriver'; +import { WebDriver, By, Key } from "selenium-webdriver"; export type CompletionItem = { type: string; text: string; highlight: boolean; -} +}; export class Console { - constructor(private webdriver: WebDriver) { - } + constructor(private webdriver: WebDriver) {} async sendKeys(...keys: string[]) { - const input = await this.webdriver.findElement(By.css('input')); + const input = await this.webdriver.findElement(By.css("input")); input.sendKeys(...keys); } async currentValue() { return await this.webdriver.executeScript(() => { - const input = document.querySelector('input'); + const input = document.querySelector("input"); if (input === null) { - throw new Error('could not find input element'); + throw new Error("could not find input element"); } return input.value; }); } async execCommand(command: string): Promise<void> { - const input = await this.webdriver.findElement(By.css('input.vimvixen-console-command-input')); + const input = await this.webdriver.findElement( + By.css("input.vimvixen-console-command-input") + ); await input.sendKeys(command, Key.ENTER); } async getErrorMessage(): Promise<string> { - const p = await this.webdriver.findElement(By.css('.vimvixen-console-error')); + const p = await this.webdriver.findElement( + By.css(".vimvixen-console-error") + ); return p.getText(); } async getInformationMessage(): Promise<string> { - const p = await this.webdriver.findElement(By.css('.vimvixen-console-info')); + const p = await this.webdriver.findElement( + By.css(".vimvixen-console-info") + ); return p.getText(); } async inputKeys(...keys: string[]) { - const input = await this.webdriver.findElement(By.css('input')); + const input = await this.webdriver.findElement(By.css("input")); await input.sendKeys(...keys); } getCompletions(): Promise<CompletionItem[]> { return this.webdriver.executeScript(() => { - const items = document.querySelectorAll('.vimvixen-console-completion > li'); + const items = document.querySelectorAll( + ".vimvixen-console-completion > li" + ); if (items.length === 0) { - throw new Error('completion items not found'); + throw new Error("completion items not found"); } const objs = []; for (const 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') { - const highlight = li.classList.contains('vimvixen-completion-selected'); - objs.push({ type: 'item', text: li.textContent!!.trim(), highlight }); + if (li.classList.contains("vimvixen-console-completion-title")) { + objs.push({ type: "title", text: li.textContent!!.trim() }); + } else if ("vimvixen-console-completion-item") { + const highlight = li.classList.contains( + "vimvixen-completion-selected" + ); + objs.push({ type: "item", text: li.textContent!!.trim(), highlight }); } else { throw new Error(`unexpected class: ${li.className}`); } @@ -68,10 +77,10 @@ export class Console { } async close(): Promise<void> { - const input = await this.webdriver.findElement(By.css('input')); + const input = await this.webdriver.findElement(By.css("input")); await input.sendKeys(Key.ESCAPE); // TODO remove sleep - await new Promise(resolve => setTimeout(resolve, 100)); + 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 index 33ce2a7..5551684 100644 --- a/e2e/lib/FormOptionPage.ts +++ b/e2e/lib/FormOptionPage.ts @@ -1,5 +1,5 @@ -import { Lanthan } from 'lanthan'; -import { WebDriver, By, until } from 'selenium-webdriver'; +import { Lanthan } from "lanthan"; +import { WebDriver, By, until } from "selenium-webdriver"; export default class FormOptionPage { private webdriver: WebDriver; @@ -9,92 +9,136 @@ export default class FormOptionPage { } async setBlacklist(nth: number, url: string): Promise<void> { - const selector = '.form-blacklist-form-row > .column-url'; + const selector = ".form-blacklist-form-row > .column-url"; const inputs = await this.webdriver.findElements(By.css(selector)); if (inputs.length <= nth) { - throw new RangeError('Index out of range to set a blacklist') + throw new RangeError("Index out of range to set a blacklist"); } await inputs[nth].sendKeys(url); - await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); + await this.webdriver.executeScript( + `document.querySelectorAll('${selector}')[${nth}].blur()` + ); } - async setPartialBlacklist(nth: number, url: string, keys: string): Promise<void> { - let selector = '.form-partial-blacklist-form-row > .column-url'; + async setPartialBlacklist( + nth: number, + url: string, + keys: string + ): Promise<void> { + let selector = ".form-partial-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 partial blacklist') + throw new RangeError("Index out of range to set a partial blacklist"); } await inputs[nth].sendKeys(url); - await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); + await this.webdriver.executeScript( + `document.querySelectorAll('${selector}')[${nth}].blur()` + ); - selector = '.form-partial-blacklist-form-row > .column-keys'; + selector = ".form-partial-blacklist-form-row > .column-keys"; inputs = await this.webdriver.findElements(By.css(selector)); if (inputs.length <= nth) { - throw new RangeError('Index out of range to set a partial blacklist') + throw new RangeError("Index out of range to set a partial blacklist"); } await inputs[nth].sendKeys(keys); - await this.webdriver.executeScript(`document.querySelectorAll('${selector}')[${nth}].blur()`); + 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 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') + 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()`); + await this.webdriver.executeScript( + `document.querySelectorAll('${selector}')[${nth}].blur()` + ); - selector = '.form-search-form-row > .column-url'; + 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') + 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()`); + await this.webdriver.executeScript( + `document.querySelectorAll('${selector}')[${nth}].blur()` + ); } async addBlacklist(): Promise<void> { - const rows = await this.webdriver.findElements(By.css(`.form-blacklist-form-row`)); - const button = await this.webdriver.findElement(By.css('.form-blacklist-form .ui-add-button')) + const rows = await this.webdriver.findElements( + By.css(`.form-blacklist-form-row`) + ); + const 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})`))); + await this.webdriver.wait( + until.elementLocated( + By.css(`.form-blacklist-form-row:nth-child(${rows.length + 1})`) + ) + ); } async addPartialBlacklist(): Promise<void> { - const rows = await this.webdriver.findElements(By.css(`.form-partial-blacklist-form-row`)); - const button = await this.webdriver.findElement(By.css('.form-partial-blacklist-form .ui-add-button')) + const rows = await this.webdriver.findElements( + By.css(`.form-partial-blacklist-form-row`) + ); + const button = await this.webdriver.findElement( + By.css(".form-partial-blacklist-form .ui-add-button") + ); await button.click(); - await this.webdriver.wait(until.elementLocated(By.css(`.form-partial-blacklist-form-row:nth-child(${rows.length + 2})`))); + await this.webdriver.wait( + until.elementLocated( + By.css(`.form-partial-blacklist-form-row:nth-child(${rows.length + 2})`) + ) + ); } async removeBlackList(nth: number): Promise<void> { - const buttons = await this.webdriver.findElements(By.css('.form-blacklist-form-row .ui-delete-button')); + const 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') + throw new RangeError("Index out of range to remove blacklist"); } - await buttons[nth].click() + await buttons[nth].click(); } async removePartialBlackList(nth: number): Promise<void> { - const buttons = await this.webdriver.findElements(By.css('.form-partial-blacklist-form-row .ui-delete-button')); + const buttons = await this.webdriver.findElements( + By.css(".form-partial-blacklist-form-row .ui-delete-button") + ); if (buttons.length <= nth) { - throw new RangeError('Index out of range to remove partial blacklist') + throw new RangeError("Index out of range to remove partial blacklist"); } - await buttons[nth].click() + await buttons[nth].click(); } async addSearchEngine(): Promise<void> { - const rows = await this.webdriver.findElements(By.css(`.form-search-form-row > .column-name`)); - const button = await this.webdriver.findElement(By.css('.form-search-form > .ui-add-button')) + const rows = await this.webdriver.findElements( + By.css(`.form-search-form-row > .column-name`) + ); + const 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})`))); + await this.webdriver.wait( + until.elementLocated( + By.css(`.form-search-form-row:nth-child(${rows.length + 1})`) + ) + ); } async setDefaultSearchEngine(nth: number): Promise<void> { - const radios = await this.webdriver.findElements(By.css('.form-search-form-row input[type=radio]')); + const 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'); + 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 index d6ed7ee..1c2db5b 100644 --- a/e2e/lib/JSONOptionPage.ts +++ b/e2e/lib/JSONOptionPage.ts @@ -1,5 +1,5 @@ -import { Lanthan } from 'lanthan'; -import { WebDriver, By } from 'selenium-webdriver'; +import { Lanthan } from "lanthan"; +import { WebDriver, By } from "selenium-webdriver"; export default class JSONOptionPage { private webdriver: WebDriver; @@ -9,14 +9,20 @@ export default class JSONOptionPage { } async updateSettings(value: string): Promise<void> { - const 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()); + const 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> { - const error = await this.webdriver.findElement(By.css('.settings-ui-input-error')); + const 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 index 9f994a0..e1ea759 100644 --- a/e2e/lib/OptionPage.ts +++ b/e2e/lib/OptionPage.ts @@ -1,7 +1,7 @@ -import { Lanthan } from 'lanthan'; -import { WebDriver, By } from 'selenium-webdriver'; -import JSONOptionPage from './JSONOptionPage'; -import FormOptionPage from './FormOptionPage'; +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; @@ -11,13 +11,17 @@ export default class OptionPage { } static async open(lanthan: Lanthan) { - const url = await lanthan.getWebExtBrowser().runtime.getURL("build/settings.html") + const url = await lanthan + .getWebExtBrowser() + .runtime.getURL("build/settings.html"); await lanthan.getWebDriver().navigate().to(url); return new OptionPage(lanthan); } async switchToForm(): Promise<FormOptionPage> { - const useFormInput = await this.webdriver.findElement(By.css('#setting-source-form')); + const useFormInput = await this.webdriver.findElement( + By.css("#setting-source-form") + ); await useFormInput.click(); await this.webdriver.switchTo().alert().accept(); return new FormOptionPage(this.lanthan); diff --git a/e2e/lib/Page.ts b/e2e/lib/Page.ts index 31605cb..85bda8d 100644 --- a/e2e/lib/Page.ts +++ b/e2e/lib/Page.ts @@ -1,19 +1,18 @@ -import { WebDriver, By, until } from 'selenium-webdriver'; -import { Console } from './Console'; +import { WebDriver, By, until } from "selenium-webdriver"; +import { Console } from "./Console"; type Hint = { - displayed: boolean, - text: string, + displayed: boolean; + text: string; }; type Selection = { - from: number, - to: number, + from: number; + to: number; }; export default class Page { - private constructor(private webdriver: WebDriver) { - } + private constructor(private webdriver: WebDriver) {} static async currentContext(webdriver: WebDriver): Promise<Page> { await Page.waitForConsoleLoaded(webdriver); @@ -26,8 +25,10 @@ export default class Page { return new Page(webdriver); } - async sendKeys(...keys: Array<string|number|Promise<string|number>>): Promise<void> { - const body = await this.webdriver.findElement(By.css('body')); + async sendKeys( + ...keys: Array<string | number | Promise<string | number>> + ): Promise<void> { + const body = await this.webdriver.findElement(By.css("body")); await body.sendKeys(...keys); } @@ -38,17 +39,23 @@ export default class Page { } async showConsole(): Promise<Console> { - const iframe = this.webdriver.findElement(By.css('#vimvixen-console-frame')); + const iframe = this.webdriver.findElement( + By.css("#vimvixen-console-frame") + ); - await this.sendKeys(':'); + 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'))); + await this.webdriver.wait( + until.elementLocated(By.css("input.vimvixen-console-command-input")) + ); return new Console(this.webdriver); } async getConsole(): Promise<Console> { - const iframe = this.webdriver.findElement(By.css('#vimvixen-console-frame')); + const iframe = this.webdriver.findElement( + By.css("#vimvixen-console-frame") + ); await this.webdriver.wait(until.elementIsVisible(iframe)); await this.webdriver.switchTo().frame(0); @@ -68,16 +75,22 @@ export default class Page { } pageHeight(): Promise<number> { - return this.webdriver.executeScript(() => window.document.documentElement.clientHeight); + return this.webdriver.executeScript( + () => window.document.documentElement.clientHeight + ); } async getSelection(): Promise<Selection> { - const obj = await this.webdriver.executeScript(`return window.getSelection();`) as any; + const obj = (await this.webdriver.executeScript( + `return window.getSelection();` + )) as any; return { from: obj.anchorOffset, to: obj.focusOffset }; } async clearSelection(): Promise<void> { - await this.webdriver.executeScript(`window.getSelection().removeAllRanges()`); + await this.webdriver.executeScript( + `window.getSelection().removeAllRanges()` + ); } async switchToTop(): Promise<void> { @@ -85,15 +98,17 @@ export default class Page { } async waitAndGetHints(): Promise<Hint[]> { - await this.webdriver.wait(until.elementsLocated(By.css('.vimvixen-hint'))); + await this.webdriver.wait(until.elementsLocated(By.css(".vimvixen-hint"))); - const elements = await this.webdriver.findElements(By.css(`.vimvixen-hint`)); + const elements = await this.webdriver.findElements( + By.css(`.vimvixen-hint`) + ); const hints = []; for (const e of elements) { - const display = await e.getCssValue('display'); + const display = await e.getCssValue("display"); const text = await e.getText(); hints.push({ - displayed: display !== 'none', + displayed: display !== "none", text: text, }); } @@ -105,7 +120,9 @@ export default class Page { if (!topFrame) { return; } - await webdriver.wait(until.elementLocated(By.css('iframe.vimvixen-console-frame'))); - await new Promise(resolve => setTimeout(resolve, 100)); + await webdriver.wait( + until.elementLocated(By.css("iframe.vimvixen-console-frame")) + ); + await new Promise((resolve) => setTimeout(resolve, 100)); } } diff --git a/e2e/lib/SettingRepository.ts b/e2e/lib/SettingRepository.ts index 3bdf6d2..87fb50b 100644 --- a/e2e/lib/SettingRepository.ts +++ b/e2e/lib/SettingRepository.ts @@ -1,18 +1,15 @@ -import { JSONTextSettings, SettingSource } from '../../src/shared/SettingData'; -import Settings from '../../src/shared/settings/Settings'; +import { JSONTextSettings, SettingSource } from "../../src/shared/SettingData"; +import Settings from "../../src/shared/settings/Settings"; export default class SettingRepository { - constructor( - private readonly browser: any, - ) { - } + constructor(private readonly browser: any) {} async saveJSON(settings: Settings): Promise<void> { await this.browser.storage.sync.set({ settings: { source: SettingSource.JSON, - json: JSONTextSettings.fromSettings(settings).toJSONText(), - } + json: JSONTextSettings.fromSettings(settings).toJSONText(), + }, }); } } diff --git a/e2e/lib/TestServer.ts b/e2e/lib/TestServer.ts index 5b9eee3..e0c711b 100644 --- a/e2e/lib/TestServer.ts +++ b/e2e/lib/TestServer.ts @@ -1,6 +1,6 @@ -import * as http from 'http'; -import * as net from 'net' -import express from 'express'; +import * as http from "http"; +import * as net from "net"; +import express from "express"; type HandlerFunc = (req: express.Request, res: express.Response) => void; @@ -9,10 +9,7 @@ export default class TestServer { private app: express.Application; - constructor( - private port = 0, - private address = '127.0.0.1', - ){ + constructor(private port = 0, private address = "127.0.0.1") { this.app = express(); } @@ -23,30 +20,30 @@ export default class TestServer { receiveContent(path: string, content: string): TestServer { this.app.get(path, (_req: express.Request, res: express.Response) => { - res.status(200).send(content) + res.status(200).send(content); }); return this; } - - url(path = '/'): string { + + url(path = "/"): string { if (!this.http) { - throw new Error('http server not started'); + throw new Error("http server not started"); } const addr = this.http.address() as net.AddressInfo; - return `http://${addr.address}:${addr.port}${path}` + return `http://${addr.address}:${addr.port}${path}`; } - start(): Promise<void> { + start(): Promise<void> { if (this.http) { - throw new Error('http server already started'); + throw new Error("http server already started"); } - this.http = http.createServer(this.app) + this.http = http.createServer(this.app); return new Promise((resolve) => { this.http!!.listen(this.port, this.address, () => { resolve(); - }) + }); }); } @@ -59,6 +56,6 @@ export default class TestServer { this.http = undefined; resolve(); }); - }) + }); } } diff --git a/e2e/lib/clipboard.ts b/e2e/lib/clipboard.ts index 297b71a..6cc94cb 100644 --- a/e2e/lib/clipboard.ts +++ b/e2e/lib/clipboard.ts @@ -1,18 +1,19 @@ -import { spawn } from 'child_process'; +import { spawn } from "child_process"; const readLinux = (): Promise<string> => { - let stdout = '', stderr = ''; + let stdout = "", + stderr = ""; return new Promise((resolve) => { - const xsel = spawn('xsel', ['--clipboard', '--output']); - xsel.stdout.on('data', (data) => { + const xsel = spawn("xsel", ["--clipboard", "--output"]); + xsel.stdout.on("data", (data) => { stdout += data; }); - xsel.stderr.on('data', (data) => { + xsel.stderr.on("data", (data) => { stderr += data; }); - xsel.on('close', (code) => { + xsel.on("close", (code) => { if (code !== 0) { - throw new Error(`xsel returns ${code}: ${stderr}`) + throw new Error(`xsel returns ${code}: ${stderr}`); } resolve(stdout); }); @@ -20,15 +21,15 @@ const readLinux = (): Promise<string> => { }; const writeLinux = (data: string): Promise<string> => { - let stderr = ''; + let stderr = ""; return new Promise((resolve) => { - const xsel = spawn('xsel', ['--clipboard', '--input']); - xsel.stderr.on('data', (data) => { + const xsel = spawn("xsel", ["--clipboard", "--input"]); + xsel.stderr.on("data", (data) => { stderr += data; }); - xsel.on('close', (code) => { + xsel.on("close", (code) => { if (code !== 0) { - throw new Error(`xsel returns ${code}: ${stderr}`) + throw new Error(`xsel returns ${code}: ${stderr}`); } resolve(); }); @@ -38,18 +39,19 @@ const writeLinux = (data: string): Promise<string> => { }; const readDarwin = (): Promise<string> => { - let stdout = '', stderr = ''; + let stdout = "", + stderr = ""; return new Promise((resolve) => { - const pbpaste = spawn('pbpaste'); - pbpaste.stdout.on('data', (data) => { + const pbpaste = spawn("pbpaste"); + pbpaste.stdout.on("data", (data) => { stdout += data; }); - pbpaste.stderr.on('data', (data) => { + pbpaste.stderr.on("data", (data) => { stderr += data; }); - pbpaste.on('close', (code) => { + pbpaste.on("close", (code) => { if (code !== 0) { - throw new Error(`pbpaste returns ${code}: ${stderr}`) + throw new Error(`pbpaste returns ${code}: ${stderr}`); } resolve(stdout); }); @@ -57,15 +59,15 @@ const readDarwin = (): Promise<string> => { }; const writeDarwin = (data: string): Promise<string> => { - let stderr = ''; + let stderr = ""; return new Promise((resolve) => { - const pbcopy = spawn('pbcopy'); - pbcopy.stderr.on('data', (data) => { + const pbcopy = spawn("pbcopy"); + pbcopy.stderr.on("data", (data) => { stderr += data; }); - pbcopy.on('close', (code) => { + pbcopy.on("close", (code) => { if (code !== 0) { - throw new Error(`pbcopy returns ${code}: ${stderr}`) + throw new Error(`pbcopy returns ${code}: ${stderr}`); } resolve(); }); @@ -83,25 +85,22 @@ class UnsupportedError extends Error { const read = () => { switch (process.platform) { - case 'linux': - return readLinux(); - case 'darwin': - return readDarwin(); + 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); + case "linux": + return writeLinux(data); + case "darwin": + return writeDarwin(data); } throw new UnsupportedError(process.platform); -} - -export { - read, - write, }; + +export { read, write }; diff --git a/e2e/mark.test.ts b/e2e/mark.test.ts index c73423b..d7ec26c 100644 --- a/e2e/mark.test.ts +++ b/e2e/mark.test.ts @@ -1,102 +1,100 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 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", () => { - const server = new TestServer().receiveContent('/', - `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); - await server.start() + await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - it('should set a local mark and jump to it', async () => { + it("should set a local mark and jump to it", async () => { const page = await Page.navigateTo(webdriver, server.url()); await page.scrollTo(200, 200); - await page.sendKeys('m', 'a'); + await page.sendKeys("m", "a"); await page.scrollTo(500, 500); - await page.sendKeys('\'', 'a'); + await page.sendKeys("'", "a"); - await eventually(async() => { + 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')); + 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.sendKeys("m", "A"); await page.scrollTo(500, 500); - await page.sendKeys('\'', 'A'); + await page.sendKeys("'", "A"); - await eventually(async() => { + await eventually(async () => { assert.strictEqual(await page.getScrollX(), 200); assert.strictEqual(await page.getScrollY(), 200); }); - await browser.tabs.create({ url: server.url('/#second') }); + await browser.tabs.create({ url: server.url("/#second") }); page = await Page.currentContext(webdriver); - await page.sendKeys('\'', 'A'); + await page.sendKeys("'", "A"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({ active: true }))[0]; const url = new URL(tab.url); - assert.strictEqual(url.hash, '#first'); + 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')); + 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'); + await page.sendKeys("m", "A"); const tab = (await browser.tabs.query({ active: true }))[0]; - await browser.tabs.create({ url: server.url('/#second') }); + await browser.tabs.create({ url: server.url("/#second") }); await browser.tabs.remove(tab.id); let handles: string[]; - await eventually(async() => { + 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'); + page = await Page.navigateTo(webdriver, server.url("/#second")); + await page.sendKeys("'", "A"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({ active: true }))[0]; const url = new URL(tab.url); - assert.strictEqual(url.hash, '#first'); + assert.strictEqual(url.hash, "#first"); }); }); }); - - diff --git a/e2e/navigate.test.ts b/e2e/navigate.test.ts index 37f0520..d0942b6 100644 --- a/e2e/navigate.test.ts +++ b/e2e/navigate.test.ts @@ -1,16 +1,16 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +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 = () => { const server = new TestServer(); - server.handle('/pagenation-a/:page', (req, res) => { + server.handle("/pagenation-a/:page", (req, res) => { res.status(200).send(` <!DOCTYPE html> <html lang="en"> @@ -19,26 +19,33 @@ const newApp = () => { </html>`); }); - server.handle('/pagenation-link/:page', (req, res) => { + 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> + <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', ` + 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>`); + </html>` + ); - server.receiveContent('/*', `ok`); + server.receiveContent("/*", `ok`); return server; }; @@ -49,204 +56,217 @@ describe("navigate test", () => { let webdriver: WebDriver; let browser: any; - before(async() => { + before(async () => { await server.start(); - const opts = (new FirefoxOptions() as any) - .setPreference('browser.startup.homepage', server.url('/#home')); - lanthan = await Builder - .forBrowser('firefox') + const opts = (new FirefoxOptions() as any).setPreference( + "browser.startup.homepage", + server.url("/#home") + ); + lanthan = await Builder.forBrowser("firefox") .setOptions(opts) - .spyAddon(path.join(__dirname, '..')) + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } }); - it('should go to parent path without hash by gu', async () => { - const page = await Page.navigateTo(webdriver, server.url('/a/b/c')); - await page.sendKeys('g', 'u'); + it("should go to parent path without hash by gu", async () => { + const page = await Page.navigateTo(webdriver, server.url("/a/b/c")); + await page.sendKeys("g", "u"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, `/a/b/`) + assert.strictEqual(url.pathname, `/a/b/`); }); }); - it('should remove hash by gu', async () => { - const page = await Page.navigateTo(webdriver, server.url('/a/b/c#hash')); - await page.sendKeys('g', 'u'); + it("should remove hash by gu", async () => { + const page = await Page.navigateTo(webdriver, server.url("/a/b/c#hash")); + await page.sendKeys("g", "u"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.hash, ''); - assert.strictEqual(url.pathname, `/a/b/c`) + assert.strictEqual(url.hash, ""); + assert.strictEqual(url.pathname, `/a/b/c`); }); }); - it('should go to root path by gU', async () => { - const page = await Page.navigateTo(webdriver, server.url('/a/b/c#hash')); - await page.sendKeys('g', Key.SHIFT, 'u'); + it("should go to root path by gU", async () => { + const page = await Page.navigateTo(webdriver, server.url("/a/b/c#hash")); + await page.sendKeys("g", Key.SHIFT, "u"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, `/`) + 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'); + 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() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, `/first`) + assert.strictEqual(url.pathname, `/first`); }); page = await Page.currentContext(webdriver); - page.sendKeys(Key.SHIFT, 'l'); + page.sendKeys(Key.SHIFT, "l"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, `/second`) + assert.strictEqual(url.pathname, `/second`); }); }); - it('should go previous and next page in <a> by [[ and ]]', async () => { - const page = await Page.navigateTo(webdriver, server.url('/pagenation-a/10')); - await page.sendKeys('[', '['); + it("should go previous and next page in <a> by [[ and ]]", async () => { + const page = await Page.navigateTo( + webdriver, + server.url("/pagenation-a/10") + ); + await page.sendKeys("[", "["); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, '/pagenation-a/9'); + assert.strictEqual(url.pathname, "/pagenation-a/9"); }); }); - it('should go next page in <a> by ]]', async () => { - const page = await Page.navigateTo(webdriver, server.url('/pagenation-a/10')); - await page.sendKeys(']', ']'); + it("should go next page in <a> by ]]", async () => { + const page = await Page.navigateTo( + webdriver, + server.url("/pagenation-a/10") + ); + await page.sendKeys("]", "]"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, '/pagenation-a/11'); + assert.strictEqual(url.pathname, "/pagenation-a/11"); }); }); - it('should go previous page in <link> by ]]', async () => { - const page = await Page.navigateTo(webdriver, server.url('/pagenation-link/10')); - await page.sendKeys('[', '['); + it("should go previous page in <link> by ]]", async () => { + const page = await Page.navigateTo( + webdriver, + server.url("/pagenation-link/10") + ); + await page.sendKeys("[", "["); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, '/pagenation-link/9'); + assert.strictEqual(url.pathname, "/pagenation-link/9"); }); }); - it('should go next page by in <link> by [[', async () => { - const page = await Page.navigateTo(webdriver, server.url('/pagenation-link/10')); - await page.sendKeys(']', ']'); + it("should go next page by in <link> by [[", async () => { + const page = await Page.navigateTo( + webdriver, + server.url("/pagenation-link/10") + ); + await page.sendKeys("]", "]"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.pathname, '/pagenation-link/11'); + assert.strictEqual(url.pathname, "/pagenation-link/11"); }); }); - it('should go to home page into current tab by gh', async () => { + it("should go to home page into current tab by gh", async () => { const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('g', 'h'); + await page.sendKeys("g", "h"); - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; const url = new URL(tab.url); - assert.strictEqual(url.hash, '#home'); + assert.strictEqual(url.hash, "#home"); }); }); - it('should go to home page into current tab by gH', async () => { + it("should go to home page into current tab by gH", async () => { const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('g', Key.SHIFT, 'H'); + await page.sendKeys("g", Key.SHIFT, "H"); - await eventually(async() => { + await eventually(async () => { const 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(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 () => { - const page = await Page.navigateTo(webdriver, server.url('/reload')); + it("should reload current tab by r", async () => { + const page = await Page.navigateTo(webdriver, server.url("/reload")); await page.scrollTo(500, 500); let before: number; - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; - before = Number(new URL(tab.url).hash.split('#')[1]); + before = Number(new URL(tab.url).hash.split("#")[1]); assert.ok(before > 0); }); - await page.sendKeys('r'); + await page.sendKeys("r"); let after; - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; - after = Number(new URL(tab.url).hash.split('#')[1]); + after = Number(new URL(tab.url).hash.split("#")[1]); assert.ok(after > before); }); - await eventually(async() => { + await eventually(async () => { const page = await Page.currentContext(webdriver); assert.strictEqual(await page.getScrollX(), 500); }); }); - it('should reload current tab without cache by R', async () => { - const page = await Page.navigateTo(webdriver, server.url('/reload')); + it("should reload current tab without cache by R", async () => { + const page = await Page.navigateTo(webdriver, server.url("/reload")); await page.scrollTo(500, 500); let before: number; - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; - before = Number(new URL(tab.url).hash.split('#')[1]); + before = Number(new URL(tab.url).hash.split("#")[1]); assert.ok(before > 0); }); - await page.sendKeys(Key.SHIFT, 'R'); + await page.sendKeys(Key.SHIFT, "R"); let after; - await eventually(async() => { + await eventually(async () => { const tab = (await browser.tabs.query({}))[0]; - after = Number(new URL(tab.url).hash.split('#')[1]); + after = Number(new URL(tab.url).hash.split("#")[1]); assert.ok(after > before); }); - await eventually(async() => { + await eventually(async () => { const page = await Page.currentContext(webdriver); assert.strictEqual(await page.getScrollY(), 0); }); diff --git a/e2e/options.test.ts b/e2e/options.test.ts index 91a3dde..64f24be 100644 --- a/e2e/options.test.ts +++ b/e2e/options.test.ts @@ -1,25 +1,25 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +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", () => { - const server = new TestServer().receiveContent('/', - `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); @@ -27,43 +27,51 @@ describe("options page", () => { await server.start(); }); - after(async() => { + after(async () => { if (lanthan) { await lanthan.quit(); } await server.stop(); }); - beforeEach(async() => { + beforeEach(async () => { const tabs = await browser.tabs.query({}); for (const tab of tabs.slice(1)) { await browser.tabs.remove(tab.id); } }); - it('saves current config on blur', async () => { + it("saves current config on blur", async () => { const page = await OptionPage.open(lanthan); const 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" ] } '); + 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" ] } '); + settings = (await browser.storage.local.get("settings")).settings; + assert.strictEqual(settings.source, "json"); + assert.strictEqual( + settings.json, + '{ "blacklist": [ "https://example.com" ] } ' + ); const message = await jsonPage.getErrorMessage(); - assert.ok(message.startsWith('SyntaxError:')) + assert.ok(message.startsWith("SyntaxError:")); }); - it('updates keymaps without reloading', async () => { + it("updates keymaps without reloading", async () => { const optionPage = await OptionPage.open(lanthan); const jsonPage = await optionPage.asJSONOptionPage(); - await jsonPage.updateSettings(`{ "keymaps": { "zz": { "type": "scroll.vertically", "count": 10 } } }`); + 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)); @@ -71,11 +79,11 @@ describe("options page", () => { await webdriver.switchTo().window(handles[1]); const page = await Page.currentContext(webdriver); - await page.sendKeys('zz'); + await page.sendKeys("zz"); - await eventually(async() => { + await eventually(async () => { const y = await page.getScrollY(); assert.strictEqual(y, 640); }); - }) + }); }); diff --git a/e2e/options_form.test.ts b/e2e/options_form.test.ts index 2121348..bb5ebf1 100644 --- a/e2e/options_form.test.ts +++ b/e2e/options_form.test.ts @@ -1,17 +1,16 @@ -import * as path from 'path'; -import * as assert from 'assert'; +import * as path from "path"; +import * as assert from "assert"; -import { Builder, Lanthan } from 'lanthan'; -import OptionPage from './lib/OptionPage'; +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, '..')) + beforeEach(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); browser = lanthan.getWebExtBrowser(); @@ -21,109 +20,119 @@ describe("options form page", () => { } }); - afterEach(async() => { + afterEach(async () => { if (lanthan) { await lanthan.quit(); } }); - it('switch to form settings', async () => { + it("switch to form settings", async () => { const page = await OptionPage.open(lanthan); await page.switchToForm(); - const { settings } = await browser.storage.local.get('settings'); - assert.strictEqual(settings.source, 'form') + const { settings } = await browser.storage.local.get("settings"); + assert.strictEqual(settings.source, "form"); }); - it('add blacklist item', async () => { + it("add blacklist item", async () => { const page = await OptionPage.open(lanthan); const forms = await page.switchToForm(); // assert default - let settings = (await browser.storage.local.get('settings')).settings; + 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'); + await forms.setBlacklist(0, "google.com"); - settings = (await browser.storage.local.get('settings')).settings; - assert.deepStrictEqual(settings.form.blacklist, ['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'); + await forms.setBlacklist(1, "yahoo.com"); - settings = (await browser.storage.local.get('settings')).settings; - assert.deepStrictEqual(settings.form.blacklist, ['google.com', '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']) + settings = (await browser.storage.local.get("settings")).settings; + assert.deepStrictEqual(settings.form.blacklist, ["yahoo.com"]); }); - it('add a partial blacklist item', async () => { + it("add a partial blacklist item", async () => { const page = await OptionPage.open(lanthan); const forms = await page.switchToForm(); // assert default - let settings = (await browser.storage.local.get('settings')).settings; + let settings = (await browser.storage.local.get("settings")).settings; assert.deepStrictEqual(settings.form.blacklist, []); // add blacklist items await forms.addPartialBlacklist(); - await forms.setPartialBlacklist(0, 'google.com', 'j,k,<C-U>'); + await forms.setPartialBlacklist(0, "google.com", "j,k,<C-U>"); - settings = (await browser.storage.local.get('settings')).settings; + settings = (await browser.storage.local.get("settings")).settings; assert.deepStrictEqual(settings.form.blacklist, [ - { url: 'google.com', keys: ['j', 'k', '<C-U>'] }, + { url: "google.com", keys: ["j", "k", "<C-U>"] }, ]); await forms.addPartialBlacklist(); - await forms.setPartialBlacklist(1, 'yahoo.com', 'g,G'); + await forms.setPartialBlacklist(1, "yahoo.com", "g,G"); - settings = (await browser.storage.local.get('settings')).settings; + settings = (await browser.storage.local.get("settings")).settings; assert.deepStrictEqual(settings.form.blacklist, [ - { url: 'google.com', keys: ['j', 'k', '<C-U>'] }, - { url: 'yahoo.com', keys: ['g', 'G'] }, + { url: "google.com", keys: ["j", "k", "<C-U>"] }, + { url: "yahoo.com", keys: ["g", "G"] }, ]); await forms.addBlacklist(); - await forms.setBlacklist(0, 'bing.com'); + await forms.setBlacklist(0, "bing.com"); - settings = (await browser.storage.local.get('settings')).settings; + settings = (await browser.storage.local.get("settings")).settings; assert.deepStrictEqual(settings.form.blacklist, [ - { url: 'google.com', keys: ['j', 'k', '<C-U>'] }, - { url: 'yahoo.com', keys: ['g', 'G'] }, - 'bing.com', + { url: "google.com", keys: ["j", "k", "<C-U>"] }, + { url: "yahoo.com", keys: ["g", "G"] }, + "bing.com", ]); // delete first item await forms.removePartialBlackList(0); - settings = (await browser.storage.local.get('settings')).settings; + settings = (await browser.storage.local.get("settings")).settings; assert.deepStrictEqual(settings.form.blacklist, [ - { url: 'yahoo.com', keys: ['g', 'G'] }, - 'bing.com', - ]) + { url: "yahoo.com", keys: ["g", "G"] }, + "bing.com", + ]); }); - it('add search engines', async () => { + it("add search engines", async () => { const page = await OptionPage.open(lanthan); const forms = await page.switchToForm(); // assert default - let settings = (await browser.storage.local.get('settings')).settings; - assert.deepStrictEqual(settings.form.search.default, 'google'); + 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'); + 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={}']); + 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/partial_blacklist.test.ts b/e2e/partial_blacklist.test.ts index cb66549..8bc1c0e 100644 --- a/e2e/partial_blacklist.test.ts +++ b/e2e/partial_blacklist.test.ts @@ -1,57 +1,57 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; -import Settings from '../src/shared/settings/Settings'; -import SettingRepository from './lib/SettingRepository'; +import TestServer from "./lib/TestServer"; +import { Builder, Lanthan } from "lanthan"; +import { WebDriver } from "selenium-webdriver"; +import Page from "./lib/Page"; +import Settings from "../src/shared/settings/Settings"; +import SettingRepository from "./lib/SettingRepository"; describe("partial blacklist test", () => { - const server = new TestServer().receiveContent('/*', - `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); - const url = server.url().replace('http://', ''); - await new SettingRepository(browser).saveJSON(Settings.fromJSON({ - keymaps: { - j: { type: 'scroll.vertically', count: 1 }, - k: { type: 'scroll.vertically', count: -1 }, - }, - blacklist: [ - { 'url': url, 'keys': ['k'] } - ] - })); + const url = server.url().replace("http://", ""); + await new SettingRepository(browser).saveJSON( + Settings.fromJSON({ + keymaps: { + j: { type: "scroll.vertically", count: 1 }, + k: { type: "scroll.vertically", count: -1 }, + }, + blacklist: [{ url: url, keys: ["k"] }], + }) + ); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - it('should disable keys in the partial blacklist', async () => { - const page = await Page.navigateTo(webdriver, server.url('/')); + it("should disable keys in the partial blacklist", async () => { + const page = await Page.navigateTo(webdriver, server.url("/")); - await page.sendKeys('j'); + await page.sendKeys("j"); let scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 64); - await page.sendKeys('k'); + await page.sendKeys("k"); scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 64); }); diff --git a/e2e/repeat.test.ts b/e2e/repeat.test.ts index 7c8b5e2..04d1331 100644 --- a/e2e/repeat.test.ts +++ b/e2e/repeat.test.ts @@ -1,73 +1,72 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 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", () => { - const server = new TestServer().receiveContent('/*', 'ok'); + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - it('repeats last command', async () => { + it("repeats last command", async () => { let page = await Page.navigateTo(webdriver, server.url()); const console = await page.showConsole(); - await console.execCommand(`tabopen ${server.url('/newtab')}`); + await console.execCommand(`tabopen ${server.url("/newtab")}`); - await eventually(async() => { + await eventually(async () => { const current = await browser.tabs.query({ url: `*://*/newtab` }); assert.strictEqual(current.length, 1); }); page = await Page.currentContext(webdriver); - await page.sendKeys('.'); + await page.sendKeys("."); - await eventually(async() => { + await eventually(async () => { const current = await browser.tabs.query({ url: `*://*/newtab` }); assert.strictEqual(current.length, 2); }); }); - it('repeats last operation', async () => { + it("repeats last operation", async () => { for (let i = 1; i < 5; ++i) { - await browser.tabs.create({ url: server.url('/#' + i) }); + await browser.tabs.create({ url: server.url("/#" + i) }); } const before = await browser.tabs.query({}); let page = await Page.currentContext(webdriver); - await page.sendKeys('d'); + await page.sendKeys("d"); - await eventually(async() => { + await eventually(async () => { const current = await browser.tabs.query({}); - assert.strictEqual(current.length, before.length - 1); + 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 page.sendKeys("."); - await eventually(async() => { + await eventually(async () => { const current = await browser.tabs.query({}); assert.strictEqual(current.length, before.length - 2); }); diff --git a/e2e/repeat_n_times.test.ts b/e2e/repeat_n_times.test.ts index a646112..303aa34 100644 --- a/e2e/repeat_n_times.test.ts +++ b/e2e/repeat_n_times.test.ts @@ -1,24 +1,24 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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 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", () => { - const server = new TestServer().receiveContent('/', - `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); @@ -27,32 +27,35 @@ describe("tab test", () => { browser = browser; }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - it('repeats scroll 3-times', async () => { + it("repeats scroll 3-times", async () => { const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('3', 'j'); + await page.sendKeys("3", "j"); const scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 64 * 3); }); - it('repeats tab deletion 3-times', async () => { - const win = await browser.windows.create({ url: server.url('/#0') }); + it("repeats tab deletion 3-times", async () => { + const 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)); + await browser.tabs.create({ + url: server.url("/#" + i), + windowId: win.id, + }); + await webdriver.navigate().to(server.url("/#" + i)); } const page = await Page.navigateTo(webdriver, server.url()); - await page.sendKeys('3', 'd'); + await page.sendKeys("3", "d"); - await eventually(async() => { + await eventually(async () => { const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current.length, 2); }); diff --git a/e2e/scroll.test.ts b/e2e/scroll.test.ts index 9b39a2e..277bb2e 100644 --- a/e2e/scroll.test.ts +++ b/e2e/scroll.test.ts @@ -1,134 +1,141 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +import TestServer from "./lib/TestServer"; +import { Builder, Lanthan } from "lanthan"; +import { WebDriver, Key } from "selenium-webdriver"; +import Page from "./lib/Page"; describe("scroll test", () => { - const server = new TestServer().receiveContent('/', - `<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`, + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { + beforeEach(async () => { await webdriver.navigate().to(server.url()); page = await Page.currentContext(webdriver); }); - - it('scrolls up by j', async () => { - await page.sendKeys('j'); + it("scrolls up by j", async () => { + await page.sendKeys("j"); const scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 64); }); - it('scrolls down by k', async () => { + it("scrolls down by k", async () => { await webdriver.executeScript(() => window.scrollTo(0, 200)); - await page.sendKeys('k'); + await page.sendKeys("k"); const scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 136); }); - it('scrolls left by h', async () => { + it("scrolls left by h", async () => { await webdriver.executeScript(() => window.scrollTo(100, 100)); - await page.sendKeys('h'); + await page.sendKeys("h"); - const pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + const pageXOffset = (await webdriver.executeScript( + () => window.pageXOffset + )) as number; assert.strictEqual(pageXOffset, 36); }); - it('scrolls left by l', async () => { + it("scrolls left by l", async () => { await webdriver.executeScript(() => window.scrollTo(100, 100)); - await page.sendKeys('l'); + await page.sendKeys("l"); - const pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + const pageXOffset = (await webdriver.executeScript( + () => window.pageXOffset + )) as number; assert.strictEqual(pageXOffset, 164); }); - it('scrolls top by gg', async () => { + it("scrolls top by gg", async () => { await webdriver.executeScript(() => window.scrollTo(0, 100)); - await page.sendKeys('g', 'g'); + await page.sendKeys("g", "g"); const scrollY = await page.getScrollY(); assert.strictEqual(scrollY, 0); }); - it('scrolls bottom by G', async () => { + it("scrolls bottom by G", async () => { await webdriver.executeScript(() => window.scrollTo(0, 100)); - await page.sendKeys(Key.SHIFT, 'g'); + await page.sendKeys(Key.SHIFT, "g"); const scrollY = await page.getScrollY(); assert.ok(scrollY > 5000); }); - it('scrolls bottom by 0', async () => { + it("scrolls bottom by 0", async () => { await webdriver.executeScript(() => window.scrollTo(0, 100)); - await page.sendKeys(Key.SHIFT, '0'); + await page.sendKeys(Key.SHIFT, "0"); - const pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + const pageXOffset = (await webdriver.executeScript( + () => window.pageXOffset + )) as number; assert.ok(pageXOffset === 0); }); - it('scrolls bottom by $', async () => { + it("scrolls bottom by $", async () => { await webdriver.executeScript(() => window.scrollTo(0, 100)); - await page.sendKeys(Key.SHIFT, '$'); + await page.sendKeys(Key.SHIFT, "$"); - const pageXOffset = await webdriver.executeScript(() => window.pageXOffset) as number; + const pageXOffset = (await webdriver.executeScript( + () => window.pageXOffset + )) as number; assert.ok(pageXOffset > 5000); }); - it('scrolls bottom by <C-U>', async () => { + it("scrolls bottom by <C-U>", async () => { await webdriver.executeScript(() => window.scrollTo(0, 1000)); - await page.sendKeys(Key.CONTROL, 'u'); + await page.sendKeys(Key.CONTROL, "u"); const pageHeight = await page.pageHeight(); const scrollY = await page.getScrollY(); assert.ok(Math.abs(scrollY - (1000 - Math.floor(pageHeight / 2))) < 5); }); - it('scrolls bottom by <C-D>', async () => { + it("scrolls bottom by <C-D>", async () => { await webdriver.executeScript(() => window.scrollTo(0, 1000)); - await page.sendKeys(Key.CONTROL, 'd'); + await page.sendKeys(Key.CONTROL, "d"); const pageHeight = await page.pageHeight(); const scrollY = await page.getScrollY(); assert.ok(Math.abs(scrollY - (1000 + Math.floor(pageHeight / 2))) < 5); }); - it('scrolls bottom by <C-B>', async () => { + it("scrolls bottom by <C-B>", async () => { await webdriver.executeScript(() => window.scrollTo(0, 1000)); - await page.sendKeys(Key.CONTROL, 'b'); + await page.sendKeys(Key.CONTROL, "b"); const pageHeight = await page.pageHeight(); const scrollY = await page.getScrollY(); assert.ok(Math.abs(scrollY - (1000 - pageHeight)) < 5); }); - it('scrolls bottom by <C-F>', async () => { + it("scrolls bottom by <C-F>", async () => { await webdriver.executeScript(() => window.scrollTo(0, 1000)); - await page.sendKeys(Key.CONTROL, 'f'); + await page.sendKeys(Key.CONTROL, "f"); const pageHeight = await page.pageHeight(); const scrollY = await page.getScrollY(); diff --git a/e2e/tab.test.ts b/e2e/tab.test.ts index 6a8e815..98ec9f8 100644 --- a/e2e/tab.test.ts +++ b/e2e/tab.test.ts @@ -1,57 +1,59 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +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", () => { - const server = new TestServer().receiveContent('/*', 'ok'); + const 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, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); await server.start(); }); - after(async() => { + after(async () => { await server.stop(); if (lanthan) { await lanthan.quit(); } }); - beforeEach(async() => { - win = await browser.windows.create({ url: server.url('/#0') }); + 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)); + 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() => { + afterEach(async () => { await browser.windows.remove(win.id); }); - it('deletes tab and selects right by d', async () => { + it("deletes tab and selects right by d", async () => { await browser.tabs.update(tabs[3].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('d'); + await page.sendKeys("d"); - await eventually(async() => { + await eventually(async () => { const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current.length, tabs.length - 1); assert.strictEqual(current[3].active, true); @@ -59,34 +61,34 @@ describe("tab test", () => { }); }); - it('deletes tab and selects left by D', async () => { + it("deletes tab and selects left by D", async () => { await browser.tabs.update(tabs[3].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys(Key.SHIFT, 'D'); + await page.sendKeys(Key.SHIFT, "D"); - await eventually(async() => { + await eventually(async () => { const 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 () => { + it("deletes all tabs to the right by x$", async () => { await browser.tabs.update(tabs[1].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('x', '$'); + await page.sendKeys("x", "$"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current.length, 2); }); - it('duplicates tab by zd', async () => { + it("duplicates tab by zd", async () => { await browser.tabs.update(tabs[0].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('z', 'd'); + await page.sendKeys("z", "d"); - await eventually(async() => { + await eventually(async () => { const 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); @@ -94,118 +96,121 @@ describe("tab test", () => { }); }); - it('makes pinned by zp', async () => { + it("makes pinned by zp", async () => { await browser.tabs.update(tabs[0].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('z', 'p'); + await page.sendKeys("z", "p"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current[0].pinned, true); }); - it('selects previous tab by K', async () => { + it("selects previous tab by K", async () => { await browser.tabs.update(tabs[2].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys(Key.SHIFT, 'K'); + await page.sendKeys(Key.SHIFT, "K"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current[1].active, true); }); - it('selects previous tab by K rotatory', async () => { + it("selects previous tab by K rotatory", async () => { await browser.tabs.update(tabs[0].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys(Key.SHIFT, 'K'); + await page.sendKeys(Key.SHIFT, "K"); const current = await browser.tabs.query({ windowId: win.id }); - assert.strictEqual(current[current.length - 1].active, true) + assert.strictEqual(current[current.length - 1].active, true); }); - it('selects next tab by J', async () => { + it("selects next tab by J", async () => { await browser.tabs.update(tabs[2].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys(Key.SHIFT, 'J'); + await page.sendKeys(Key.SHIFT, "J"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current[3].active, true); }); - it('selects previous tab by J rotatory', async () => { + it("selects previous tab by J rotatory", async () => { await browser.tabs.update(tabs[tabs.length - 1].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys(Key.SHIFT, 'J'); + await page.sendKeys(Key.SHIFT, "J"); const current = await browser.tabs.query({ windowId: win.id }); - assert.strictEqual(current[0].active, true) + assert.strictEqual(current[0].active, true); }); - it('selects first tab by g0', async () => { + it("selects first tab by g0", async () => { await browser.tabs.update(tabs[2].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('g', '0'); + await page.sendKeys("g", "0"); const current = await browser.tabs.query({ windowId: win.id }); - assert.strictEqual(current[0].active, true) + assert.strictEqual(current[0].active, true); }); - it('selects last tab by g$', async () => { + it("selects last tab by g$", async () => { await browser.tabs.update(tabs[2].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('g', '$'); + await page.sendKeys("g", "$"); const current = await browser.tabs.query({ windowId: win.id }); - assert.strictEqual(current[current.length - 1].active, true) + assert.strictEqual(current[current.length - 1].active, true); }); - it('selects last selected tab by <C-6>', async () => { + 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 }); const page = await Page.currentContext(webdriver); - await page.sendKeys(Key.CONTROL, '6'); + await page.sendKeys(Key.CONTROL, "6"); const current = await browser.tabs.query({ windowId: win.id }); - assert.strictEqual(current[1].active, true) + 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 () => { + it.skip("reopen tab by u", async () => { await browser.tabs.remove(tabs[1].id); const page = await Page.currentContext(webdriver); - await page.sendKeys('u'); + await page.sendKeys("u"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current.length, tabs.length); }); - it('does not delete pinned tab by d', async () => { + it("does not delete pinned tab by d", async () => { await browser.tabs.update(tabs[0].id, { active: true, pinned: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('d'); + await page.sendKeys("d"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current.length, tabs.length); }); - it('deletes pinned tab by !d', async () => { + it("deletes pinned tab by !d", async () => { await browser.tabs.update(tabs[0].id, { active: true, pinned: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('!', 'd'); + await page.sendKeys("!", "d"); const current = await browser.tabs.query({ windowId: win.id }); assert.strictEqual(current.length, tabs.length - 1); }); - it('opens view-source by gf', async () => { + it("opens view-source by gf", async () => { await browser.tabs.update(tabs[0].id, { active: true }); const page = await Page.currentContext(webdriver); - await page.sendKeys('g', 'f'); + await page.sendKeys("g", "f"); - await eventually(async() => { + await eventually(async () => { const 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')}`); + assert.strictEqual( + current[current.length - 1].url, + `view-source:${server.url("/#0")}` + ); }); }); }); diff --git a/e2e/zoom.test.ts b/e2e/zoom.test.ts index d089097..5e21774 100644 --- a/e2e/zoom.test.ts +++ b/e2e/zoom.test.ts @@ -1,10 +1,10 @@ -import * as path from 'path'; -import * as assert from 'assert'; +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'; +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; @@ -13,10 +13,9 @@ describe("zoom test", () => { let tab: any; let page: Page; - before(async() => { - lanthan = await Builder - .forBrowser('firefox') - .spyAddon(path.join(__dirname, '..')) + before(async () => { + lanthan = await Builder.forBrowser("firefox") + .spyAddon(path.join(__dirname, "..")) .build(); webdriver = lanthan.getWebDriver(); browser = lanthan.getWebExtBrowser(); @@ -24,42 +23,41 @@ describe("zoom test", () => { page = await Page.currentContext(webdriver); }); - after(async() => { + after(async () => { await lanthan.quit(); }); - beforeEach(async() => { - await webdriver.navigate().to('about:blank'); + beforeEach(async () => { + await webdriver.navigate().to("about:blank"); }); - it('should zoom in by zi', async () => { + it("should zoom in by zi", async () => { const before = await browser.tabs.getZoom(tab.id); - await page.sendKeys('zi'); + await page.sendKeys("zi"); - await eventually(async() => { + await eventually(async () => { const actual = await browser.tabs.getZoom(tab.id); assert.ok(before < actual); }); }); - it('should zoom out by zo', async () => { + it("should zoom out by zo", async () => { const before = await browser.tabs.getZoom(tab.id); - await page.sendKeys('zo'); + await page.sendKeys("zo"); - await eventually(async() => { + await eventually(async () => { const actual = await browser.tabs.getZoom(tab.id); assert.ok(before > actual); }); }); - it('should reset zoom by zz', async () => { + it("should reset zoom by zz", async () => { await browser.tabs.setZoom(tab.id, 2); - await page.sendKeys('zz'); + await page.sendKeys("zz"); - await eventually(async() => { + await eventually(async () => { const actual = await browser.tabs.getZoom(tab.id); assert.strictEqual(actual, 1); }); }); }); - diff --git a/src/background/Application.ts b/src/background/Application.ts index c2c48b5..69fe4a4 100644 --- a/src/background/Application.ts +++ b/src/background/Application.ts @@ -1,7 +1,7 @@ -import { injectable, inject } from 'tsyringe'; -import ContentMessageListener from './infrastructures/ContentMessageListener'; -import SettingController from './controllers/SettingController'; -import VersionController from './controllers/VersionController'; +import { injectable, inject } from "tsyringe"; +import ContentMessageListener from "./infrastructures/ContentMessageListener"; +import SettingController from "./controllers/SettingController"; +import VersionController from "./controllers/VersionController"; import SettingRepository from "./repositories/SettingRepository"; @injectable() @@ -10,15 +10,15 @@ export default class Application { private contentMessageListener: ContentMessageListener, private settingController: SettingController, private versionController: VersionController, - @inject("SyncSettingRepository") private syncSettingRepository: SettingRepository, - ) { - } + @inject("SyncSettingRepository") + private syncSettingRepository: SettingRepository + ) {} run() { this.settingController.reload(); browser.runtime.onInstalled.addListener((details) => { - if (details.reason !== 'install' && details.reason !== 'update') { + if (details.reason !== "install" && details.reason !== "update") { return; } this.versionController.notify(); diff --git a/src/background/clients/NavigateClient.ts b/src/background/clients/NavigateClient.ts index bdd94ec..40ceb45 100644 --- a/src/background/clients/NavigateClient.ts +++ b/src/background/clients/NavigateClient.ts @@ -1,5 +1,5 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; @injectable() export default class NavigateClient { diff --git a/src/background/completion/BookmarkRepository.ts b/src/background/completion/BookmarkRepository.ts index 14105c8..4dec12e 100644 --- a/src/background/completion/BookmarkRepository.ts +++ b/src/background/completion/BookmarkRepository.ts @@ -1,7 +1,7 @@ export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export default interface BookmarkRepository { queryBookmarks(query: string): Promise<BookmarkItem[]>; diff --git a/src/background/completion/HistoryRepository.ts b/src/background/completion/HistoryRepository.ts index 5eb3a2b..446d110 100644 --- a/src/background/completion/HistoryRepository.ts +++ b/src/background/completion/HistoryRepository.ts @@ -1,7 +1,7 @@ export type HistoryItem = { - title: string - url: string -} + title: string; + url: string; +}; export default interface HistoryRepository { queryHistories(keywords: string): Promise<HistoryItem[]>; diff --git a/src/background/completion/OpenCompletionUseCase.ts b/src/background/completion/OpenCompletionUseCase.ts index 1b63e7c..e678c2f 100644 --- a/src/background/completion/OpenCompletionUseCase.ts +++ b/src/background/completion/OpenCompletionUseCase.ts @@ -5,38 +5,39 @@ import BookmarkRepository from "./BookmarkRepository"; import HistoryRepository from "./HistoryRepository"; export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export type HistoryItem = { - title: string - url: string -} + title: string; + url: string; +}; @injectable() export default class OpenCompletionUseCase { constructor( - @inject('BookmarkRepository') private bookmarkRepository: BookmarkRepository, - @inject('HistoryRepository') private historyRepository: HistoryRepository, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, - ) { - } + @inject("BookmarkRepository") + private bookmarkRepository: BookmarkRepository, + @inject("HistoryRepository") private historyRepository: HistoryRepository, + @inject("CachedSettingRepository") + private cachedSettingRepository: CachedSettingRepository + ) {} async getCompletionTypes(): Promise<CompletionType[]> { const settings = await this.cachedSettingRepository.get(); const types: CompletionType[] = []; for (const c of settings.properties.complete) { switch (c) { - case 's': - types.push(CompletionType.SearchEngines); - break; - case 'h': - types.push(CompletionType.History); - break; - case 'b': - types.push(CompletionType.Bookmarks); - break; + case "s": + types.push(CompletionType.SearchEngines); + break; + case "h": + types.push(CompletionType.History); + break; + case "b": + types.push(CompletionType.Bookmarks); + break; } // ignore invalid characters in the complete property } @@ -45,8 +46,9 @@ export default class OpenCompletionUseCase { async requestSearchEngines(query: string): Promise<string[]> { const settings = await this.cachedSettingRepository.get(); - return Object.keys(settings.search.engines) - .filter(key => key.startsWith(query)) + return Object.keys(settings.search.engines).filter((key) => + key.startsWith(query) + ); } requestBookmarks(query: string): Promise<BookmarkItem[]> { @@ -56,4 +58,4 @@ export default class OpenCompletionUseCase { requestHistory(query: string): Promise<HistoryItem[]> { return this.historyRepository.queryHistories(query); } -}
\ No newline at end of file +} diff --git a/src/background/completion/PropertyCompletionUseCase.ts b/src/background/completion/PropertyCompletionUseCase.ts index 049cfb8..7b72259 100644 --- a/src/background/completion/PropertyCompletionUseCase.ts +++ b/src/background/completion/PropertyCompletionUseCase.ts @@ -3,14 +3,14 @@ import Properties from "../../shared/settings/Properties"; type Property = { name: string; - type: 'string' | 'boolean' | 'number'; -} + type: "string" | "boolean" | "number"; +}; @injectable() export default class PropertyCompletionUseCase { async getProperties(): Promise<Property[]> { - return Properties.defs().map(def => ({ + return Properties.defs().map((def) => ({ name: def.name, type: def.type, })); } -}
\ No newline at end of file +} diff --git a/src/background/completion/TabCompletionUseCase.ts b/src/background/completion/TabCompletionUseCase.ts index dec86e9..d0d3bb7 100644 --- a/src/background/completion/TabCompletionUseCase.ts +++ b/src/background/completion/TabCompletionUseCase.ts @@ -7,10 +7,9 @@ import TabFlag from "../../shared/TabFlag"; @injectable() export default class TabCompletionUseCase { constructor( - @inject('TabRepository') private tabRepository: TabRepository, - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + @inject("TabRepository") private tabRepository: TabRepository, + @inject("TabPresenter") private tabPresenter: TabPresenter + ) {} async queryTabs(query: string, excludePinned: boolean): Promise<TabItem[]> { const lastTabId = await this.tabPresenter.getLastSelectedId(); @@ -18,17 +17,17 @@ export default class TabCompletionUseCase { const num = parseInt(query, 10); let tabs: Tab[] = []; if (!isNaN(num)) { - const tab = allTabs.find(t => t.index === num - 1); + const tab = allTabs.find((t) => t.index === num - 1); if (tab) { tabs = [tab]; } - } else if (query == '%') { - const tab = allTabs.find(t => t.active); + } else if (query == "%") { + const tab = allTabs.find((t) => t.active); if (tab) { tabs = [tab]; } - } else if (query == '#') { - const tab = allTabs.find(t => t.id === lastTabId); + } else if (query == "#") { + const tab = allTabs.find((t) => t.id === lastTabId); if (tab) { tabs = [tab]; } @@ -36,20 +35,20 @@ export default class TabCompletionUseCase { tabs = await this.tabRepository.queryTabs(query, excludePinned); } - return tabs.map(tab => { + return tabs.map((tab) => { let flag = TabFlag.None; if (tab.active) { - flag = TabFlag.CurrentTab + flag = TabFlag.CurrentTab; } else if (tab.id == lastTabId) { - flag = TabFlag.LastTab + flag = TabFlag.LastTab; } return { index: tab.index + 1, flag: flag, title: tab.title, url: tab.url, - faviconUrl : tab.faviconUrl - } + faviconUrl: tab.faviconUrl, + }; }); } } diff --git a/src/background/completion/TabItem.ts b/src/background/completion/TabItem.ts index 630855a..eb7b657 100644 --- a/src/background/completion/TabItem.ts +++ b/src/background/completion/TabItem.ts @@ -1,11 +1,11 @@ import TabFlag from "../../shared/TabFlag"; type TabItem = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -} + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}; -export default TabItem;
\ No newline at end of file +export default TabItem; diff --git a/src/background/completion/TabRepository.ts b/src/background/completion/TabRepository.ts index fe1b601..57dbf21 100644 --- a/src/background/completion/TabRepository.ts +++ b/src/background/completion/TabRepository.ts @@ -1,14 +1,14 @@ export type Tab = { - id: number - index: number - active: boolean - title: string - url: string - faviconUrl?: string -} + id: number; + index: number; + active: boolean; + title: string; + url: string; + faviconUrl?: string; +}; export default interface TabRepository { queryTabs(query: string, excludePinned: boolean): Promise<Tab[]>; - getAllTabs(excludePinned: boolean): Promise<Tab[]> + getAllTabs(excludePinned: boolean): Promise<Tab[]>; } diff --git a/src/background/completion/impl/BookmarkRepositoryImpl.ts b/src/background/completion/impl/BookmarkRepositoryImpl.ts index 3b80b93..2bc779d 100644 --- a/src/background/completion/impl/BookmarkRepositoryImpl.ts +++ b/src/background/completion/impl/BookmarkRepositoryImpl.ts @@ -1,5 +1,5 @@ -import BookmarkRepository, {BookmarkItem} from "../BookmarkRepository"; -import {HistoryItem} from "../HistoryRepository"; +import BookmarkRepository, { BookmarkItem } from "../BookmarkRepository"; +import { HistoryItem } from "../HistoryRepository"; import PrefetchAndCache from "./PrefetchAndCache"; const COMPLETION_ITEM_LIMIT = 10; @@ -8,7 +8,7 @@ export default class CachedBookmarkRepository implements BookmarkRepository { private bookmarkCache: PrefetchAndCache<BookmarkItem>; constructor() { - this.bookmarkCache = new PrefetchAndCache(this.getter, this.filter, 10,); + this.bookmarkCache = new PrefetchAndCache(this.getter, this.filter, 10); } queryBookmarks(query: string): Promise<BookmarkItem[]> { @@ -16,10 +16,10 @@ export default class CachedBookmarkRepository implements BookmarkRepository { } private async getter(query: string): Promise<BookmarkItem[]> { - const items = await browser.bookmarks.search({query}); + const items = await browser.bookmarks.search({ query }); return items - .filter(item => item.title && item.title.length > 0) - .filter(item => item.type === 'bookmark' && item.url) + .filter((item) => item.title && item.title.length > 0) + .filter((item) => item.type === "bookmark" && item.url) .filter((item) => { let url = undefined; try { @@ -27,20 +27,23 @@ export default class CachedBookmarkRepository implements BookmarkRepository { } catch (e) { return false; } - return url.protocol !== 'place:'; + return url.protocol !== "place:"; }) .slice(0, COMPLETION_ITEM_LIMIT) - .map(item => ({ + .map((item) => ({ title: item.title!!, url: item.url!!, })); } private filter(items: HistoryItem[], query: string) { - return items.filter(item => { - return query.split(' ').every(keyword => { - return item.title.toLowerCase().includes(keyword.toLowerCase()) || item.url!!.includes(keyword) + return items.filter((item) => { + return query.split(" ").every((keyword) => { + return ( + item.title.toLowerCase().includes(keyword.toLowerCase()) || + item.url!!.includes(keyword) + ); }); - }) - }; + }); + } } diff --git a/src/background/completion/impl/HistoryRepositoryImpl.ts b/src/background/completion/impl/HistoryRepositoryImpl.ts index cd55cd0..b1992a4 100644 --- a/src/background/completion/impl/HistoryRepositoryImpl.ts +++ b/src/background/completion/impl/HistoryRepositoryImpl.ts @@ -1,5 +1,5 @@ import * as filters from "./filters"; -import HistoryRepository, {HistoryItem} from "../HistoryRepository"; +import HistoryRepository, { HistoryItem } from "../HistoryRepository"; import PrefetchAndCache from "./PrefetchAndCache"; const COMPLETION_ITEM_LIMIT = 10; @@ -8,13 +8,17 @@ export default class CachedHistoryRepository implements HistoryRepository { private historyCache: PrefetchAndCache<browser.history.HistoryItem>; constructor() { - this.historyCache = new PrefetchAndCache(this.getter, this.filter, 10) + this.historyCache = new PrefetchAndCache(this.getter, this.filter, 10); } async queryHistories(keywords: string): Promise<HistoryItem[]> { const items = await this.historyCache.get(keywords); - const filterOrKeep = <T>(source: T[], filter: (items: T[]) => T[], min: number): T[] => { + const filterOrKeep = <T>( + source: T[], + filter: (items: T[]) => T[], + min: number + ): T[] => { const filtered = filter(source); if (filtered.length < min) { return source; @@ -23,17 +27,23 @@ export default class CachedHistoryRepository implements HistoryRepository { }; return [items] - .map(items => filterOrKeep(items, filters.filterByPathname, COMPLETION_ITEM_LIMIT)) - .map(items => filterOrKeep(items, filters.filterByOrigin, COMPLETION_ITEM_LIMIT))[0] - .sort((x, y) => Number(y.visitCount) - Number(x.visitCount)) - .slice(0, COMPLETION_ITEM_LIMIT) - .map(item => ({ - title: item.title!!, - url: item.url!!, - })); + .map((items) => + filterOrKeep(items, filters.filterByPathname, COMPLETION_ITEM_LIMIT) + ) + .map((items) => + filterOrKeep(items, filters.filterByOrigin, COMPLETION_ITEM_LIMIT) + )[0] + .sort((x, y) => Number(y.visitCount) - Number(x.visitCount)) + .slice(0, COMPLETION_ITEM_LIMIT) + .map((item) => ({ + title: item.title!!, + url: item.url!!, + })); } - private async getter (keywords: string): Promise<browser.history.HistoryItem[]> { + private async getter( + keywords: string + ): Promise<browser.history.HistoryItem[]> { const items = await browser.history.search({ text: keywords, startTime: 0, @@ -42,14 +52,17 @@ export default class CachedHistoryRepository implements HistoryRepository { return [items] .map(filters.filterBlankTitle) .map(filters.filterHttp) - .map(filters.filterByTailingSlash)[0] + .map(filters.filterByTailingSlash)[0]; } private filter(items: browser.history.HistoryItem[], query: string) { - return items.filter(item => { - return query.split(' ').every(keyword => { - return item.title!!.toLowerCase().includes(keyword.toLowerCase()) || item.url!!.includes(keyword) + return items.filter((item) => { + return query.split(" ").every((keyword) => { + return ( + item.title!!.toLowerCase().includes(keyword.toLowerCase()) || + item.url!!.includes(keyword) + ); }); - }) - }; + }); + } } diff --git a/src/background/completion/impl/PrefetchAndCache.ts b/src/background/completion/impl/PrefetchAndCache.ts index 3c074c2..d2889b0 100644 --- a/src/background/completion/impl/PrefetchAndCache.ts +++ b/src/background/completion/impl/PrefetchAndCache.ts @@ -5,14 +5,14 @@ const WHITESPACE = /\s/; // `shortKey` returns a shorten key to pre-fetch completions and store in the // cache. The shorten key is generated by the following rules: -// +// // 1. If the query contains a space in the middle: i.e. the query consists of // multiple words, the method removes the last word from the query, and // returns joined remaining words with space. -// +// // 2. If the query is a single word and it's an URL, the method returns a new // URL excluding search query with the upper path of the original URL. -// +// // 3. If the query is a single word and it's not an URL, the method returns a // word with the half-length of the original query. // @@ -29,11 +29,15 @@ const WHITESPACE = /\s/; // export const shortKey = (query: string): string => { if (WHITESPACE.test(query)) { - return query.split(WHITESPACE).filter(word => word.length > 0).slice(0, -1).join(' '); + return query + .split(WHITESPACE) + .filter((word) => word.length > 0) + .slice(0, -1) + .join(" "); } let url; try { - url = new URL(query) + url = new URL(query); } catch (e) { return query.slice(0, query.length / 2); } @@ -42,12 +46,12 @@ export const shortKey = (query: string): string => { // may be on typing or removing URLs such as "such as https://goog" return query.slice(0, query.length / 2); } - if (url.pathname.endsWith('/')) { + if (url.pathname.endsWith("/")) { // remove parameters and move to upper path - return new URL('..', url).href; + return new URL("..", url).href; } // remove parameters - return new URL('.', url).href; + return new URL(".", url).href; }; export default class PrefetchAndCache<T> { @@ -58,9 +62,8 @@ export default class PrefetchAndCache<T> { constructor( private getter: Getter<T>, private filter: Filter<T>, - private prefetchThrethold: number = 1, - ) { - } + private prefetchThrethold: number = 1 + ) {} async get(query: string): Promise<T[]> { query = query.trim(); @@ -79,7 +82,7 @@ export default class PrefetchAndCache<T> { private needToRefresh(query: string): boolean { if (!this.shortKey) { // no cache - return true + return true; } if (query.length < this.shortKey.length) { @@ -89,17 +92,17 @@ export default class PrefetchAndCache<T> { } if (!query.startsWith(this.shortKey)) { - // queyr: "hello_w" - // shorten: "hello_morning" - return true + // queyr: "hello_w" + // shorten: "hello_morning" + return true; } - if (query.slice(this.shortKey.length).includes(' ')) { + if (query.slice(this.shortKey.length).includes(" ")) { // queyr: "hello x" // shorten: "hello" return true; } - return false + return false; } } diff --git a/src/background/completion/impl/TabRepositoryImpl.ts b/src/background/completion/impl/TabRepositoryImpl.ts index adcaba7..5e33e5a 100644 --- a/src/background/completion/impl/TabRepositoryImpl.ts +++ b/src/background/completion/impl/TabRepositoryImpl.ts @@ -1,34 +1,34 @@ import TabRepository, { Tab } from "../TabRepository"; -const COMPLETION_ITEM_LIMIT = 10; - export default class TabRepositoryImpl implements TabRepository { async queryTabs(query: string, excludePinned: boolean): Promise<Tab[]> { const tabs = await browser.tabs.query({ currentWindow: true }); return tabs .filter((t) => { - return t.url && t.url.toLowerCase().includes(query.toLowerCase()) || - t.title && t.title.toLowerCase().includes(query.toLowerCase()); + return ( + (t.url && t.url.toLowerCase().includes(query.toLowerCase())) || + (t.title && t.title.toLowerCase().includes(query.toLowerCase())) + ); }) .filter((t) => { return !(excludePinned && t.pinned); }) - .filter(item => item.id && item.title && item.url) - .slice(0, COMPLETION_ITEM_LIMIT) + .filter((item) => item.id && item.title && item.url) .map(TabRepositoryImpl.toEntity); } async getAllTabs(excludePinned: boolean): Promise<Tab[]> { - if (excludePinned) { - return (await browser.tabs.query({ currentWindow: true, pinned: true })) - .map(TabRepositoryImpl.toEntity) - - } - return (await browser.tabs.query({ currentWindow: true })) - .map(TabRepositoryImpl.toEntity) + if (excludePinned) { + return ( + await browser.tabs.query({ currentWindow: true, pinned: true }) + ).map(TabRepositoryImpl.toEntity); + } + return (await browser.tabs.query({ currentWindow: true })).map( + TabRepositoryImpl.toEntity + ); } - private static toEntity(tab: browser.tabs.Tab,): Tab { + private static toEntity(tab: browser.tabs.Tab): Tab { return { id: tab.id!!, url: tab.url!!, @@ -36,6 +36,6 @@ export default class TabRepositoryImpl implements TabRepository { title: tab.title!!, faviconUrl: tab.favIconUrl, index: tab.index, - } + }; } } diff --git a/src/background/completion/impl/filters.ts b/src/background/completion/impl/filters.ts index 3aa56e4..523491d 100644 --- a/src/background/completion/impl/filters.ts +++ b/src/background/completion/impl/filters.ts @@ -1,32 +1,36 @@ type Item = browser.history.HistoryItem; const filterHttp = (items: Item[]): Item[] => { - const httpsHosts = items.map(x => new URL(x.url as string)) - .filter(x => x.protocol === 'https:') - .map(x => x.host); + const httpsHosts = items + .map((x) => new URL(x.url as string)) + .filter((x) => x.protocol === "https:") + .map((x) => x.host); const hostsSet = new Set(httpsHosts); return items.filter((item: Item) => { const url = new URL(item.url as string); - return url.protocol === 'https:' || !hostsSet.has(url.host); + return url.protocol === "https:" || !hostsSet.has(url.host); }); }; const filterBlankTitle = (items: Item[]): Item[] => { - return items.filter(item => item.title && item.title !== ''); + return items.filter((item) => item.title && item.title !== ""); }; const filterByTailingSlash = (items: Item[]): Item[] => { - const urls = items.map(item => new URL(item.url as string)); + const urls = items.map((item) => new URL(item.url as string)); const simplePaths = urls - .filter(url => url.hash === '' && url.search === '') - .map(url => url.origin + url.pathname); + .filter((url) => url.hash === "" && url.search === "") + .map((url) => url.origin + url.pathname); const pathsSet = new Set(simplePaths); return items.filter((item) => { const url = new URL(item.url as string); - if (url.hash !== '' || url.search !== '' || - url.pathname.slice(-1) !== '/') { + if ( + url.hash !== "" || + url.search !== "" || + url.pathname.slice(-1) !== "/" + ) { return true; } return !pathsSet.has(url.origin + url.pathname.slice(0, -1)); @@ -34,14 +38,15 @@ const filterByTailingSlash = (items: Item[]): Item[] => { }; const filterByPathname = (items: Item[]): Item[] => { - const hash: {[key: string]: Item} = {}; + const hash: { [key: string]: Item } = {}; for (const item of items) { const url = new URL(item.url as string); const pathname = url.origin + url.pathname; if (!hash[pathname]) { hash[pathname] = item; - } else if ((hash[pathname].url as string).length > - (item.url as string).length) { + } else if ( + (hash[pathname].url as string).length > (item.url as string).length + ) { hash[pathname] = item; } } @@ -49,13 +54,14 @@ const filterByPathname = (items: Item[]): Item[] => { }; const filterByOrigin = (items: Item[]): Item[] => { - const hash: {[key: string]: Item} = {}; + const hash: { [key: string]: Item } = {}; for (const item of items) { const origin = new URL(item.url as string).origin; if (!hash[origin]) { hash[origin] = item; - } else if ((hash[origin].url as string).length > - (item.url as string).length) { + } else if ( + (hash[origin].url as string).length > (item.url as string).length + ) { hash[origin] = item; } } @@ -63,6 +69,9 @@ const filterByOrigin = (items: Item[]): Item[] => { }; export { - filterHttp, filterBlankTitle, filterByTailingSlash, - filterByPathname, filterByOrigin + filterHttp, + filterBlankTitle, + filterByTailingSlash, + filterByPathname, + filterByOrigin, }; diff --git a/src/background/controllers/AddonEnabledController.ts b/src/background/controllers/AddonEnabledController.ts index 903df40..170abdf 100644 --- a/src/background/controllers/AddonEnabledController.ts +++ b/src/background/controllers/AddonEnabledController.ts @@ -1,13 +1,9 @@ -import { injectable } from 'tsyringe'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; +import { injectable } from "tsyringe"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; @injectable() export default class AddonEnabledController { - - constructor( - private addonEnabledUseCase: AddonEnabledUseCase, - ) { - } + constructor(private addonEnabledUseCase: AddonEnabledUseCase) {} indicate(enabled: boolean): Promise<any> { return this.addonEnabledUseCase.indicate(enabled); diff --git a/src/background/controllers/CommandController.ts b/src/background/controllers/CommandController.ts index 16aa6e8..f19303f 100644 --- a/src/background/controllers/CommandController.ts +++ b/src/background/controllers/CommandController.ts @@ -1,17 +1,14 @@ -import { injectable } from 'tsyringe'; -import CommandUseCase from '../usecases/CommandUseCase'; +import { injectable } from "tsyringe"; +import CommandUseCase from "../usecases/CommandUseCase"; const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 - return str.replace(/^\s+/, ''); + return str.replace(/^\s+/, ""); }; @injectable() export default class CommandController { - constructor( - private commandIndicator: CommandUseCase, - ) { - } + constructor(private commandIndicator: CommandUseCase) {} // eslint-disable-next-line complexity exec(line: string): Promise<any> { @@ -24,44 +21,44 @@ export default class CommandController { const keywords = trimStart(trimmed.slice(name.length)); switch (words[0]) { - case 'o': - case 'open': - return this.commandIndicator.open(keywords); - case 't': - case 'tabopen': - return this.commandIndicator.tabopen(keywords); - case 'w': - case 'winopen': - return this.commandIndicator.winopen(keywords); - case 'b': - case 'buffer': - return this.commandIndicator.buffer(keywords); - case 'bd': - case 'bdel': - case 'bdelete': - return this.commandIndicator.bdelete(false, keywords); - case 'bd!': - case 'bdel!': - case 'bdelete!': - return this.commandIndicator.bdelete(true, keywords); - case 'bdeletes': - return this.commandIndicator.bdeletes(false, keywords); - case 'bdeletes!': - return this.commandIndicator.bdeletes(true, keywords); - case 'addbookmark': - return this.commandIndicator.addbookmark(keywords); - case 'q': - case 'quit': - return this.commandIndicator.quit(); - case 'qa': - case 'quitall': - return this.commandIndicator.quitAll(); - case 'set': - return this.commandIndicator.set(keywords); - case 'h': - case 'help': - return this.commandIndicator.help(); + case "o": + case "open": + return this.commandIndicator.open(keywords); + case "t": + case "tabopen": + return this.commandIndicator.tabopen(keywords); + case "w": + case "winopen": + return this.commandIndicator.winopen(keywords); + case "b": + case "buffer": + return this.commandIndicator.buffer(keywords); + case "bd": + case "bdel": + case "bdelete": + return this.commandIndicator.bdelete(false, keywords); + case "bd!": + case "bdel!": + case "bdelete!": + return this.commandIndicator.bdelete(true, keywords); + case "bdeletes": + return this.commandIndicator.bdeletes(false, keywords); + case "bdeletes!": + return this.commandIndicator.bdeletes(true, keywords); + case "addbookmark": + return this.commandIndicator.addbookmark(keywords); + case "q": + case "quit": + return this.commandIndicator.quit(); + case "qa": + case "quitall": + return this.commandIndicator.quitAll(); + case "set": + return this.commandIndicator.set(keywords); + case "h": + case "help": + return this.commandIndicator.help(); } - throw new Error(words[0] + ' command is not defined'); + throw new Error(words[0] + " command is not defined"); } } diff --git a/src/background/controllers/CompletionController.ts b/src/background/controllers/CompletionController.ts index fb6137c..35538be 100644 --- a/src/background/controllers/CompletionController.ts +++ b/src/background/controllers/CompletionController.ts @@ -4,7 +4,7 @@ import { ConsoleRequestBookmarksResponse, ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse, - ConsoleRequesttabsResponse + ConsoleRequesttabsResponse, } from "../../shared/messages"; import { injectable } from "tsyringe"; import OpenCompletionUseCase from "../completion/OpenCompletionUseCase"; @@ -16,20 +16,23 @@ export default class CompletionController { constructor( private completionUseCase: OpenCompletionUseCase, private tabCompletionUseCase: TabCompletionUseCase, - private propertyCompletionUseCase: PropertyCompletionUseCase, - ) { - } + private propertyCompletionUseCase: PropertyCompletionUseCase + ) {} async getCompletionTypes(): Promise<ConsoleGetCompletionTypesResponse> { return this.completionUseCase.getCompletionTypes(); } - async requestSearchEngines(query: string): Promise<ConsoleRequestSearchEnginesResponse> { + async requestSearchEngines( + query: string + ): Promise<ConsoleRequestSearchEnginesResponse> { const items = await this.completionUseCase.requestSearchEngines(query); - return items.map(name => ({ title: name })); + return items.map((name) => ({ title: name })); } - async requestBookmarks(query: string): Promise<ConsoleRequestBookmarksResponse> { + async requestBookmarks( + query: string + ): Promise<ConsoleRequestBookmarksResponse> { return this.completionUseCase.requestBookmarks(query); } @@ -37,11 +40,14 @@ export default class CompletionController { return this.completionUseCase.requestHistory(query); } - async queryTabs(query: string, excludePinned: boolean): Promise<ConsoleRequesttabsResponse> { + async queryTabs( + query: string, + excludePinned: boolean + ): Promise<ConsoleRequesttabsResponse> { return this.tabCompletionUseCase.queryTabs(query, excludePinned); } async getProperties(): Promise<ConsoleGetPropertiesResponse> { - return this.propertyCompletionUseCase.getProperties(); + return this.propertyCompletionUseCase.getProperties(); } -}
\ No newline at end of file +} diff --git a/src/background/controllers/FindController.ts b/src/background/controllers/FindController.ts index 1cec962..92dfeb0 100644 --- a/src/background/controllers/FindController.ts +++ b/src/background/controllers/FindController.ts @@ -1,12 +1,9 @@ -import { injectable } from 'tsyringe'; -import FindUseCase from '../usecases/FindUseCase'; +import { injectable } from "tsyringe"; +import FindUseCase from "../usecases/FindUseCase"; @injectable() export default class FindController { - constructor( - private findUseCase: FindUseCase, - ) { - } + constructor(private findUseCase: FindUseCase) {} getKeyword(): Promise<string> { return this.findUseCase.getKeyword(); diff --git a/src/background/controllers/LinkController.ts b/src/background/controllers/LinkController.ts index af6148e..a410bc7 100644 --- a/src/background/controllers/LinkController.ts +++ b/src/background/controllers/LinkController.ts @@ -1,19 +1,18 @@ -import { injectable } from 'tsyringe'; -import LinkUseCase from '../usecases/LinkUseCase'; +import { injectable } from "tsyringe"; +import LinkUseCase from "../usecases/LinkUseCase"; @injectable() export default class LinkController { - constructor( - private linkUseCase: LinkUseCase, - ) { - } + constructor(private linkUseCase: LinkUseCase) {} openToTab(url: string, tabId: number): Promise<void> { return this.linkUseCase.openToTab(url, tabId); } openNewTab( - url: string, openerId: number, background: boolean, + url: string, + openerId: number, + background: boolean ): Promise<void> { return this.linkUseCase.openNewTab(url, openerId, background); } diff --git a/src/background/controllers/MarkController.ts b/src/background/controllers/MarkController.ts index 4726fbc..0d468f2 100644 --- a/src/background/controllers/MarkController.ts +++ b/src/background/controllers/MarkController.ts @@ -1,12 +1,9 @@ -import { injectable } from 'tsyringe'; -import MarkUseCase from '../usecases/MarkUseCase'; +import { injectable } from "tsyringe"; +import MarkUseCase from "../usecases/MarkUseCase"; @injectable() export default class MarkController { - constructor( - private markUseCase: MarkUseCase, - ) { - } + constructor(private markUseCase: MarkUseCase) {} setGlobal(key: string, x: number, y: number): Promise<any> { return this.markUseCase.setGlobal(key, x, y); diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts index 181dd19..5a7047d 100644 --- a/src/background/controllers/OperationController.ts +++ b/src/background/controllers/OperationController.ts @@ -1,12 +1,12 @@ -import { injectable } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import FindUseCase from '../usecases/FindUseCase'; -import ConsoleUseCase from '../usecases/ConsoleUseCase'; -import TabUseCase from '../usecases/TabUseCase'; -import TabSelectUseCase from '../usecases/TabSelectUseCase'; -import ZoomUseCase from '../usecases/ZoomUseCase'; -import NavigateUseCase from '../usecases/NavigateUseCase'; -import RepeatUseCase from '../usecases/RepeatUseCase'; +import { injectable } from "tsyringe"; +import * as operations from "../../shared/operations"; +import FindUseCase from "../usecases/FindUseCase"; +import ConsoleUseCase from "../usecases/ConsoleUseCase"; +import TabUseCase from "../usecases/TabUseCase"; +import TabSelectUseCase from "../usecases/TabSelectUseCase"; +import ZoomUseCase from "../usecases/ZoomUseCase"; +import NavigateUseCase from "../usecases/NavigateUseCase"; +import RepeatUseCase from "../usecases/RepeatUseCase"; @injectable() export default class OperationController { @@ -17,9 +17,8 @@ export default class OperationController { private tabSelectUseCase: TabSelectUseCase, private zoomUseCase: ZoomUseCase, private navigateUseCase: NavigateUseCase, - private repeatUseCase: RepeatUseCase, - ) { - } + private repeatUseCase: RepeatUseCase + ) {} async exec(repeat: number, op: operations.Operation): Promise<any> { await this.doOperation(repeat, op); @@ -31,91 +30,96 @@ export default class OperationController { // eslint-disable-next-line complexity, max-lines-per-function async doOperation( repeat: number, - operation: operations.Operation, + operation: operations.Operation ): Promise<any> { // eslint-disable-next-line complexity, max-lines-per-function const opFunc = (() => { switch (operation.type) { - case operations.TAB_CLOSE: - return () => this.tabUseCase.close(false, operation.select === 'left'); - case operations.TAB_CLOSE_RIGHT: - return () => this.tabUseCase.closeRight(); - case operations.TAB_CLOSE_FORCE: - return () => this.tabUseCase.close(true); - case operations.TAB_REOPEN: - return () => this.tabUseCase.reopen(); - case operations.TAB_PREV: - return () => this.tabSelectUseCase.selectPrev(1); - case operations.TAB_NEXT: - return () => this.tabSelectUseCase.selectNext(1); - case operations.TAB_FIRST: - return () => this.tabSelectUseCase.selectFirst(); - case operations.TAB_LAST: - return () => this.tabSelectUseCase.selectLast(); - case operations.TAB_PREV_SEL: - return () => this.tabSelectUseCase.selectPrevSelected(); - case operations.TAB_RELOAD: - return () => this.tabUseCase.reload(operation.cache); - case operations.TAB_PIN: - return () => this.tabUseCase.setPinned(true); - case operations.TAB_UNPIN: - return () => this.tabUseCase.setPinned(false); - case operations.TAB_TOGGLE_PINNED: - return () => this.tabUseCase.togglePinned(); - case operations.TAB_DUPLICATE: - return () => this.tabUseCase.duplicate(); - case operations.PAGE_SOURCE: - return () => this.tabUseCase.openPageSource(); - case operations.PAGE_HOME: - return () => this.tabUseCase.openHome(operation.newTab); - case operations.ZOOM_IN: - return () => this.zoomUseCase.zoomIn(); - case operations.ZOOM_OUT: - return () => this.zoomUseCase.zoomOut(); - case operations.ZOOM_NEUTRAL: - return () => this.zoomUseCase.zoomNutoral(); - case operations.COMMAND_SHOW: - return () => this.consoleUseCase.showCommand(); - case operations.COMMAND_SHOW_OPEN: - return () => this.consoleUseCase.showOpenCommand(operation.alter); - case operations.COMMAND_SHOW_TABOPEN: - return () => this.consoleUseCase.showTabopenCommand(operation.alter); - case operations.COMMAND_SHOW_WINOPEN: - return () => this.consoleUseCase.showWinopenCommand(operation.alter); - case operations.COMMAND_SHOW_BUFFER: - return () => this.consoleUseCase.showBufferCommand(); - case operations.COMMAND_SHOW_ADDBOOKMARK: - return () => this.consoleUseCase.showAddbookmarkCommand( - operation.alter); - case operations.FIND_START: - return () => this.findUseCase.findStart(); - case operations.CANCEL: - return () => this.consoleUseCase.hideConsole(); - case operations.NAVIGATE_HISTORY_PREV: - return () => this.navigateUseCase.openHistoryPrev(); - case operations.NAVIGATE_HISTORY_NEXT: - return () => this.navigateUseCase.openHistoryNext(); - case operations.NAVIGATE_LINK_PREV: - return () => this.navigateUseCase.openLinkPrev(); - case operations.NAVIGATE_LINK_NEXT: - return () => this.navigateUseCase.openLinkNext(); - case operations.NAVIGATE_PARENT: - return () => this.navigateUseCase.openParent(); - case operations.NAVIGATE_ROOT: - return () => this.navigateUseCase.openRoot(); - case operations.REPEAT_LAST: - return () => { - const last = this.repeatUseCase.getLastOperation(); - if (typeof last !== 'undefined') { - return this.doOperation(1, last); - } - return Promise.resolve(); - }; - case operations.INTERNAL_OPEN_URL: - return () => this.tabUseCase.openURL( - operation.url, operation.newTab, operation.newWindow); - default: - throw new Error('unknown operation: ' + operation.type); + case operations.TAB_CLOSE: + return () => + this.tabUseCase.close(false, operation.select === "left"); + case operations.TAB_CLOSE_RIGHT: + return () => this.tabUseCase.closeRight(); + case operations.TAB_CLOSE_FORCE: + return () => this.tabUseCase.close(true); + case operations.TAB_REOPEN: + return () => this.tabUseCase.reopen(); + case operations.TAB_PREV: + return () => this.tabSelectUseCase.selectPrev(1); + case operations.TAB_NEXT: + return () => this.tabSelectUseCase.selectNext(1); + case operations.TAB_FIRST: + return () => this.tabSelectUseCase.selectFirst(); + case operations.TAB_LAST: + return () => this.tabSelectUseCase.selectLast(); + case operations.TAB_PREV_SEL: + return () => this.tabSelectUseCase.selectPrevSelected(); + case operations.TAB_RELOAD: + return () => this.tabUseCase.reload(operation.cache); + case operations.TAB_PIN: + return () => this.tabUseCase.setPinned(true); + case operations.TAB_UNPIN: + return () => this.tabUseCase.setPinned(false); + case operations.TAB_TOGGLE_PINNED: + return () => this.tabUseCase.togglePinned(); + case operations.TAB_DUPLICATE: + return () => this.tabUseCase.duplicate(); + case operations.PAGE_SOURCE: + return () => this.tabUseCase.openPageSource(); + case operations.PAGE_HOME: + return () => this.tabUseCase.openHome(operation.newTab); + case operations.ZOOM_IN: + return () => this.zoomUseCase.zoomIn(); + case operations.ZOOM_OUT: + return () => this.zoomUseCase.zoomOut(); + case operations.ZOOM_NEUTRAL: + return () => this.zoomUseCase.zoomNutoral(); + case operations.COMMAND_SHOW: + return () => this.consoleUseCase.showCommand(); + case operations.COMMAND_SHOW_OPEN: + return () => this.consoleUseCase.showOpenCommand(operation.alter); + case operations.COMMAND_SHOW_TABOPEN: + return () => this.consoleUseCase.showTabopenCommand(operation.alter); + case operations.COMMAND_SHOW_WINOPEN: + return () => this.consoleUseCase.showWinopenCommand(operation.alter); + case operations.COMMAND_SHOW_BUFFER: + return () => this.consoleUseCase.showBufferCommand(); + case operations.COMMAND_SHOW_ADDBOOKMARK: + return () => + this.consoleUseCase.showAddbookmarkCommand(operation.alter); + case operations.FIND_START: + return () => this.findUseCase.findStart(); + case operations.CANCEL: + return () => this.consoleUseCase.hideConsole(); + case operations.NAVIGATE_HISTORY_PREV: + return () => this.navigateUseCase.openHistoryPrev(); + case operations.NAVIGATE_HISTORY_NEXT: + return () => this.navigateUseCase.openHistoryNext(); + case operations.NAVIGATE_LINK_PREV: + return () => this.navigateUseCase.openLinkPrev(); + case operations.NAVIGATE_LINK_NEXT: + return () => this.navigateUseCase.openLinkNext(); + case operations.NAVIGATE_PARENT: + return () => this.navigateUseCase.openParent(); + case operations.NAVIGATE_ROOT: + return () => this.navigateUseCase.openRoot(); + case operations.REPEAT_LAST: + return () => { + const last = this.repeatUseCase.getLastOperation(); + if (typeof last !== "undefined") { + return this.doOperation(1, last); + } + return Promise.resolve(); + }; + case operations.INTERNAL_OPEN_URL: + return () => + this.tabUseCase.openURL( + operation.url, + operation.newTab, + operation.newWindow + ); + default: + throw new Error("unknown operation: " + operation.type); } })(); @@ -125,4 +129,3 @@ export default class OperationController { } } } - diff --git a/src/background/controllers/SettingController.ts b/src/background/controllers/SettingController.ts index 26edc07..4248746 100644 --- a/src/background/controllers/SettingController.ts +++ b/src/background/controllers/SettingController.ts @@ -1,15 +1,14 @@ -import { injectable } from 'tsyringe'; -import SettingUseCase from '../usecases/SettingUseCase'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; -import Settings from '../../shared/settings/Settings'; +import { injectable } from "tsyringe"; +import SettingUseCase from "../usecases/SettingUseCase"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; +import Settings from "../../shared/settings/Settings"; @injectable() export default class SettingController { constructor( private settingUseCase: SettingUseCase, - private contentMessageClient: ContentMessageClient, - ) { - } + private contentMessageClient: ContentMessageClient + ) {} getSetting(): Promise<Settings> { return this.settingUseCase.getCached(); diff --git a/src/background/controllers/VersionController.ts b/src/background/controllers/VersionController.ts index b00185a..92fca9e 100644 --- a/src/background/controllers/VersionController.ts +++ b/src/background/controllers/VersionController.ts @@ -1,12 +1,9 @@ -import { injectable } from 'tsyringe'; -import VersionUseCase from '../usecases/VersionUseCase'; +import { injectable } from "tsyringe"; +import VersionUseCase from "../usecases/VersionUseCase"; @injectable() export default class VersionController { - constructor( - private versionUseCase: VersionUseCase, - ) { - } + constructor(private versionUseCase: VersionUseCase) {} notify(): Promise<void> { return this.versionUseCase.notify(); diff --git a/src/background/di.ts b/src/background/di.ts index c186262..5e6ad03 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -1,19 +1,28 @@ /* eslint-disable max-len */ -import { LocalSettingRepository, SyncSettingRepository } from "./repositories/SettingRepository"; +import { + LocalSettingRepository, + SyncSettingRepository, +} from "./repositories/SettingRepository"; import { NotifierImpl } from "./presenters/Notifier"; import { CachedSettingRepositoryImpl } from "./repositories/CachedSettingRepository"; -import { container } from 'tsyringe'; +import { container } from "tsyringe"; import HistoryRepositoryImpl from "./completion/impl/HistoryRepositoryImpl"; import BookmarkRepositoryImpl from "./completion/impl/BookmarkRepositoryImpl"; import TabRepositoryImpl from "./completion/impl/TabRepositoryImpl"; -import {TabPresenterImpl} from "./presenters/TabPresenter"; +import { TabPresenterImpl } from "./presenters/TabPresenter"; -container.register('LocalSettingRepository', { useValue: LocalSettingRepository }); -container.register('SyncSettingRepository', { useClass: SyncSettingRepository }); -container.register('CachedSettingRepository', { useClass: CachedSettingRepositoryImpl }); -container.register('Notifier', { useClass: NotifierImpl }); -container.register('HistoryRepository', { useClass: HistoryRepositoryImpl }); -container.register('BookmarkRepository', { useClass: BookmarkRepositoryImpl }); -container.register('TabRepository', { useClass: TabRepositoryImpl }); -container.register('TabPresenter', { useClass: TabPresenterImpl }); +container.register("LocalSettingRepository", { + useValue: LocalSettingRepository, +}); +container.register("SyncSettingRepository", { + useClass: SyncSettingRepository, +}); +container.register("CachedSettingRepository", { + useClass: CachedSettingRepositoryImpl, +}); +container.register("Notifier", { useClass: NotifierImpl }); +container.register("HistoryRepository", { useClass: HistoryRepositoryImpl }); +container.register("BookmarkRepository", { useClass: BookmarkRepositoryImpl }); +container.register("TabRepository", { useClass: TabRepositoryImpl }); +container.register("TabPresenter", { useClass: TabPresenterImpl }); diff --git a/src/background/index.ts b/src/background/index.ts index f75c53b..6fe68af 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,7 +1,7 @@ -import 'reflect-metadata'; -import { container } from 'tsyringe'; -import Application from './Application'; -import './di'; +import "reflect-metadata"; +import { container } from "tsyringe"; +import Application from "./Application"; +import "./di"; const app = container.resolve(Application); app.run(); diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts index 1385fe7..8d0af89 100644 --- a/src/background/infrastructures/ConsoleClient.ts +++ b/src/background/infrastructures/ConsoleClient.ts @@ -1,5 +1,5 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; @injectable() export default class ConsoleClient { @@ -12,7 +12,7 @@ export default class ConsoleClient { showFind(tabId: number): Promise<any> { return browser.tabs.sendMessage(tabId, { - type: messages.CONSOLE_SHOW_FIND + type: messages.CONSOLE_SHOW_FIND, }); } @@ -36,4 +36,3 @@ export default class ConsoleClient { }); } } - diff --git a/src/background/infrastructures/ContentMessageClient.ts b/src/background/infrastructures/ContentMessageClient.ts index b6c0c23..e889392 100644 --- a/src/background/infrastructures/ContentMessageClient.ts +++ b/src/background/infrastructures/ContentMessageClient.ts @@ -1,12 +1,12 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; @injectable() export default class ContentMessageClient { async broadcastSettingsChanged(): Promise<void> { const tabs = await browser.tabs.query({}); for (const tab of tabs) { - if (!tab.id || tab.url && tab.url.startsWith('about:')) { + if (!tab.id || (tab.url && tab.url.startsWith("about:"))) { continue; } browser.tabs.sendMessage(tab.id, { @@ -19,7 +19,7 @@ export default class ContentMessageClient { const enabled = await browser.tabs.sendMessage(tabId, { type: messages.ADDON_ENABLED_QUERY, }); - return enabled as any as boolean; + return (enabled as any) as boolean; } async toggleAddonEnabled(tabId: number): Promise<void> { diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index 2fbb9cf..6978d35 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -1,18 +1,18 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import * as operations from '../../shared/operations'; -import CommandController from '../controllers/CommandController'; -import SettingController from '../controllers/SettingController'; -import FindController from '../controllers/FindController'; -import AddonEnabledController from '../controllers/AddonEnabledController'; -import LinkController from '../controllers/LinkController'; -import OperationController from '../controllers/OperationController'; -import MarkController from '../controllers/MarkController'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import * as operations from "../../shared/operations"; +import CommandController from "../controllers/CommandController"; +import SettingController from "../controllers/SettingController"; +import FindController from "../controllers/FindController"; +import AddonEnabledController from "../controllers/AddonEnabledController"; +import LinkController from "../controllers/LinkController"; +import OperationController from "../controllers/OperationController"; +import MarkController from "../controllers/MarkController"; import CompletionController from "../controllers/CompletionController"; @injectable() export default class ContentMessageListener { - private consolePorts: {[tabId: number]: browser.runtime.Port}; + private consolePorts: { [tabId: number]: browser.runtime.Port }; constructor( private settingController: SettingController, @@ -22,21 +22,29 @@ export default class ContentMessageListener { private addonEnabledController: AddonEnabledController, private linkController: LinkController, private operationController: OperationController, - private markController: MarkController, + private markController: MarkController ) { this.consolePorts = {}; } run(): void { - browser.runtime.onMessage.addListener(( - message: any, sender: browser.runtime.MessageSender, - ) => { - try { - const ret = this.onMessage(message, sender.tab as browser.tabs.Tab); - if (!(ret instanceof Promise)) { - return {}; - } - return ret.catch((e) => { + browser.runtime.onMessage.addListener( + (message: any, sender: browser.runtime.MessageSender) => { + try { + const ret = this.onMessage(message, sender.tab as browser.tabs.Tab); + if (!(ret instanceof Promise)) { + return {}; + } + return ret.catch((e) => { + if (!sender.tab || !sender.tab.id) { + return; + } + return browser.tabs.sendMessage(sender.tab.id, { + type: messages.CONSOLE_SHOW_ERROR, + text: e.message, + }); + }); + } catch (e) { if (!sender.tab || !sender.tab.id) { return; } @@ -44,64 +52,62 @@ export default class ContentMessageListener { type: messages.CONSOLE_SHOW_ERROR, text: e.message, }); - }); - } catch (e) { - if (!sender.tab || !sender.tab.id) { - return; } - return browser.tabs.sendMessage(sender.tab.id, { - type: messages.CONSOLE_SHOW_ERROR, - text: e.message, - }); } - }); + ); browser.runtime.onConnect.addListener(this.onConnected.bind(this)); } onMessage( - message: messages.Message, senderTab: browser.tabs.Tab, + message: messages.Message, + senderTab: browser.tabs.Tab ): Promise<any> | any { switch (message.type) { - case messages.CONSOLE_GET_COMPLETION_TYPES: - return this.completionController.getCompletionTypes(); - case messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE: - return this.completionController.requestSearchEngines(message.query); - case messages.CONSOLE_REQUEST_BOOKMARKS: - return this.completionController.requestBookmarks(message.query); - case messages.CONSOLE_REQUEST_HISTORY: - return this.completionController.requestHistory(message.query); - case messages.CONSOLE_REQUEST_TABS: - return this.completionController.queryTabs(message.query, message.excludePinned); - case messages.CONSOLE_GET_PROPERTIES: - return this.completionController.getProperties(); - case messages.CONSOLE_ENTER_COMMAND: - return this.onConsoleEnterCommand(message.text); - case messages.SETTINGS_QUERY: - return this.onSettingsQuery(); - case messages.FIND_GET_KEYWORD: - return this.onFindGetKeyword(); - case messages.FIND_SET_KEYWORD: - return this.onFindSetKeyword(message.keyword); - case messages.ADDON_ENABLED_RESPONSE: - return this.onAddonEnabledResponse(message.enabled); - case messages.OPEN_URL: - return this.onOpenUrl( - message.newTab, - message.url, - senderTab.id as number, - message.background); - case messages.BACKGROUND_OPERATION: - return this.onBackgroundOperation(message.repeat, message.operation); - case messages.MARK_SET_GLOBAL: - return this.onMarkSetGlobal(message.key, message.x, message.y); - case messages.MARK_JUMP_GLOBAL: - return this.onMarkJumpGlobal(message.key); - case messages.CONSOLE_FRAME_MESSAGE: - return this.onConsoleFrameMessage( - senderTab.id as number, message.message, - ); + case messages.CONSOLE_GET_COMPLETION_TYPES: + return this.completionController.getCompletionTypes(); + case messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE: + return this.completionController.requestSearchEngines(message.query); + case messages.CONSOLE_REQUEST_BOOKMARKS: + return this.completionController.requestBookmarks(message.query); + case messages.CONSOLE_REQUEST_HISTORY: + return this.completionController.requestHistory(message.query); + case messages.CONSOLE_REQUEST_TABS: + return this.completionController.queryTabs( + message.query, + message.excludePinned + ); + case messages.CONSOLE_GET_PROPERTIES: + return this.completionController.getProperties(); + case messages.CONSOLE_ENTER_COMMAND: + return this.onConsoleEnterCommand(message.text); + case messages.SETTINGS_QUERY: + return this.onSettingsQuery(); + case messages.FIND_GET_KEYWORD: + return this.onFindGetKeyword(); + case messages.FIND_SET_KEYWORD: + return this.onFindSetKeyword(message.keyword); + case messages.ADDON_ENABLED_RESPONSE: + return this.onAddonEnabledResponse(message.enabled); + case messages.OPEN_URL: + return this.onOpenUrl( + message.newTab, + message.url, + senderTab.id as number, + message.background + ); + case messages.BACKGROUND_OPERATION: + return this.onBackgroundOperation(message.repeat, message.operation); + case messages.MARK_SET_GLOBAL: + return this.onMarkSetGlobal(message.key, message.x, message.y); + case messages.MARK_JUMP_GLOBAL: + return this.onMarkJumpGlobal(message.key); + case messages.CONSOLE_FRAME_MESSAGE: + return this.onConsoleFrameMessage( + senderTab.id as number, + message.message + ); } - throw new Error('unsupported message: ' + message.type); + throw new Error("unsupported message: " + message.type); } onConsoleEnterCommand(text: string): Promise<any> { @@ -125,7 +131,10 @@ export default class ContentMessageListener { } onOpenUrl( - newTab: boolean, url: string, openerId: number, background: boolean, + newTab: boolean, + url: string, + openerId: number, + background: boolean ): Promise<any> { if (newTab) { return this.linkController.openNewTab(url, openerId, background); @@ -154,7 +163,7 @@ export default class ContentMessageListener { } onConnected(port: browser.runtime.Port): void { - if (port.name !== 'vimvixen-console') { + if (port.name !== "vimvixen-console") { return; } diff --git a/src/background/infrastructures/MemoryStorage.ts b/src/background/infrastructures/MemoryStorage.ts index af445a6..ad7bcd7 100644 --- a/src/background/infrastructures/MemoryStorage.ts +++ b/src/background/infrastructures/MemoryStorage.ts @@ -1,10 +1,10 @@ -const db: {[key: string]: any} = {}; +const db: { [key: string]: any } = {}; export default class MemoryStorage { set(name: string, value: any): void { const data = JSON.stringify(value); - if (typeof data === 'undefined') { - throw new Error('value is not serializable'); + if (typeof data === "undefined") { + throw new Error("value is not serializable"); } db[name] = data; } diff --git a/src/background/presenters/HelpPresenter.ts b/src/background/presenters/HelpPresenter.ts index f5c3a6b..7fa0597 100644 --- a/src/background/presenters/HelpPresenter.ts +++ b/src/background/presenters/HelpPresenter.ts @@ -1,6 +1,6 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; -const url = 'https://ueokande.github.io/vim-vixen/'; +const url = "https://ueokande.github.io/vim-vixen/"; @injectable() export default class HelpPresenter { diff --git a/src/background/presenters/IndicatorPresenter.ts b/src/background/presenters/IndicatorPresenter.ts index 6a33e62..5b4b673 100644 --- a/src/background/presenters/IndicatorPresenter.ts +++ b/src/background/presenters/IndicatorPresenter.ts @@ -1,18 +1,17 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; @injectable() export default class IndicatorPresenter { indicate(enabled: boolean): Promise<void> { const path = enabled - ? 'resources/enabled_32x32.png' - : 'resources/disabled_32x32.png'; - if (typeof browser.browserAction.setIcon === 'function') { + ? "resources/enabled_32x32.png" + : "resources/disabled_32x32.png"; + if (typeof browser.browserAction.setIcon === "function") { return browser.browserAction.setIcon({ path }); } // setIcon not supported on Android return Promise.resolve(); - } onClick(listener: (arg: browser.tabs.Tab) => void): void { diff --git a/src/background/presenters/Notifier.ts b/src/background/presenters/Notifier.ts index 57d58cb..2cd3225 100644 --- a/src/background/presenters/Notifier.ts +++ b/src/background/presenters/Notifier.ts @@ -1,5 +1,5 @@ -const NOTIFICATION_ID_UPDATE = 'vimvixen-update'; -const NOTIFICATION_ID_INVALID_SETTINGS = 'vimvixen-update-invalid-settings'; +const NOTIFICATION_ID_UPDATE = "vimvixen-update"; +const NOTIFICATION_ID_INVALID_SETTINGS = "vimvixen-update-invalid-settings"; export default interface Notifier { notifyUpdated(version: string, onclick: () => void): Promise<void>; @@ -10,7 +10,7 @@ export default interface Notifier { export class NotifierImpl implements NotifierImpl { async notifyUpdated(version: string, onclick: () => void): Promise<void> { const title = `Vim Vixen ${version} has been installed`; - const message = 'Click here to see release notes'; + const message = "Click here to see release notes"; const listener = (id: string) => { if (id !== NOTIFICATION_ID_UPDATE) { @@ -22,8 +22,8 @@ export class NotifierImpl implements NotifierImpl { browser.notifications.onClicked.addListener(listener); await browser.notifications.create(NOTIFICATION_ID_UPDATE, { - 'type': 'basic', - 'iconUrl': browser.extension.getURL('resources/icon_48x48.png'), + type: "basic", + iconUrl: browser.extension.getURL("resources/icon_48x48.png"), title, message, }); @@ -32,7 +32,8 @@ export class NotifierImpl implements NotifierImpl { async notifyInvalidSettings(onclick: () => void): Promise<void> { const title = `Loaded settings is invalid`; // eslint-disable-next-line max-len - const message = 'The default settings is used due to the last saved settings is invalid. Check your current settings from the add-on preference'; + const message = + "The default settings is used due to the last saved settings is invalid. Check your current settings from the add-on preference"; const listener = (id: string) => { if (id !== NOTIFICATION_ID_INVALID_SETTINGS) { @@ -44,8 +45,8 @@ export class NotifierImpl implements NotifierImpl { browser.notifications.onClicked.addListener(listener); await browser.notifications.create(NOTIFICATION_ID_INVALID_SETTINGS, { - 'type': 'basic', - 'iconUrl': browser.extension.getURL('resources/icon_48x48.png'), + type: "basic", + iconUrl: browser.extension.getURL("resources/icon_48x48.png"), title, message, }); diff --git a/src/background/presenters/TabPresenter.ts b/src/background/presenters/TabPresenter.ts index bded5a2..09cfa23 100644 --- a/src/background/presenters/TabPresenter.ts +++ b/src/background/presenters/TabPresenter.ts @@ -1,7 +1,7 @@ -import MemoryStorage from '../infrastructures/MemoryStorage'; +import MemoryStorage from "../infrastructures/MemoryStorage"; -const CURRENT_SELECTED_KEY = 'tabs.current.selected'; -const LAST_SELECTED_KEY = 'tabs.last.selected'; +const CURRENT_SELECTED_KEY = "tabs.current.selected"; +const LAST_SELECTED_KEY = "tabs.last.selected"; type Tab = browser.tabs.Tab; @@ -35,7 +35,7 @@ export default interface TabPresenter { setZoom(tabId: number, factor: number): Promise<void>; onSelected( - listener: (arg: { tabId: number, windowId: number}) => void, + listener: (arg: { tabId: number; windowId: number }) => void ): void; } @@ -50,7 +50,8 @@ export class TabPresenterImpl implements TabPresenter { async getCurrent(): Promise<Tab> { const tabs = await browser.tabs.query({ - active: true, currentWindow: true + active: true, + currentWindow: true, }); return tabs[0]; } @@ -62,22 +63,24 @@ export class TabPresenterImpl implements TabPresenter { async getLastSelectedId(): Promise<number | undefined> { const cache = new MemoryStorage(); const tabId = await cache.get(LAST_SELECTED_KEY); - if (tabId === null || typeof tabId === 'undefined') { + if (tabId === null || typeof tabId === "undefined") { return; } return tabId; } - async getByKeyword( - keyword: string, excludePinned = false, - ): Promise<Tab[]> { + async getByKeyword(keyword: string, excludePinned = false): Promise<Tab[]> { const tabs = await browser.tabs.query({ currentWindow: true }); - return tabs.filter((t) => { - return t.url && t.url.toLowerCase().includes(keyword.toLowerCase()) || - t.title && t.title.toLowerCase().includes(keyword.toLowerCase()); - }).filter((t) => { - return !(excludePinned && t.pinned); - }); + return tabs + .filter((t) => { + return ( + (t.url && t.url.toLowerCase().includes(keyword.toLowerCase())) || + (t.title && t.title.toLowerCase().includes(keyword.toLowerCase())) + ); + }) + .filter((t) => { + return !(excludePinned && t.pinned); + }); } async select(tabId: number): Promise<void> { @@ -125,7 +128,7 @@ export class TabPresenterImpl implements TabPresenter { } onSelected( - listener: (arg: { tabId: number, windowId: number}) => void, + listener: (arg: { tabId: number; windowId: number }) => void ): void { browser.tabs.onActivated.addListener(listener); } diff --git a/src/background/presenters/WindowPresenter.ts b/src/background/presenters/WindowPresenter.ts index 150a48b..4f37f5d 100644 --- a/src/background/presenters/WindowPresenter.ts +++ b/src/background/presenters/WindowPresenter.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; @injectable() export default class WindowPresenter { diff --git a/src/background/repositories/BookmarkRepository.ts b/src/background/repositories/BookmarkRepository.ts index 0d2a1fc..e6e55c9 100644 --- a/src/background/repositories/BookmarkRepository.ts +++ b/src/background/repositories/BookmarkRepository.ts @@ -1,17 +1,18 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; @injectable() export default class BookmarkRepository { async create( - title: string, url: string + title: string, + url: string ): Promise<browser.bookmarks.BookmarkTreeNode> { const item = await browser.bookmarks.create({ - type: 'bookmark', + type: "bookmark", title, url, }); if (!item) { - throw new Error('Could not create a bookmark'); + throw new Error("Could not create a bookmark"); } return item; } diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts index a47b64d..20013f4 100644 --- a/src/background/repositories/BrowserSettingRepository.ts +++ b/src/background/repositories/BrowserSettingRepository.ts @@ -1,18 +1,17 @@ -import { injectable } from 'tsyringe'; -import * as urls from '../../shared/urls'; +import { injectable } from "tsyringe"; +import * as urls from "../../shared/urls"; declare namespace browser.browserSettings.homepageOverride { - type BrowserSettings = { value: string; levelOfControl: LevelOfControlType; }; type LevelOfControlType = - 'not_controllable' | - 'controlled_by_other_extensions' | - 'controllable_by_this_extension' | - 'controlled_by_this_extension'; + | "not_controllable" + | "controlled_by_other_extensions" + | "controllable_by_this_extension" + | "controlled_by_this_extension"; function get(param: object): Promise<BrowserSettings>; } @@ -21,6 +20,6 @@ declare namespace browser.browserSettings.homepageOverride { export default class BrowserSettingRepository { async getHomepageUrls(): Promise<string[]> { const { value } = await browser.browserSettings.homepageOverride.get({}); - return value.split('|').map(urls.normalizeUrl); + return value.split("|").map(urls.normalizeUrl); } } diff --git a/src/background/repositories/CachedSettingRepository.ts b/src/background/repositories/CachedSettingRepository.ts index 1af15d4..e3d3950 100644 --- a/src/background/repositories/CachedSettingRepository.ts +++ b/src/background/repositories/CachedSettingRepository.ts @@ -1,17 +1,15 @@ -import MemoryStorage from '../infrastructures/MemoryStorage'; -import Settings from '../../shared/settings/Settings'; -import Properties from '../../shared/settings/Properties'; +import MemoryStorage from "../infrastructures/MemoryStorage"; +import Settings from "../../shared/settings/Settings"; +import Properties from "../../shared/settings/Properties"; -const CACHED_SETTING_KEY = 'setting'; +const CACHED_SETTING_KEY = "setting"; export default interface CachedSettingRepository { get(): Promise<Settings>; update(value: Settings): Promise<void>; - setProperty( - name: string, value: string | number | boolean, - ): Promise<void>; + setProperty(name: string, value: string | number | boolean): Promise<void>; } export class CachedSettingRepositoryImpl implements CachedSettingRepository { @@ -28,35 +26,36 @@ export class CachedSettingRepositoryImpl implements CachedSettingRepository { update(value: Settings): Promise<void> { this.cache.set(CACHED_SETTING_KEY, value.toJSON()); - return Promise.resolve() + return Promise.resolve(); } async setProperty( - name: string, value: string | number | boolean, + name: string, + value: string | number | boolean ): Promise<void> { const def = Properties.def(name); if (!def) { - throw new Error('unknown property: ' + name); + throw new Error("unknown property: " + name); } if (typeof value !== def.type) { throw new TypeError(`property type of ${name} mismatch: ${typeof value}`); } let newValue = value; - if (typeof value === 'string' && value === '') { + if (typeof value === "string" && value === "") { newValue = def.defaultValue; } const current = await this.get(); switch (name) { - case 'hintchars': - current.properties.hintchars = newValue as string; - break; - case 'smoothscroll': - current.properties.smoothscroll = newValue as boolean; - break; - case 'complete': - current.properties.complete = newValue as string; - break; + case "hintchars": + current.properties.hintchars = newValue as string; + break; + case "smoothscroll": + current.properties.smoothscroll = newValue as boolean; + break; + case "complete": + current.properties.complete = newValue as string; + break; } await this.update(current); } diff --git a/src/background/repositories/FindRepository.ts b/src/background/repositories/FindRepository.ts index 6a087f5..be56284 100644 --- a/src/background/repositories/FindRepository.ts +++ b/src/background/repositories/FindRepository.ts @@ -1,7 +1,7 @@ -import { injectable } from 'tsyringe'; -import MemoryStorage from '../infrastructures/MemoryStorage'; +import { injectable } from "tsyringe"; +import MemoryStorage from "../infrastructures/MemoryStorage"; -const FIND_KEYWORD_KEY = 'find-keyword'; +const FIND_KEYWORD_KEY = "find-keyword"; @injectable() export default class FindRepository { @@ -20,4 +20,3 @@ export default class FindRepository { return Promise.resolve(); } } - diff --git a/src/background/repositories/MarkRepository.ts b/src/background/repositories/MarkRepository.ts index 1f4ab0c..e2c1e94 100644 --- a/src/background/repositories/MarkRepository.ts +++ b/src/background/repositories/MarkRepository.ts @@ -1,8 +1,8 @@ -import { injectable } from 'tsyringe'; -import MemoryStorage from '../infrastructures/MemoryStorage'; -import GlobalMark from '../domains/GlobalMark'; +import { injectable } from "tsyringe"; +import MemoryStorage from "../infrastructures/MemoryStorage"; +import GlobalMark from "../domains/GlobalMark"; -const MARK_KEY = 'mark'; +const MARK_KEY = "mark"; @injectable() export default class MarkRepository { @@ -34,4 +34,3 @@ export default class MarkRepository { return this.cache.get(MARK_KEY) || {}; } } - diff --git a/src/background/repositories/RepeatRepository.ts b/src/background/repositories/RepeatRepository.ts index c7f7a71..e3ab43d 100644 --- a/src/background/repositories/RepeatRepository.ts +++ b/src/background/repositories/RepeatRepository.ts @@ -1,8 +1,8 @@ -import { injectable } from 'tsyringe'; -import { Operation } from '../../shared/operations'; -import MemoryStorage from '../infrastructures/MemoryStorage'; +import { injectable } from "tsyringe"; +import { Operation } from "../../shared/operations"; +import MemoryStorage from "../infrastructures/MemoryStorage"; -const REPEAT_KEY = 'repeat'; +const REPEAT_KEY = "repeat"; @injectable() export default class RepeatRepository { diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts index b522045..d726cfb 100644 --- a/src/background/repositories/SettingRepository.ts +++ b/src/background/repositories/SettingRepository.ts @@ -1,4 +1,4 @@ -import SettingData from '../../shared/SettingData'; +import SettingData from "../../shared/SettingData"; export default interface SettingRepository { load(): Promise<SettingData | null>; @@ -8,7 +8,7 @@ export default interface SettingRepository { export class LocalSettingRepository implements SettingRepository { async load(): Promise<SettingData | null> { - const {settings} = await browser.storage.local.get('settings'); + const { settings } = await browser.storage.local.get("settings"); if (!settings) { return null; } @@ -17,7 +17,7 @@ export class LocalSettingRepository implements SettingRepository { onChange(callback: () => void) { browser.storage.onChanged.addListener((changes, area) => { - if (area !== 'local') { + if (area !== "local") { return; } if (changes.settings) { @@ -29,7 +29,7 @@ export class LocalSettingRepository implements SettingRepository { export class SyncSettingRepository implements SettingRepository { async load(): Promise<SettingData | null> { - const {settings} = await browser.storage.sync.get('settings'); + const { settings } = await browser.storage.sync.get("settings"); if (!settings) { return null; } @@ -38,7 +38,7 @@ export class SyncSettingRepository implements SettingRepository { onChange(callback: () => void) { browser.storage.onChanged.addListener((changes, area) => { - if (area !== 'sync') { + if (area !== "sync") { return; } if (changes.settings) { @@ -46,4 +46,4 @@ export class SyncSettingRepository implements SettingRepository { } }); } -}
\ No newline at end of file +} diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts index 51f02e1..f563ab0 100644 --- a/src/background/usecases/AddonEnabledUseCase.ts +++ b/src/background/usecases/AddonEnabledUseCase.ts @@ -1,21 +1,21 @@ -import { inject, injectable } from 'tsyringe'; -import IndicatorPresenter from '../presenters/IndicatorPresenter'; -import TabPresenter from '../presenters/TabPresenter'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; +import { inject, injectable } from "tsyringe"; +import IndicatorPresenter from "../presenters/IndicatorPresenter"; +import TabPresenter from "../presenters/TabPresenter"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; @injectable() export default class AddonEnabledUseCase { constructor( private indicatorPresentor: IndicatorPresenter, @inject("TabPresenter") private tabPresenter: TabPresenter, - private contentMessageClient: ContentMessageClient, + private contentMessageClient: ContentMessageClient ) { this.indicatorPresentor.onClick((tab) => { if (tab.id) { this.onIndicatorClick(tab.id); } }); - this.tabPresenter.onSelected(info => this.onTabSelected(info.tabId)); + this.tabPresenter.onSelected((info) => this.onTabSelected(info.tabId)); } indicate(enabled: boolean): Promise<void> { diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts index d2d707e..811ec77 100644 --- a/src/background/usecases/CommandUseCase.ts +++ b/src/background/usecases/CommandUseCase.ts @@ -1,29 +1,29 @@ -import { injectable, inject } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import * as parsers from './parsers'; -import * as urls from '../../shared/urls'; -import TabPresenter from '../presenters/TabPresenter'; -import WindowPresenter from '../presenters/WindowPresenter'; -import HelpPresenter from '../presenters/HelpPresenter'; -import CachedSettingRepository from '../repositories/CachedSettingRepository'; -import BookmarkRepository from '../repositories/BookmarkRepository'; -import ConsoleClient from '../infrastructures/ConsoleClient'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; -import RepeatUseCase from '../usecases/RepeatUseCase'; +import { injectable, inject } from "tsyringe"; +import * as operations from "../../shared/operations"; +import * as parsers from "./parsers"; +import * as urls from "../../shared/urls"; +import TabPresenter from "../presenters/TabPresenter"; +import WindowPresenter from "../presenters/WindowPresenter"; +import HelpPresenter from "../presenters/HelpPresenter"; +import CachedSettingRepository from "../repositories/CachedSettingRepository"; +import BookmarkRepository from "../repositories/BookmarkRepository"; +import ConsoleClient from "../infrastructures/ConsoleClient"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; +import RepeatUseCase from "../usecases/RepeatUseCase"; @injectable() export default class CommandIndicator { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private windowPresenter: WindowPresenter, private helpPresenter: HelpPresenter, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, + @inject("CachedSettingRepository") + private cachedSettingRepository: CachedSettingRepository, private bookmarkRepository: BookmarkRepository, private consoleClient: ConsoleClient, private contentMessageClient: ContentMessageClient, - private repeatUseCase: RepeatUseCase, - ) { - } + private repeatUseCase: RepeatUseCase + ) {} async open(keywords: string): Promise<browser.tabs.Tab> { const url = await this.urlOrSearch(keywords); @@ -67,14 +67,14 @@ export default class CommandIndicator { throw new RangeError(`tab ${index + 1} does not exist`); } return this.tabPresenter.select(tabs[index].id as number); - } else if (keywords.trim() === '%') { + } else if (keywords.trim() === "%") { // Select current window return; - } else if (keywords.trim() === '#') { + } else if (keywords.trim() === "#") { // Select last selected window const lastId = await this.tabPresenter.getLastSelectedId(); - if (typeof lastId === 'undefined' || lastId === null) { - throw new Error('No last selected tab'); + if (typeof lastId === "undefined" || lastId === null) { + throw new Error("No last selected tab"); } return this.tabPresenter.select(lastId); } @@ -82,7 +82,7 @@ export default class CommandIndicator { const current = await this.tabPresenter.getCurrent(); const tabs = await this.tabPresenter.getByKeyword(keywords, false); if (tabs.length === 0) { - throw new RangeError('No matching buffer for ' + keywords); + throw new RangeError("No matching buffer for " + keywords); } for (const tab of tabs) { if (tab.index > current.index) { @@ -96,9 +96,9 @@ export default class CommandIndicator { const excludePinned = !force; const tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned); if (tabs.length === 0) { - throw new Error('No matching buffer for ' + keywords); + throw new Error("No matching buffer for " + keywords); } else if (tabs.length > 1) { - throw new Error('More than one match for ' + keywords); + throw new Error("More than one match for " + keywords); } return this.tabPresenter.remove([tabs[0].id as number]); } @@ -106,7 +106,7 @@ export default class CommandIndicator { async bdeletes(force: boolean, keywords: string): Promise<any> { const excludePinned = !force; const tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned); - const ids = tabs.map(tab => tab.id as number); + const ids = tabs.map((tab) => tab.id as number); return this.tabPresenter.remove(ids); } @@ -117,14 +117,14 @@ export default class CommandIndicator { async quitAll(): Promise<any> { const tabs = await this.tabPresenter.getAll(); - const ids = tabs.map(tab => tab.id as number); + const ids = tabs.map((tab) => tab.id as number); this.tabPresenter.remove(ids); } async addbookmark(title: string): Promise<any> { const tab = await this.tabPresenter.getCurrent(); const item = await this.bookmarkRepository.create(title, tab.url as string); - const message = 'Saved current page: ' + item.url; + const message = "Saved current page: " + item.url; return this.consoleClient.showInfo(tab.id as number, message); } diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts index 2de5bc1..195c70f 100644 --- a/src/background/usecases/ConsoleUseCase.ts +++ b/src/background/usecases/ConsoleUseCase.ts @@ -1,59 +1,57 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import ConsoleClient from '../infrastructures/ConsoleClient'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class ConsoleUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - private consoleClient: ConsoleClient, - ) { - } + @inject("TabPresenter") private tabPresenter: TabPresenter, + private consoleClient: ConsoleClient + ) {} async showCommand(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showCommand(tab.id as number, ''); + return this.consoleClient.showCommand(tab.id as number, ""); } async showOpenCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'open '; + let command = "open "; if (alter) { - command += tab.url || ''; + command += tab.url || ""; } return this.consoleClient.showCommand(tab.id as number, command); } async showTabopenCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'tabopen '; + let command = "tabopen "; if (alter) { - command += tab.url || ''; + command += tab.url || ""; } return this.consoleClient.showCommand(tab.id as number, command); } async showWinopenCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'winopen '; + let command = "winopen "; if (alter) { - command += tab.url || ''; + command += tab.url || ""; } return this.consoleClient.showCommand(tab.id as number, command); } async showBufferCommand(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - const command = 'buffer '; + const command = "buffer "; return this.consoleClient.showCommand(tab.id as number, command); } async showAddbookmarkCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'addbookmark '; + let command = "addbookmark "; if (alter) { - command += tab.title || ''; + command += tab.title || ""; } return this.consoleClient.showCommand(tab.id as number, command); } diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts index cb41cd5..facc461 100644 --- a/src/background/usecases/FindUseCase.ts +++ b/src/background/usecases/FindUseCase.ts @@ -1,16 +1,15 @@ -import { inject, injectable } from 'tsyringe'; -import FindRepository from '../repositories/FindRepository'; -import TabPresenter from '../presenters/TabPresenter'; -import ConsoleClient from '../infrastructures/ConsoleClient'; +import { inject, injectable } from "tsyringe"; +import FindRepository from "../repositories/FindRepository"; +import TabPresenter from "../presenters/TabPresenter"; +import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class FindUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private findRepository: FindRepository, - private consoleClient: ConsoleClient, - ) { - } + private consoleClient: ConsoleClient + ) {} getKeyword(): Promise<string> { return this.findRepository.getKeyword(); diff --git a/src/background/usecases/LinkUseCase.ts b/src/background/usecases/LinkUseCase.ts index be076c7..d2cd464 100644 --- a/src/background/usecases/LinkUseCase.ts +++ b/src/background/usecases/LinkUseCase.ts @@ -1,24 +1,23 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class LinkUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} openToTab(url: string, tabId: number): Promise<any> { return this.tabPresenter.open(url, tabId); } async openNewTab( - url: string, openerId: number, background: boolean, + url: string, + openerId: number, + background: boolean ): Promise<any> { const properties: any = { active: !background }; const platform = await browser.runtime.getPlatformInfo(); - if (platform.os !== 'android') { + if (platform.os !== "android") { // openerTabId not supported on Android properties.openerTabId = openerId; } diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts index 2c0bc13..9da9a21 100644 --- a/src/background/usecases/MarkUseCase.ts +++ b/src/background/usecases/MarkUseCase.ts @@ -1,18 +1,17 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import MarkRepository from '../repositories/MarkRepository'; -import ConsoleClient from '../infrastructures/ConsoleClient'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import MarkRepository from "../repositories/MarkRepository"; +import ConsoleClient from "../infrastructures/ConsoleClient"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; @injectable() export default class MarkUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private markRepository: MarkRepository, private consoleClient: ConsoleClient, - private contentMessageClient: ContentMessageClient, - ) { - } + private contentMessageClient: ContentMessageClient + ) {} async setGlobal(key: string, x: number, y: number): Promise<any> { const tab = await this.tabPresenter.getCurrent(); @@ -26,7 +25,9 @@ export default class MarkUseCase { const mark = await this.markRepository.getMark(key); if (!mark) { return this.consoleClient.showError( - current.id as number, 'Mark is not set'); + current.id as number, + "Mark is not set" + ); } try { await this.contentMessageClient.scrollTo(mark.tabId, mark.x, mark.y); @@ -34,7 +35,10 @@ export default class MarkUseCase { } catch (e) { const tab = await this.tabPresenter.create(mark.url); return this.markRepository.setMark(key, { - tabId: tab.id as number, url: mark.url, x: mark.x, y: mark.y, + tabId: tab.id as number, + url: mark.url, + x: mark.x, + y: mark.y, }); } } diff --git a/src/background/usecases/NavigateUseCase.ts b/src/background/usecases/NavigateUseCase.ts index 3aa1ed6..2e887e7 100644 --- a/src/background/usecases/NavigateUseCase.ts +++ b/src/background/usecases/NavigateUseCase.ts @@ -1,14 +1,13 @@ -import { inject, injectable } from 'tsyringe'; -import NavigateClient from '../clients/NavigateClient'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import NavigateClient from "../clients/NavigateClient"; +import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class NavigateUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - private navigateClient: NavigateClient, - ) { - } + @inject("TabPresenter") private tabPresenter: TabPresenter, + private navigateClient: NavigateClient + ) {} async openHistoryNext(): Promise<void> { const tab = await this.tabPresenter.getCurrent(); @@ -34,16 +33,16 @@ export default class NavigateUseCase { const tab = await this.tabPresenter.getCurrent(); const url = new URL(tab.url!!); if (url.hash.length > 0) { - url.hash = ''; + url.hash = ""; } else if (url.search.length > 0) { - url.search = ''; + url.search = ""; } else { const basenamePattern = /\/[^/]+$/; const lastDirPattern = /\/[^/]+\/$/; if (basenamePattern.test(url.pathname)) { - url.pathname = url.pathname.replace(basenamePattern, '/'); + url.pathname = url.pathname.replace(basenamePattern, "/"); } else if (lastDirPattern.test(url.pathname)) { - url.pathname = url.pathname.replace(lastDirPattern, '/'); + url.pathname = url.pathname.replace(lastDirPattern, "/"); } } await this.tabPresenter.open(url.href); diff --git a/src/background/usecases/RepeatUseCase.ts b/src/background/usecases/RepeatUseCase.ts index d78de34..d7235ee 100644 --- a/src/background/usecases/RepeatUseCase.ts +++ b/src/background/usecases/RepeatUseCase.ts @@ -1,15 +1,12 @@ -import { injectable } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import RepeatRepository from '../repositories/RepeatRepository'; +import { injectable } from "tsyringe"; +import * as operations from "../../shared/operations"; +import RepeatRepository from "../repositories/RepeatRepository"; type Operation = operations.Operation; @injectable() export default class RepeatUseCase { - constructor( - private repeatRepository: RepeatRepository, - ) { - } + constructor(private repeatRepository: RepeatRepository) {} storeLastOperation(op: Operation): void { this.repeatRepository.setLastOperation(op); @@ -22,28 +19,28 @@ export default class RepeatUseCase { // eslint-disable-next-line complexity isRepeatable(op: Operation): boolean { switch (op.type) { - case operations.NAVIGATE_HISTORY_PREV: - case operations.NAVIGATE_HISTORY_NEXT: - case operations.NAVIGATE_LINK_PREV: - case operations.NAVIGATE_LINK_NEXT: - case operations.NAVIGATE_PARENT: - case operations.NAVIGATE_ROOT: - case operations.PAGE_SOURCE: - case operations.PAGE_HOME: - case operations.TAB_CLOSE: - case operations.TAB_CLOSE_FORCE: - case operations.TAB_CLOSE_RIGHT: - case operations.TAB_REOPEN: - case operations.TAB_RELOAD: - case operations.TAB_PIN: - case operations.TAB_UNPIN: - case operations.TAB_TOGGLE_PINNED: - case operations.TAB_DUPLICATE: - case operations.ZOOM_IN: - case operations.ZOOM_OUT: - case operations.ZOOM_NEUTRAL: - case operations.INTERNAL_OPEN_URL: - return true; + case operations.NAVIGATE_HISTORY_PREV: + case operations.NAVIGATE_HISTORY_NEXT: + case operations.NAVIGATE_LINK_PREV: + case operations.NAVIGATE_LINK_NEXT: + case operations.NAVIGATE_PARENT: + case operations.NAVIGATE_ROOT: + case operations.PAGE_SOURCE: + case operations.PAGE_HOME: + case operations.TAB_CLOSE: + case operations.TAB_CLOSE_FORCE: + case operations.TAB_CLOSE_RIGHT: + case operations.TAB_REOPEN: + case operations.TAB_RELOAD: + case operations.TAB_PIN: + case operations.TAB_UNPIN: + case operations.TAB_TOGGLE_PINNED: + case operations.TAB_DUPLICATE: + case operations.ZOOM_IN: + case operations.ZOOM_OUT: + case operations.ZOOM_NEUTRAL: + case operations.INTERNAL_OPEN_URL: + return true; } return false; } diff --git a/src/background/usecases/SettingUseCase.ts b/src/background/usecases/SettingUseCase.ts index 69b4572..ccee227 100644 --- a/src/background/usecases/SettingUseCase.ts +++ b/src/background/usecases/SettingUseCase.ts @@ -1,20 +1,21 @@ -import {inject, injectable} from 'tsyringe'; -import CachedSettingRepository from '../repositories/CachedSettingRepository'; -import SettingData, {DefaultSettingData} from '../../shared/SettingData'; -import Settings from '../../shared/settings/Settings'; -import Notifier from '../presenters/Notifier'; +import { inject, injectable } from "tsyringe"; +import CachedSettingRepository from "../repositories/CachedSettingRepository"; +import SettingData, { DefaultSettingData } from "../../shared/SettingData"; +import Settings from "../../shared/settings/Settings"; +import Notifier from "../presenters/Notifier"; import SettingRepository from "../repositories/SettingRepository"; @injectable() export default class SettingUseCase { - constructor( - @inject("LocalSettingRepository") private localSettingRepository: SettingRepository, - @inject("SyncSettingRepository") private syncSettingRepository: SettingRepository, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, - @inject("Notifier") private notifier: Notifier, - ) { - } + @inject("LocalSettingRepository") + private localSettingRepository: SettingRepository, + @inject("SyncSettingRepository") + private syncSettingRepository: SettingRepository, + @inject("CachedSettingRepository") + private cachedSettingRepository: CachedSettingRepository, + @inject("Notifier") private notifier: Notifier + ) {} getCached(): Promise<Settings> { return this.cachedSettingRepository.get(); @@ -42,7 +43,7 @@ export default class SettingUseCase { private async loadSettings(): Promise<SettingData> { const sync = await this.syncSettingRepository.load(); if (sync) { - return sync; + return sync; } const local = await this.localSettingRepository.load(); if (local) { @@ -52,7 +53,7 @@ export default class SettingUseCase { } private showUnableToLoad(e: Error) { - console.error('unable to load settings', e); + console.error("unable to load settings", e); this.notifier.notifyInvalidSettings(() => { browser.runtime.openOptionsPage(); }); diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts index 271bb6c..663ceb8 100644 --- a/src/background/usecases/TabSelectUseCase.ts +++ b/src/background/usecases/TabSelectUseCase.ts @@ -1,19 +1,16 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class TabSelectUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} async selectPrev(count: number): Promise<any> { const tabs = await this.tabPresenter.getAll(); if (tabs.length < 2) { return; } - const tab = tabs.find(t => t.active); + const tab = tabs.find((t) => t.active); if (!tab) { return; } @@ -26,7 +23,7 @@ export default class TabSelectUseCase { if (tabs.length < 2) { return; } - const tab = tabs.find(t => t.active); + const tab = tabs.find((t) => t.active); if (!tab) { return; } @@ -46,7 +43,7 @@ export default class TabSelectUseCase { async selectPrevSelected(): Promise<any> { const tabId = await this.tabPresenter.getLastSelectedId(); - if (tabId === null || typeof tabId === 'undefined') { + if (tabId === null || typeof tabId === "undefined") { return Promise.resolve(); } return this.tabPresenter.select(tabId); diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts index 418dde5..1439107 100644 --- a/src/background/usecases/TabUseCase.ts +++ b/src/background/usecases/TabUseCase.ts @@ -1,16 +1,15 @@ -import {inject, injectable} from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import WindowPresenter from '../presenters/WindowPresenter'; -import BrowserSettingRepository from '../repositories/BrowserSettingRepository'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import WindowPresenter from "../presenters/WindowPresenter"; +import BrowserSettingRepository from "../repositories/BrowserSettingRepository"; @injectable() export default class TabUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private windowPresenter: WindowPresenter, - private browserSettingRepository: BrowserSettingRepository, - ) { - } + private browserSettingRepository: BrowserSettingRepository + ) {} async close(force: boolean, selectLeft = false): Promise<any> { const tab = await this.tabPresenter.getCurrent(); @@ -27,7 +26,7 @@ export default class TabUseCase { async closeRight(): Promise<any> { const tabs = await this.tabPresenter.getAll(); tabs.sort((t1, t2) => t1.index - t2.index); - const index = tabs.findIndex(t => t.active); + const index = tabs.findIndex((t) => t.active); if (index < 0) { return; } @@ -65,16 +64,18 @@ export default class TabUseCase { async openPageSource(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - const url = 'view-source:' + tab.url; + const url = "view-source:" + tab.url; return this.tabPresenter.create(url); } async openHome(newTab: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); const urls = await this.browserSettingRepository.getHomepageUrls(); - if (urls.length === 1 && urls[0] === 'about:home') { + if (urls.length === 1 && urls[0] === "about:home") { // eslint-disable-next-line max-len - throw new Error('Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs'); + throw new Error( + "Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs" + ); } if (urls.length === 1 && !newTab) { return this.tabPresenter.open(urls[0], tab.id); @@ -85,7 +86,9 @@ export default class TabUseCase { } async openURL( - url: string, newTab?: boolean, newWindow?: boolean, + url: string, + newTab?: boolean, + newWindow?: boolean ): Promise<void> { if (newWindow) { await this.windowPresenter.create(url); diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts index 21a5e2c..74df8a8 100644 --- a/src/background/usecases/VersionUseCase.ts +++ b/src/background/usecases/VersionUseCase.ts @@ -1,14 +1,13 @@ -import { injectable, inject } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import Notifier from '../presenters/Notifier'; +import { injectable, inject } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import Notifier from "../presenters/Notifier"; @injectable() export default class VersionUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - @inject("Notifier") private notifier: Notifier, - ) { - } + @inject("TabPresenter") private tabPresenter: TabPresenter, + @inject("Notifier") private notifier: Notifier + ) {} notify(): Promise<void> { const manifest = browser.runtime.getManifest(); @@ -22,6 +21,6 @@ export default class VersionUseCase { if (version) { return `https://github.com/ueokande/vim-vixen/releases/tag/${version}`; } - return 'https://github.com/ueokande/vim-vixen/releases/'; + return "https://github.com/ueokande/vim-vixen/releases/"; } } diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts index ca1368d..173e4d7 100644 --- a/src/background/usecases/ZoomUseCase.ts +++ b/src/background/usecases/ZoomUseCase.ts @@ -1,23 +1,32 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; const ZOOM_SETTINGS: number[] = [ - 0.33, 0.50, 0.66, 0.75, 0.80, 0.90, 1.00, - 1.10, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00 + 0.33, + 0.5, + 0.66, + 0.75, + 0.8, + 0.9, + 1.0, + 1.1, + 1.25, + 1.5, + 1.75, + 2.0, + 2.5, + 3.0, ]; @injectable() export default class ZoomUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} async zoomIn(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); const tabId = tab.id as number; const current = await this.tabPresenter.getZoom(tabId); - const factor = ZOOM_SETTINGS.find(f => f > current); + const factor = ZOOM_SETTINGS.find((f) => f > current); if (factor) { return this.tabPresenter.setZoom(tabId as number, factor); } @@ -27,7 +36,9 @@ export default class ZoomUseCase { const tab = await this.tabPresenter.getCurrent(); const tabId = tab.id as number; const current = await this.tabPresenter.getZoom(tabId); - const factor = ZOOM_SETTINGS.slice(0).reverse().find(f => f < current); + const factor = ZOOM_SETTINGS.slice(0) + .reverse() + .find((f) => f < current); if (factor) { return this.tabPresenter.setZoom(tabId as number, factor); } diff --git a/src/background/usecases/parsers.ts b/src/background/usecases/parsers.ts index 99ff2eb..23a6193 100644 --- a/src/background/usecases/parsers.ts +++ b/src/background/usecases/parsers.ts @@ -1,36 +1,39 @@ -import Properties from '../../shared/settings/Properties'; +import Properties from "../../shared/settings/Properties"; const mustNumber = (v: any): number => { const num = Number(v); if (isNaN(num)) { - throw new Error('Not number: ' + v); + throw new Error("Not number: " + v); } return num; }; -const parseSetOption = ( - args: string, -): any[] => { - let [key, value]: any[] = args.split('='); +const parseSetOption = (args: string): any[] => { + let [key, value]: any[] = args.split("="); if (value === undefined) { - value = !key.startsWith('no'); + value = !key.startsWith("no"); key = value ? key : key.slice(2); } const def = Properties.def(key); if (!def) { - throw new Error('Unknown property: ' + key); + throw new Error("Unknown property: " + key); } - if (def.type === 'boolean' && typeof value !== 'boolean' || - def.type !== 'boolean' && typeof value === 'boolean') { - throw new Error('Invalid argument: ' + args); + if ( + (def.type === "boolean" && typeof value !== "boolean") || + (def.type !== "boolean" && typeof value === "boolean") + ) { + throw new Error("Invalid argument: " + args); } switch (def.type) { - case 'string': return [key, value]; - case 'number': return [key, mustNumber(value)]; - case 'boolean': return [key, value]; - default: - throw new Error('Unknown property type: ' + def.type); + case "string": + return [key, value]; + case "number": + return [key, mustNumber(value)]; + case "boolean": + return [key, value]; + default: + throw new Error("Unknown property type: " + def.type); } }; diff --git a/src/console/Completions.ts b/src/console/Completions.ts index ec9135f..a18f160 100644 --- a/src/console/Completions.ts +++ b/src/console/Completions.ts @@ -1,11 +1,11 @@ type Completions = { - readonly name: string; - readonly items: { - readonly caption?: string; - readonly content?: string; - readonly url?: string; - readonly icon?: string; - }[]; -}[] + readonly name: string; + readonly items: { + readonly caption?: string; + readonly content?: string; + readonly url?: string; + readonly icon?: string; + }[]; +}[]; -export default Completions;
\ No newline at end of file +export default Completions; diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts index e44c974..205676b 100644 --- a/src/console/actions/console.ts +++ b/src/console/actions/console.ts @@ -1,6 +1,6 @@ -import * as messages from '../../shared/messages'; -import * as actions from './index'; -import {Command} from "../../shared/Command"; +import * as messages from "../../shared/messages"; +import * as actions from "./index"; +import { Command } from "../../shared/Command"; import CompletionClient from "../clients/CompletionClient"; import CompletionType from "../../shared/CompletionType"; import Completions from "../Completions"; @@ -9,23 +9,23 @@ import TabFlag from "../../shared/TabFlag"; const completionClient = new CompletionClient(); const commandDocs = { - [Command.Set]: 'Set a value of the property', - [Command.Open]: 'Open a URL or search by keywords in current tab', - [Command.TabOpen]: 'Open a URL or search by keywords in new tab', - [Command.WindowOpen]: 'Open a URL or search by keywords in new window', - [Command.Buffer]: 'Select tabs by matched keywords', - [Command.BufferDelete]: 'Close a certain tab matched by keywords', - [Command.BuffersDelete]: 'Close all tabs matched by keywords', - [Command.Quit]: 'Close the current tab', - [Command.QuitAll]: 'Close all tabs', - [Command.AddBookmark]: 'Add current page to bookmarks', - [Command.Help]: 'Open Vim Vixen help in new tab', + [Command.Set]: "Set a value of the property", + [Command.Open]: "Open a URL or search by keywords in current tab", + [Command.TabOpen]: "Open a URL or search by keywords in new tab", + [Command.WindowOpen]: "Open a URL or search by keywords in new window", + [Command.Buffer]: "Select tabs by matched keywords", + [Command.BufferDelete]: "Close a certain tab matched by keywords", + [Command.BuffersDelete]: "Close all tabs matched by keywords", + [Command.Quit]: "Close the current tab", + [Command.QuitAll]: "Close all tabs", + [Command.AddBookmark]: "Add current page to bookmarks", + [Command.Help]: "Open Vim Vixen help in new tab", }; -const propertyDocs: {[key: string]: string} = { - 'hintchars': 'hint characters on follow mode', - 'smoothscroll': 'smooth scroll', - 'complete': 'which are completed at the open page', +const propertyDocs: { [key: string]: string } = { + hintchars: "hint characters on follow mode", + smoothscroll: "smooth scroll", + complete: "which are completed at the open page", }; const hide = (): actions.ConsoleAction => { @@ -52,27 +52,32 @@ const showFind = (): actions.ShowFindAction => { const showError = (text: string): actions.ShowErrorAction => { return { type: actions.CONSOLE_SHOW_ERROR, - text: text + text: text, }; }; const showInfo = (text: string): actions.ShowInfoAction => { return { type: actions.CONSOLE_SHOW_INFO, - text: text + text: text, }; }; const hideCommand = (): actions.HideCommandAction => { - window.top.postMessage(JSON.stringify({ - type: messages.CONSOLE_UNFOCUS, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.CONSOLE_UNFOCUS, + }), + "*" + ); return { type: actions.CONSOLE_HIDE_COMMAND, }; }; -const enterCommand = async(text: string): Promise<actions.HideCommandAction> => { +const enterCommand = async ( + text: string +): Promise<actions.HideCommandAction> => { await browser.runtime.sendMessage({ type: messages.CONSOLE_ENTER_COMMAND, text, @@ -81,10 +86,13 @@ const enterCommand = async(text: string): Promise<actions.HideCommandAction> => }; const enterFind = (text?: string): actions.HideCommandAction => { - window.top.postMessage(JSON.stringify({ - type: messages.CONSOLE_ENTER_FIND, - text, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.CONSOLE_ENTER_FIND, + text, + }), + "*" + ); return hideCommand(); }; @@ -97,25 +105,30 @@ const setConsoleText = (consoleText: string): actions.SetConsoleTextAction => { const getCommandCompletions = (text: string): actions.SetCompletionsAction => { const items = Object.entries(commandDocs) - .filter(([name]) => name.startsWith(text.trimLeft())) - .map(([name, doc]) => ({ - caption: name, - content: name, - url: doc, - })); - const completions = [{ - name: "Console Command", - items, - }]; + .filter(([name]) => name.startsWith(text.trimLeft())) + .map(([name, doc]) => ({ + caption: name, + content: name, + url: doc, + })); + const completions = [ + { + name: "Console Command", + items, + }, + ]; return { type: actions.CONSOLE_SET_COMPLETIONS, completions, completionSource: text, - } + }; }; -const getOpenCompletions = async( - types: CompletionType[], original: string, command: Command, query: string, +const getOpenCompletions = async ( + types: CompletionType[], + original: string, + command: Command, + query: string ): Promise<actions.SetCompletionsAction> => { const completions: Completions = []; for (const type of types) { @@ -126,11 +139,11 @@ const getOpenCompletions = async( break; } completions.push({ - name: 'Search Engines', - items: items.map(key => ({ + name: "Search Engines", + items: items.map((key) => ({ caption: key.title, - content: command + ' ' + key.title, - })) + content: command + " " + key.title, + })), }); break; } @@ -140,11 +153,11 @@ const getOpenCompletions = async( break; } completions.push({ - name: 'History', - items: items.map(item => ({ + name: "History", + items: items.map((item) => ({ caption: item.title, - content: command + ' ' + item.url, - url: item.url + content: command + " " + item.url, + url: item.url, })), }); break; @@ -155,12 +168,12 @@ const getOpenCompletions = async( break; } completions.push({ - name: 'Bookmarks', - items: items.map(item => ({ + name: "Bookmarks", + items: items.map((item) => ({ caption: item.title, - content: command + ' ' + item.url, - url: item.url - })) + content: command + " " + item.url, + url: item.url, + })), }); break; } @@ -175,61 +188,75 @@ const getOpenCompletions = async( }; const getTabCompletions = async ( - original: string, command: Command, query: string, excludePinned: boolean, + original: string, + command: Command, + query: string, + excludePinned: boolean ): Promise<actions.SetCompletionsAction> => { - const items = await completionClient.requestTabs(query, excludePinned); - let completions: Completions = []; - if (items.length > 0) { - completions = [{ - name: 'Buffers', - items: items.map(item => ({ - content: command + ' ' + item.url, - caption: `${item.index}: ${item.flag != TabFlag.None ? item.flag : ' ' } ${item.title}`, + const items = await completionClient.requestTabs(query, excludePinned); + let completions: Completions = []; + if (items.length > 0) { + completions = [ + { + name: "Buffers", + items: items.map((item) => ({ + content: command + " " + item.url, + caption: `${item.index}: ${ + item.flag != TabFlag.None ? item.flag : " " + } ${item.title}`, url: item.url, icon: item.faviconUrl, })), - }]; - } - return { - type: actions.CONSOLE_SET_COMPLETIONS, - completions, - completionSource: original, - } + }, + ]; + } + return { + type: actions.CONSOLE_SET_COMPLETIONS, + completions, + completionSource: original, + }; }; -const getPropertyCompletions = async( - original: string, command: Command, query: string, +const getPropertyCompletions = async ( + original: string, + command: Command, + query: string ): Promise<actions.SetCompletionsAction> => { const properties = await completionClient.getProperties(); const items = properties - .map(item => { - const desc = propertyDocs[item.name] || ''; - if (item.type === 'boolean') { - return [{ + .map((item) => { + const desc = propertyDocs[item.name] || ""; + if (item.type === "boolean") { + return [ + { caption: item.name, - content: command + ' ' + item.name, - url: 'Enable ' + desc, - }, { - caption: 'no' + item.name, - content: command + ' no' + item.name, - url: 'Disable ' + desc, - }]; - } else { - return [{ + content: command + " " + item.name, + url: "Enable " + desc, + }, + { + caption: "no" + item.name, + content: command + " no" + item.name, + url: "Disable " + desc, + }, + ]; + } else { + return [ + { caption: item.name, - content: name + ' ' + item.name, - url: 'Set ' + desc, - }]; - } - }) - .reduce((acc, val) => acc.concat(val), []) - .filter(item => item.caption.startsWith(query)); - const completions: Completions = [{ name: 'Properties', items }]; + content: name + " " + item.name, + url: "Set " + desc, + }, + ]; + } + }) + .reduce((acc, val) => acc.concat(val), []) + .filter((item) => item.caption.startsWith(query)); + const completions: Completions = [{ name: "Properties", items }]; return { type: actions.CONSOLE_SET_COMPLETIONS, completions, completionSource: original, - } + }; }; const completionNext = (): actions.CompletionNextAction => { @@ -245,7 +272,19 @@ const completionPrev = (): actions.CompletionPrevAction => { }; export { - hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText, enterCommand, enterFind, - getCommandCompletions, getOpenCompletions, getTabCompletions, getPropertyCompletions, - completionNext, completionPrev, + hide, + showCommand, + showFind, + showError, + showInfo, + hideCommand, + setConsoleText, + enterCommand, + enterFind, + getCommandCompletions, + getOpenCompletions, + getTabCompletions, + getPropertyCompletions, + completionNext, + completionPrev, }; diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts index e292608..308a093 100644 --- a/src/console/actions/index.ts +++ b/src/console/actions/index.ts @@ -1,16 +1,16 @@ import Completions from "../Completions"; import CompletionType from "../../shared/CompletionType"; -export const CONSOLE_HIDE = 'console.hide'; -export const CONSOLE_SHOW_COMMAND = 'console.show.command'; -export const CONSOLE_SHOW_ERROR = 'console.show.error'; -export const CONSOLE_SHOW_INFO = 'console.show.info'; -export const CONSOLE_HIDE_COMMAND = 'console.hide.command'; -export const CONSOLE_SET_CONSOLE_TEXT = 'console.set.command'; -export const CONSOLE_SET_COMPLETIONS = 'console.set.completions'; -export const CONSOLE_COMPLETION_NEXT = 'console.completion.next'; -export const CONSOLE_COMPLETION_PREV = 'console.completion.prev'; -export const CONSOLE_SHOW_FIND = 'console.show.find'; +export const CONSOLE_HIDE = "console.hide"; +export const CONSOLE_SHOW_COMMAND = "console.show.command"; +export const CONSOLE_SHOW_ERROR = "console.show.error"; +export const CONSOLE_SHOW_INFO = "console.show.info"; +export const CONSOLE_HIDE_COMMAND = "console.hide.command"; +export const CONSOLE_SET_CONSOLE_TEXT = "console.set.command"; +export const CONSOLE_SET_COMPLETIONS = "console.set.completions"; +export const CONSOLE_COMPLETION_NEXT = "console.completion.next"; +export const CONSOLE_COMPLETION_PREV = "console.completion.prev"; +export const CONSOLE_SHOW_FIND = "console.show.find"; export interface HideAction { type: typeof CONSOLE_HIDE; @@ -60,7 +60,13 @@ export interface CompletionPrevAction { } export type ConsoleAction = - HideAction | ShowCommand | ShowFindAction | ShowErrorAction | - ShowInfoAction | HideCommandAction | SetConsoleTextAction | - SetCompletionsAction | CompletionNextAction | CompletionPrevAction; - + | HideAction + | ShowCommand + | ShowFindAction + | ShowErrorAction + | ShowInfoAction + | HideCommandAction + | SetConsoleTextAction + | SetCompletionsAction + | CompletionNextAction + | CompletionPrevAction; diff --git a/src/console/clients/CompletionClient.ts b/src/console/clients/CompletionClient.ts index 56dc665..64119e8 100644 --- a/src/console/clients/CompletionClient.ts +++ b/src/console/clients/CompletionClient.ts @@ -1,84 +1,87 @@ import * as messages from "../../shared/messages"; import { - ConsoleGetCompletionTypesResponse, ConsoleGetPropertiesResponse, + ConsoleGetCompletionTypesResponse, + ConsoleGetPropertiesResponse, ConsoleRequestBookmarksResponse, - ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse, ConsoleRequesttabsResponse + ConsoleRequestHistoryResponse, + ConsoleRequestSearchEnginesResponse, + ConsoleRequesttabsResponse, } from "../../shared/messages"; import CompletionType from "../../shared/CompletionType"; import TabFlag from "../../shared/TabFlag"; export type SearchEngines = { - title: string -} + title: string; +}; export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export type HistoryItem = { - title: string - url: string -} + title: string; + url: string; +}; export type TabItem = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -} + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}; export type Property = { - name: string - type: 'string' | 'boolean' | 'number'; -} + name: string; + type: "string" | "boolean" | "number"; +}; export default class CompletionClient { async getCompletionTypes(): Promise<CompletionType[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_GET_COMPLETION_TYPES, - }) as ConsoleGetCompletionTypesResponse; + })) as ConsoleGetCompletionTypesResponse; return resp; } async requestSearchEngines(query: string): Promise<SearchEngines[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE, query, - }) as ConsoleRequestSearchEnginesResponse; + })) as ConsoleRequestSearchEnginesResponse; return resp; } async requestBookmarks(query: string): Promise<BookmarkItem[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_BOOKMARKS, query, - }) as ConsoleRequestBookmarksResponse; + })) as ConsoleRequestBookmarksResponse; return resp; } async requestHistory(query: string): Promise<HistoryItem[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_HISTORY, query, - }) as ConsoleRequestHistoryResponse; + })) as ConsoleRequestHistoryResponse; return resp; } async requestTabs(query: string, excludePinned: boolean): Promise<TabItem[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_TABS, query, excludePinned, - }) as ConsoleRequesttabsResponse; + })) as ConsoleRequesttabsResponse; return resp; } async getProperties(): Promise<Property[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_GET_PROPERTIES, - }) as ConsoleGetPropertiesResponse; + })) as ConsoleGetPropertiesResponse; return resp; } } diff --git a/src/console/commandline/CommandLineParser.ts b/src/console/commandline/CommandLineParser.ts index a166f49..ffff375 100644 --- a/src/console/commandline/CommandLineParser.ts +++ b/src/console/commandline/CommandLineParser.ts @@ -2,9 +2,9 @@ import CommandParser from "./CommandParser"; import { Command } from "../../shared/Command"; export type CommandLine = { - readonly command: Command, - readonly args: string -} + readonly command: Command; + readonly args: string; +}; export enum InputPhase { OnCommand, @@ -17,11 +17,11 @@ export default class CommandLineParser { inputPhase(line: string): InputPhase { line = line.trimLeft(); if (line.length == 0) { - return InputPhase.OnCommand + return InputPhase.OnCommand; } const command = line.split(/\s+/, 1)[0]; if (line.length == command.length) { - return InputPhase.OnCommand + return InputPhase.OnCommand; } return InputPhase.OnArgs; } @@ -33,6 +33,6 @@ export default class CommandLineParser { return { command: this.commandParser.parse(command), args: args, - } + }; } } diff --git a/src/console/commandline/CommandParser.ts b/src/console/commandline/CommandParser.ts index 5228c77..7488cbc 100644 --- a/src/console/commandline/CommandParser.ts +++ b/src/console/commandline/CommandParser.ts @@ -9,43 +9,43 @@ export class UnknownCommandError extends Error { export default class CommandParser { parse(value: string): Command { switch (value) { - case 'o': - case 'open': - return Command.Open; - case 't': - case 'tabopen': - return Command.TabOpen; - case 'w': - case 'winopen': - return Command.WindowOpen; - case 'b': - case 'buffer': - return Command.Buffer; - case 'bd': - case 'bdel': - case 'bdelete': - return Command.BufferDelete; - case 'bd!': - case 'bdel!': - case 'bdelete!': - return Command.BufferDeleteForce; - case 'bdeletes': - return Command.BuffersDelete; - case 'bdeletes!': - return Command.BuffersDeleteForce; - case 'addbookmark': - return Command.AddBookmark; - case 'q': - case 'quit': - return Command.Quit; - case 'qa': - case 'quitall': - return Command.QuitAll; - case 'set': - return Command.Set; - case 'h': - case 'help': - return Command.Help; + case "o": + case "open": + return Command.Open; + case "t": + case "tabopen": + return Command.TabOpen; + case "w": + case "winopen": + return Command.WindowOpen; + case "b": + case "buffer": + return Command.Buffer; + case "bd": + case "bdel": + case "bdelete": + return Command.BufferDelete; + case "bd!": + case "bdel!": + case "bdelete!": + return Command.BufferDeleteForce; + case "bdeletes": + return Command.BuffersDelete; + case "bdeletes!": + return Command.BuffersDeleteForce; + case "addbookmark": + return Command.AddBookmark; + case "q": + case "quit": + return Command.Quit; + case "qa": + case "quitall": + return Command.QuitAll; + case "set": + return Command.Set; + case "h": + case "help": + return Command.Help; } throw new UnknownCommandError(value); } diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx index 3fe5cee..d74040d 100644 --- a/src/console/components/Console.tsx +++ b/src/console/components/Console.tsx @@ -1,19 +1,21 @@ -import './console.scss'; -import { connect } from 'react-redux'; -import React from 'react'; -import Input from './console/Input'; -import Completion from './console/Completion'; -import Message from './console/Message'; -import * as consoleActions from '../../console/actions/console'; -import { State as AppState } from '../reducers'; -import CommandLineParser, { InputPhase } from "../commandline/CommandLineParser"; +import "./console.scss"; +import { connect } from "react-redux"; +import React from "react"; +import Input from "./console/Input"; +import Completion from "./console/Completion"; +import Message from "./console/Message"; +import * as consoleActions from "../../console/actions/console"; +import { State as AppState } from "../reducers"; +import CommandLineParser, { + InputPhase, +} from "../commandline/CommandLineParser"; import { Command } from "../../shared/Command"; const COMPLETION_MAX_ITEMS = 33; type StateProps = ReturnType<typeof mapStateToProps>; interface DispatchProps { - dispatch: (action: any) => void, + dispatch: (action: any) => void; } type Props = StateProps & DispatchProps; @@ -29,7 +31,7 @@ class Console extends React.Component<Props> { } onBlur() { - if (this.props.mode === 'command' || this.props.mode === 'find') { + if (this.props.mode === "command" || this.props.mode === "find") { return this.props.dispatch(consoleActions.hideCommand()); } } @@ -39,11 +41,12 @@ class Console extends React.Component<Props> { e.preventDefault(); const value = (e.target as HTMLInputElement).value; - if (this.props.mode === 'command') { + if (this.props.mode === "command") { return this.props.dispatch(consoleActions.enterCommand(value)); - } else if (this.props.mode === 'find') { - return this.props.dispatch(consoleActions.enterFind( - value === '' ? undefined : value)); + } else if (this.props.mode === "find") { + return this.props.dispatch( + consoleActions.enterFind(value === "" ? undefined : value) + ); } } @@ -61,94 +64,95 @@ class Console extends React.Component<Props> { onKeyDown(e: React.KeyboardEvent<HTMLInputElement>) { switch (e.key) { - case 'Escape': - return this.props.dispatch(consoleActions.hideCommand()); - case 'Enter': - return this.doEnter(e); - case 'Tab': - if (e.shiftKey) { - this.props.dispatch(consoleActions.completionPrev()); - } else { - this.props.dispatch(consoleActions.completionNext()); - } - e.stopPropagation(); - e.preventDefault(); - break; - case '[': - if (e.ctrlKey) { - e.preventDefault(); - return this.props.dispatch(consoleActions.hideCommand()); - } - break; - case 'c': - if (e.ctrlKey) { - e.preventDefault(); + case "Escape": return this.props.dispatch(consoleActions.hideCommand()); - } - break; - case 'm': - if (e.ctrlKey) { + case "Enter": return this.doEnter(e); - } - break; - case 'n': - if (e.ctrlKey) { - this.selectNext(e); - } - break; - case 'p': - if (e.ctrlKey) { - this.selectPrev(e); - } - break; + case "Tab": + if (e.shiftKey) { + this.props.dispatch(consoleActions.completionPrev()); + } else { + this.props.dispatch(consoleActions.completionNext()); + } + e.stopPropagation(); + e.preventDefault(); + break; + case "[": + if (e.ctrlKey) { + e.preventDefault(); + return this.props.dispatch(consoleActions.hideCommand()); + } + break; + case "c": + if (e.ctrlKey) { + e.preventDefault(); + return this.props.dispatch(consoleActions.hideCommand()); + } + break; + case "m": + if (e.ctrlKey) { + return this.doEnter(e); + } + break; + case "n": + if (e.ctrlKey) { + this.selectNext(e); + } + break; + case "p": + if (e.ctrlKey) { + this.selectPrev(e); + } + break; } } onChange(e: React.ChangeEvent<HTMLInputElement>) { const text = e.target.value; this.props.dispatch(consoleActions.setConsoleText(text)); - if (this.props.mode !== 'command') { - return + if (this.props.mode !== "command") { + return; } - this.updateCompletions(text) + this.updateCompletions(text); } - componentDidUpdate(prevProps: Props) { - if (prevProps.mode !== 'command' && this.props.mode === 'command') { + if (prevProps.mode !== "command" && this.props.mode === "command") { this.updateCompletions(this.props.consoleText); this.focus(); - } else if (prevProps.mode !== 'find' && this.props.mode === 'find') { + } else if (prevProps.mode !== "find" && this.props.mode === "find") { this.focus(); } } render() { switch (this.props.mode) { - case 'command': - case 'find': - return <div className='vimvixen-console-command-wrapper'> - <Completion - size={COMPLETION_MAX_ITEMS} - completions={this.props.completions} - select={this.props.select} - /> - <Input - ref={this.input} - mode={this.props.mode} - onBlur={this.onBlur.bind(this)} - onKeyDown={this.onKeyDown.bind(this)} - onChange={this.onChange.bind(this)} - value={this.props.consoleText} - /> - </div>; - case 'info': - case 'error': - return <Message mode={ this.props.mode } > - { this.props.messageText } - </Message>; - default: - return null; + case "command": + case "find": + return ( + <div className="vimvixen-console-command-wrapper"> + <Completion + size={COMPLETION_MAX_ITEMS} + completions={this.props.completions} + select={this.props.select} + /> + <Input + ref={this.input} + mode={this.props.mode} + onBlur={this.onBlur.bind(this)} + onKeyDown={this.onKeyDown.bind(this)} + onChange={this.onChange.bind(this)} + value={this.props.consoleText} + /> + </div> + ); + case "info": + case "error": + return ( + <Message mode={this.props.mode}>{this.props.messageText}</Message> + ); + default: + return null; } } @@ -166,25 +170,40 @@ class Console extends React.Component<Props> { } else { const cmd = this.commandLineParser.parse(text); switch (cmd.command) { - case Command.Open: - case Command.TabOpen: - case Command.WindowOpen: - this.props.dispatch(consoleActions.getOpenCompletions(this.props.completionTypes, text, cmd.command, cmd.args)); - break; - case Command.Buffer: - this.props.dispatch(consoleActions.getTabCompletions(text, cmd.command, cmd.args, false)); - break; - case Command.BufferDelete: - case Command.BuffersDelete: - this.props.dispatch(consoleActions.getTabCompletions(text, cmd.command, cmd.args, true)); - break; - case Command.BufferDeleteForce: - case Command.BuffersDeleteForce: - this.props.dispatch(consoleActions.getTabCompletions(text, cmd.command, cmd.args, false)); - break; - case Command.Set: - this.props.dispatch(consoleActions.getPropertyCompletions(text, cmd.command, cmd.args)); - break; + case Command.Open: + case Command.TabOpen: + case Command.WindowOpen: + this.props.dispatch( + consoleActions.getOpenCompletions( + this.props.completionTypes, + text, + cmd.command, + cmd.args + ) + ); + break; + case Command.Buffer: + this.props.dispatch( + consoleActions.getTabCompletions(text, cmd.command, cmd.args, false) + ); + break; + case Command.BufferDelete: + case Command.BuffersDelete: + this.props.dispatch( + consoleActions.getTabCompletions(text, cmd.command, cmd.args, true) + ); + break; + case Command.BufferDeleteForce: + case Command.BuffersDeleteForce: + this.props.dispatch( + consoleActions.getTabCompletions(text, cmd.command, cmd.args, false) + ); + break; + case Command.Set: + this.props.dispatch( + consoleActions.getPropertyCompletions(text, cmd.command, cmd.args) + ); + break; } } } @@ -192,6 +211,4 @@ class Console extends React.Component<Props> { const mapStateToProps = (state: AppState) => ({ ...state }); -export default connect( - mapStateToProps, -)(Console); +export default connect(mapStateToProps)(Console); diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx index e2fa1de..9b4cf15 100644 --- a/src/console/components/console/Completion.tsx +++ b/src/console/components/console/Completion.tsx @@ -1,6 +1,6 @@ -import React from 'react'; -import CompletionItem from './CompletionItem'; -import CompletionTitle from './CompletionTitle'; +import React from "react"; +import CompletionItem from "./CompletionItem"; +import CompletionTitle from "./CompletionTitle"; interface Item { icon?: string; @@ -52,8 +52,10 @@ class Completion extends React.Component<Props, State> { if (nextProps.select < 0) { viewOffset = 0; } else if (prevState.select < nextProps.select) { - viewOffset = Math.max(prevState.viewOffset, - viewSelect - nextProps.size + 1); + viewOffset = Math.max( + prevState.viewOffset, + viewSelect - nextProps.size + 1 + ); } else if (prevState.select > nextProps.select) { viewOffset = Math.min(prevState.viewOffset, viewSelect); } @@ -65,18 +67,17 @@ class Completion extends React.Component<Props, State> { let index = 0; for (const group of this.props.completions) { - eles.push(<CompletionTitle - key={`group-${index}`} - title={ group.name } - />); + eles.push(<CompletionTitle key={`group-${index}`} title={group.name} />); for (const item of group.items) { - eles.push(<CompletionItem - key={`item-${index}`} - icon={item.icon} - caption={item.caption} - url={item.url} - highlight={index === this.props.select} - / >); + eles.push( + <CompletionItem + key={`item-${index}`} + icon={item.icon} + caption={item.caption} + url={item.url} + highlight={index === this.props.select} + /> + ); ++index; } } @@ -84,11 +85,7 @@ class Completion extends React.Component<Props, State> { const viewOffset = this.state.viewOffset; eles = eles.slice(viewOffset, viewOffset + this.props.size); - return ( - <ul className='vimvixen-console-completion'> - { eles } - </ul> - ); + return <ul className="vimvixen-console-completion">{eles}</ul>; } } diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx index 1cbf3de..657f360 100644 --- a/src/console/components/console/CompletionItem.tsx +++ b/src/console/components/console/CompletionItem.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; interface Props { highlight: boolean; @@ -9,21 +9,21 @@ interface Props { } const CompletionItem = (props: Props) => { - let className = 'vimvixen-console-completion-item'; + let className = "vimvixen-console-completion-item"; if (props.highlight) { - className += ' vimvixen-completion-selected'; + className += " vimvixen-completion-selected"; } - return <li - className={className} - style={{ backgroundImage: 'url(' + props.icon + ')' }} - > - <span - className='vimvixen-console-completion-item-caption' - >{props.caption}</span> - <span - className='vimvixen-console-completion-item-url' - >{props.url}</span> - </li>; + return ( + <li + className={className} + style={{ backgroundImage: "url(" + props.icon + ")" }} + > + <span className="vimvixen-console-completion-item-caption"> + {props.caption} + </span> + <span className="vimvixen-console-completion-item-url">{props.url}</span> + </li> + ); }; CompletionItem.propTypes = { diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx index 2543619..7257006 100644 --- a/src/console/components/console/CompletionTitle.tsx +++ b/src/console/components/console/CompletionTitle.tsx @@ -1,13 +1,11 @@ -import React from 'react'; +import React from "react"; interface Props { title: string; } const CompletionTitle = (props: Props) => { - return <li className='vimvixen-console-completion-title'> - {props.title} - </li>; + return <li className="vimvixen-console-completion-title">{props.title}</li>; }; export default CompletionTitle; diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx index 54ea251..e412a0c 100644 --- a/src/console/components/console/Input.tsx +++ b/src/console/components/console/Input.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; interface Props { mode: string; @@ -24,20 +24,18 @@ class Input extends React.Component<Props> { } render() { - let prompt = ''; - if (this.props.mode === 'command') { - prompt = ':'; - } else if (this.props.mode === 'find') { - prompt = '/'; + let prompt = ""; + if (this.props.mode === "command") { + prompt = ":"; + } else if (this.props.mode === "find") { + prompt = "/"; } return ( - <div className='vimvixen-console-command'> - <i className='vimvixen-console-command-prompt'> - { prompt } - </i> + <div className="vimvixen-console-command"> + <i className="vimvixen-console-command-prompt">{prompt}</i> <input - className='vimvixen-console-command-input' + className="vimvixen-console-command-input" ref={this.input} onBlur={this.props.onBlur} onKeyDown={this.props.onKeyDown} diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx index 9fa2788..fd1c9d7 100644 --- a/src/console/components/console/Message.tsx +++ b/src/console/components/console/Message.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; interface Props { mode: string; @@ -7,18 +7,18 @@ interface Props { const Message = (props: Props) => { switch (props.mode) { - case 'error': - return ( - <p className='vimvixen-console-message vimvixen-console-error'> - { props.children } - </p> - ); - case 'info': - return ( - <p className='vimvixen-console-message vimvixen-console-info'> - { props.children } - </p> - ); + case "error": + return ( + <p className="vimvixen-console-message vimvixen-console-error"> + {props.children} + </p> + ); + case "info": + return ( + <p className="vimvixen-console-message vimvixen-console-info"> + {props.children} + </p> + ); } return null; }; diff --git a/src/console/index.tsx b/src/console/index.tsx index 7bee746..e1a9dd3 100644 --- a/src/console/index.tsx +++ b/src/console/index.tsx @@ -1,43 +1,41 @@ -import * as messages from '../shared/messages'; -import reducers from './reducers'; -import { createStore, applyMiddleware } from 'redux'; -import promise from 'redux-promise'; -import * as consoleActions from './actions/console'; -import { Provider } from 'react-redux'; -import Console from './components/Console'; -import React from 'react'; -import ReactDOM from 'react-dom'; +import * as messages from "../shared/messages"; +import reducers from "./reducers"; +import { createStore, applyMiddleware } from "redux"; +import promise from "redux-promise"; +import * as consoleActions from "./actions/console"; +import { Provider } from "react-redux"; +import Console from "./components/Console"; +import React from "react"; +import ReactDOM from "react-dom"; -const store = createStore( - reducers, - applyMiddleware(promise), -); +const store = createStore(reducers, applyMiddleware(promise)); -window.addEventListener('load', () => { - const wrapper = document.getElementById('vimvixen-console'); +window.addEventListener("load", () => { + const wrapper = document.getElementById("vimvixen-console"); ReactDOM.render( - <Provider store={store} > + <Provider store={store}> <Console></Console> </Provider>, - wrapper); + wrapper + ); }); const onMessage = async (message: any): Promise<any> => { const msg = messages.valueOf(message); switch (msg.type) { - case messages.CONSOLE_SHOW_COMMAND: - return store.dispatch(await consoleActions.showCommand(msg.command)); - case messages.CONSOLE_SHOW_FIND: - return store.dispatch(consoleActions.showFind()); - case messages.CONSOLE_SHOW_ERROR: - return store.dispatch(consoleActions.showError(msg.text)); - case messages.CONSOLE_SHOW_INFO: - return store.dispatch(consoleActions.showInfo(msg.text)); - case messages.CONSOLE_HIDE: - return store.dispatch(consoleActions.hide()); + case messages.CONSOLE_SHOW_COMMAND: + return store.dispatch(await consoleActions.showCommand(msg.command)); + case messages.CONSOLE_SHOW_FIND: + return store.dispatch(consoleActions.showFind()); + case messages.CONSOLE_SHOW_ERROR: + return store.dispatch(consoleActions.showError(msg.text)); + case messages.CONSOLE_SHOW_INFO: + return store.dispatch(consoleActions.showInfo(msg.text)); + case messages.CONSOLE_HIDE: + return store.dispatch(consoleActions.hide()); } }; browser.runtime.onMessage.addListener(onMessage); -const port = browser.runtime.connect(undefined, { name: 'vimvixen-console' }); +const port = browser.runtime.connect(undefined, { name: "vimvixen-console" }); port.onMessage.addListener(onMessage); diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts index f1508bb..f2ffed7 100644 --- a/src/console/reducers/index.ts +++ b/src/console/reducers/index.ts @@ -1,4 +1,4 @@ -import * as actions from '../actions'; +import * as actions from "../actions"; import Completions from "../Completions"; import CompletionType from "../../shared/CompletionType"; @@ -14,11 +14,11 @@ export interface State { } const defaultState = { - mode: '', - messageText: '', - consoleText: '', + mode: "", + messageText: "", + consoleText: "", completionTypes: [], - completionSource: '', + completionSource: "", completions: [], select: -1, viewIndex: 0, @@ -33,7 +33,7 @@ const nextSelection = (state: State): number => { } const length = state.completions - .map(g => g.items.length) + .map((g) => g.items.length) .reduce((x, y) => x + y); if (state.select + 1 < length) { return state.select + 1; @@ -43,7 +43,7 @@ const nextSelection = (state: State): number => { const prevSelection = (state: State): number => { const length = state.completions - .map(g => g.items.length) + .map((g) => g.items.length) .reduce((x, y) => x + y); if (state.select < 0) { return length - 1; @@ -55,66 +55,74 @@ const nextConsoleText = (completions: any[], select: number, defaults: any) => { if (select < 0) { return defaults; } - const items = completions.map(g => g.items).reduce((g1, g2) => g1.concat(g2)); + const items = completions + .map((g) => g.items) + .reduce((g1, g2) => g1.concat(g2)); return items[select].content; }; // eslint-disable-next-line max-lines-per-function export default function reducer( state: State = defaultState, - action: actions.ConsoleAction, + action: actions.ConsoleAction ): State { switch (action.type) { - case actions.CONSOLE_HIDE: - return { ...state, - mode: '', }; - case actions.CONSOLE_SHOW_COMMAND: - return { ...state, - mode: 'command', - consoleText: action.text, - completionTypes: action.completionTypes, - completions: []}; - case actions.CONSOLE_SHOW_FIND: - return { ...state, - mode: 'find', - consoleText: '', - completions: []}; - case actions.CONSOLE_SHOW_ERROR: - return { ...state, - mode: 'error', - messageText: action.text, }; - case actions.CONSOLE_SHOW_INFO: - return { ...state, - mode: 'info', - messageText: action.text, }; - case actions.CONSOLE_HIDE_COMMAND: - return { - ...state, - mode: state.mode === 'command' || state.mode === 'find' ? '' : state.mode, - }; - case actions.CONSOLE_SET_CONSOLE_TEXT: - return { ...state, - consoleText: action.consoleText, }; - case actions.CONSOLE_SET_COMPLETIONS: - return { ...state, - completions: action.completions, - completionSource: action.completionSource, - select: -1 }; - case actions.CONSOLE_COMPLETION_NEXT: { - const select = nextSelection(state); - return { ...state, - select: select, - consoleText: nextConsoleText( - state.completions, select, state.completionSource) }; - } - case actions.CONSOLE_COMPLETION_PREV: { - const select = prevSelection(state); - return { ...state, - select: select, - consoleText: nextConsoleText( - state.completions, select, state.completionSource) }; - } - default: - return state; + case actions.CONSOLE_HIDE: + return { ...state, mode: "" }; + case actions.CONSOLE_SHOW_COMMAND: + return { + ...state, + mode: "command", + consoleText: action.text, + completionTypes: action.completionTypes, + completions: [], + }; + case actions.CONSOLE_SHOW_FIND: + return { ...state, mode: "find", consoleText: "", completions: [] }; + case actions.CONSOLE_SHOW_ERROR: + return { ...state, mode: "error", messageText: action.text }; + case actions.CONSOLE_SHOW_INFO: + return { ...state, mode: "info", messageText: action.text }; + case actions.CONSOLE_HIDE_COMMAND: + return { + ...state, + mode: + state.mode === "command" || state.mode === "find" ? "" : state.mode, + }; + case actions.CONSOLE_SET_CONSOLE_TEXT: + return { ...state, consoleText: action.consoleText }; + case actions.CONSOLE_SET_COMPLETIONS: + return { + ...state, + completions: action.completions, + completionSource: action.completionSource, + select: -1, + }; + case actions.CONSOLE_COMPLETION_NEXT: { + const select = nextSelection(state); + return { + ...state, + select: select, + consoleText: nextConsoleText( + state.completions, + select, + state.completionSource + ), + }; + } + case actions.CONSOLE_COMPLETION_PREV: { + const select = prevSelection(state); + return { + ...state, + select: select, + consoleText: nextConsoleText( + state.completions, + select, + state.completionSource + ), + }; + } + default: + return state; } } diff --git a/src/content/Application.ts b/src/content/Application.ts index fbfeb6d..996bbbc 100644 --- a/src/content/Application.ts +++ b/src/content/Application.ts @@ -1,25 +1,24 @@ -import { injectable } from 'tsyringe'; -import MessageListener from './MessageListener'; -import FindController from './controllers/FindController'; -import MarkController from './controllers/MarkController'; -import FollowMasterController from './controllers/FollowMasterController'; -import FollowSlaveController from './controllers/FollowSlaveController'; -import FollowKeyController from './controllers/FollowKeyController'; -import InputDriver from './InputDriver'; -import KeymapController from './controllers/KeymapController'; -import AddonEnabledUseCase from './usecases/AddonEnabledUseCase'; -import MarkKeyController from './controllers/MarkKeyController'; -import AddonEnabledController from './controllers/AddonEnabledController'; -import SettingController from './controllers/SettingController'; -import ConsoleFrameController from './controllers/ConsoleFrameController'; -import NavigateController from './controllers/NavigateController'; -import * as messages from '../shared/messages'; +import { injectable } from "tsyringe"; +import MessageListener from "./MessageListener"; +import FindController from "./controllers/FindController"; +import MarkController from "./controllers/MarkController"; +import FollowMasterController from "./controllers/FollowMasterController"; +import FollowSlaveController from "./controllers/FollowSlaveController"; +import FollowKeyController from "./controllers/FollowKeyController"; +import InputDriver from "./InputDriver"; +import KeymapController from "./controllers/KeymapController"; +import AddonEnabledUseCase from "./usecases/AddonEnabledUseCase"; +import MarkKeyController from "./controllers/MarkKeyController"; +import AddonEnabledController from "./controllers/AddonEnabledController"; +import SettingController from "./controllers/SettingController"; +import ConsoleFrameController from "./controllers/ConsoleFrameController"; +import NavigateController from "./controllers/NavigateController"; +import * as messages from "../shared/messages"; type Message = messages.Message; @injectable() export default class Application { - // eslint-disable-next-line max-params constructor( private messageListener: MessageListener, @@ -34,9 +33,8 @@ export default class Application { private addonEnabledController: AddonEnabledController, private settingController: SettingController, private consoleFrameController: ConsoleFrameController, - private navigateController: NavigateController, - ) { - } + private navigateController: NavigateController + ) {} run() { this.routeCommonComponents(); @@ -49,30 +47,30 @@ export default class Application { private routeMasterComponents() { this.messageListener.onWebMessage((msg: Message, sender: Window) => { switch (msg.type) { - case messages.CONSOLE_ENTER_FIND: - return this.findController.start(msg); - case messages.FIND_NEXT: - return this.findController.next(msg); - case messages.FIND_PREV: - return this.findController.prev(msg); - case messages.CONSOLE_UNFOCUS: - return this.consoleFrameController.unfocus(msg); - case messages.FOLLOW_START: - return this.followMasterController.followStart(msg); - case messages.FOLLOW_RESPONSE_COUNT_TARGETS: - return this.followMasterController.responseCountTargets(msg, sender); - case messages.FOLLOW_KEY_PRESS: - return this.followMasterController.keyPress(msg); + case messages.CONSOLE_ENTER_FIND: + return this.findController.start(msg); + case messages.FIND_NEXT: + return this.findController.next(msg); + case messages.FIND_PREV: + return this.findController.prev(msg); + case messages.CONSOLE_UNFOCUS: + return this.consoleFrameController.unfocus(msg); + case messages.FOLLOW_START: + return this.followMasterController.followStart(msg); + case messages.FOLLOW_RESPONSE_COUNT_TARGETS: + return this.followMasterController.responseCountTargets(msg, sender); + case messages.FOLLOW_KEY_PRESS: + return this.followMasterController.keyPress(msg); } return undefined; }); this.messageListener.onBackgroundMessage((msg: Message) => { switch (msg.type) { - case messages.ADDON_ENABLED_QUERY: - return this.addonEnabledController.getAddonEnabled(msg); - case messages.TAB_SCROLL_TO: - return this.markController.scrollTo(msg); + case messages.ADDON_ENABLED_QUERY: + return this.addonEnabledController.getAddonEnabled(msg); + case messages.TAB_SCROLL_TO: + return this.markController.scrollTo(msg); } return undefined; }); @@ -81,47 +79,47 @@ export default class Application { private routeCommonComponents() { this.messageListener.onWebMessage((msg: Message) => { switch (msg.type) { - case messages.FOLLOW_REQUEST_COUNT_TARGETS: - return this.followSlaveController.countTargets(msg); - case messages.FOLLOW_CREATE_HINTS: - return this.followSlaveController.createHints(msg); - case messages.FOLLOW_SHOW_HINTS: - return this.followSlaveController.showHints(msg); - case messages.FOLLOW_ACTIVATE: - return this.followSlaveController.activate(msg); - case messages.FOLLOW_REMOVE_HINTS: - return this.followSlaveController.clear(msg); + case messages.FOLLOW_REQUEST_COUNT_TARGETS: + return this.followSlaveController.countTargets(msg); + case messages.FOLLOW_CREATE_HINTS: + return this.followSlaveController.createHints(msg); + case messages.FOLLOW_SHOW_HINTS: + return this.followSlaveController.showHints(msg); + case messages.FOLLOW_ACTIVATE: + return this.followSlaveController.activate(msg); + case messages.FOLLOW_REMOVE_HINTS: + return this.followSlaveController.clear(msg); } return undefined; }); this.messageListener.onBackgroundMessage((msg: Message): any => { switch (msg.type) { - case messages.SETTINGS_CHANGED: - return this.settingController.reloadSettings(msg); - case messages.ADDON_TOGGLE_ENABLED: - return this.addonEnabledUseCase.toggle(); - case messages.NAVIGATE_HISTORY_NEXT: - return this.navigateController.openHistoryNext(msg); - case messages.NAVIGATE_HISTORY_PREV: - return this.navigateController.openHistoryPrev(msg); - case messages.NAVIGATE_LINK_NEXT: - return this.navigateController.openLinkNext(msg); - case messages.NAVIGATE_LINK_PREV: - return this.navigateController.openLinkPrev(msg); + case messages.SETTINGS_CHANGED: + return this.settingController.reloadSettings(msg); + case messages.ADDON_TOGGLE_ENABLED: + return this.addonEnabledUseCase.toggle(); + case messages.NAVIGATE_HISTORY_NEXT: + return this.navigateController.openHistoryNext(msg); + case messages.NAVIGATE_HISTORY_PREV: + return this.navigateController.openHistoryPrev(msg); + case messages.NAVIGATE_LINK_NEXT: + return this.navigateController.openLinkNext(msg); + case messages.NAVIGATE_LINK_PREV: + return this.navigateController.openLinkPrev(msg); } }); const inputDriver = new InputDriver(window.document.body); - inputDriver.onKey(key => this.followKeyController.press(key)); - inputDriver.onKey(key => this.markKeyController.press(key)); - inputDriver.onKey(key => this.keymapController.press(key)); + inputDriver.onKey((key) => this.followKeyController.press(key)); + inputDriver.onKey((key) => this.markKeyController.press(key)); + inputDriver.onKey((key) => this.keymapController.press(key)); this.settingController.initSettings(); } private routeFocusEvents() { - window.addEventListener('blur', () => { + window.addEventListener("blur", () => { this.keymapController.onBlurWindow(); }); } diff --git a/src/content/InputDriver.ts b/src/content/InputDriver.ts index cf28205..76c1fc9 100644 --- a/src/content/InputDriver.ts +++ b/src/content/InputDriver.ts @@ -1,24 +1,24 @@ -import * as dom from '../shared/utils/dom'; -import Key from '../shared/settings/Key'; +import * as dom from "../shared/utils/dom"; +import Key from "../shared/settings/Key"; const cancelKey = (e: KeyboardEvent): boolean => { - if (e.key === 'Escape') { + if (e.key === "Escape") { return true; } - if (e.key === '[' && e.ctrlKey) { + if (e.key === "[" && e.ctrlKey) { return true; } return false; }; const modifiedKeyName = (name: string): string => { - if (name === ' ') { - return 'Space'; + if (name === " ") { + return "Space"; } if (name.length === 1) { return name; - } else if (name === 'Escape') { - return 'Esc'; + } else if (name === "Escape") { + return "Esc"; } return name; }; @@ -44,7 +44,7 @@ export const keyFromKeyboardEvent = (e: KeyboardEvent): Key => { }; export default class InputDriver { - private pressed: {[key: string]: string} = {}; + private pressed: { [key: string]: string } = {}; private onKeyListeners: ((key: Key) => boolean)[] = []; @@ -52,9 +52,9 @@ export default class InputDriver { this.pressed = {}; this.onKeyListeners = []; - target.addEventListener('keypress', this.onKeyPress.bind(this)); - target.addEventListener('keydown', this.onKeyDown.bind(this)); - target.addEventListener('keyup', this.onKeyUp.bind(this)); + target.addEventListener("keypress", this.onKeyPress.bind(this)); + target.addEventListener("keydown", this.onKeyDown.bind(this)); + target.addEventListener("keyup", this.onKeyUp.bind(this)); } onKey(cb: (key: Key) => boolean) { @@ -62,18 +62,18 @@ export default class InputDriver { } private onKeyPress(e: KeyboardEvent) { - if (this.pressed[e.key] && this.pressed[e.key] !== 'keypress') { + if (this.pressed[e.key] && this.pressed[e.key] !== "keypress") { return; } - this.pressed[e.key] = 'keypress'; + this.pressed[e.key] = "keypress"; this.capture(e); } private onKeyDown(e: KeyboardEvent) { - if (this.pressed[e.key] && this.pressed[e.key] !== 'keydown') { + if (this.pressed[e.key] && this.pressed[e.key] !== "keydown") { return; } - this.pressed[e.key] = 'keydown'; + this.pressed[e.key] = "keydown"; this.capture(e); } @@ -93,7 +93,7 @@ export default class InputDriver { } return; } - if (['Shift', 'Control', 'Alt', 'OS'].includes(e.key)) { + if (["Shift", "Control", "Alt", "OS"].includes(e.key)) { // pressing only meta key is ignored return; } @@ -110,9 +110,11 @@ export default class InputDriver { } private fromInput(e: Element) { - return e instanceof HTMLInputElement || + return ( + e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement || - dom.isContentEditable(e); + dom.isContentEditable(e) + ); } } diff --git a/src/content/MessageListener.ts b/src/content/MessageListener.ts index e1f7c75..3fe1dcd 100644 --- a/src/content/MessageListener.ts +++ b/src/content/MessageListener.ts @@ -1,14 +1,12 @@ -import { injectable } from 'tsyringe'; -import { Message, valueOf } from '../shared/messages'; +import { injectable } from "tsyringe"; +import { Message, valueOf } from "../shared/messages"; export type WebExtMessageSender = browser.runtime.MessageSender; @injectable() export default class MessageListener { - onWebMessage( - listener: (msg: Message, sender: Window) => void, - ) { - window.addEventListener('message', (event: MessageEvent) => { + onWebMessage(listener: (msg: Message, sender: Window) => void) { + window.addEventListener("message", (event: MessageEvent) => { const sender = event.source; if (!(sender instanceof Window)) { return; @@ -25,12 +23,12 @@ export default class MessageListener { } onBackgroundMessage( - listener: (msg: Message, sender: WebExtMessageSender) => any, + listener: (msg: Message, sender: WebExtMessageSender) => any ) { browser.runtime.onMessage.addListener( (msg: any, sender: WebExtMessageSender) => { return listener(valueOf(msg), sender); - }, + } ); } } diff --git a/src/content/client/AddonIndicatorClient.ts b/src/content/client/AddonIndicatorClient.ts index b5f7e6a..861ef40 100644 --- a/src/content/client/AddonIndicatorClient.ts +++ b/src/content/client/AddonIndicatorClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface AddonIndicatorClient { setEnabled(enabled: boolean): Promise<void>; diff --git a/src/content/client/ConsoleClient.ts b/src/content/client/ConsoleClient.ts index b4fbb04..0aac8d0 100644 --- a/src/content/client/ConsoleClient.ts +++ b/src/content/client/ConsoleClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface ConsoleClient { info(text: string): Promise<void>; diff --git a/src/content/client/FindClient.ts b/src/content/client/FindClient.ts index 8b2aca4..7da5069 100644 --- a/src/content/client/FindClient.ts +++ b/src/content/client/FindClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface FindClient { getGlobalLastKeyword(): Promise<string | null>; diff --git a/src/content/client/FindMasterClient.ts b/src/content/client/FindMasterClient.ts index 9ed38dd..9c3f812 100644 --- a/src/content/client/FindMasterClient.ts +++ b/src/content/client/FindMasterClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface FindMasterClient { findNext(): void; @@ -8,14 +8,20 @@ export default interface FindMasterClient { export class FindMasterClientImpl implements FindMasterClient { findNext(): void { - window.top.postMessage(JSON.stringify({ - type: messages.FIND_NEXT, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.FIND_NEXT, + }), + "*" + ); } findPrev(): void { - window.top.postMessage(JSON.stringify({ - type: messages.FIND_PREV, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.FIND_PREV, + }), + "*" + ); } } diff --git a/src/content/client/FollowMasterClient.ts b/src/content/client/FollowMasterClient.ts index 6681e8a..f068683 100644 --- a/src/content/client/FollowMasterClient.ts +++ b/src/content/client/FollowMasterClient.ts @@ -1,5 +1,5 @@ -import * as messages from '../../shared/messages'; -import Key from '../../shared/settings/Key'; +import * as messages from "../../shared/messages"; +import Key from "../../shared/settings/Key"; export default interface FollowMasterClient { startFollow(newTab: boolean, background: boolean): void; @@ -40,6 +40,6 @@ export class FollowMasterClientImpl implements FollowMasterClient { } private postMessage(msg: messages.Message): void { - this.window.postMessage(JSON.stringify(msg), '*'); + this.window.postMessage(JSON.stringify(msg), "*"); } } diff --git a/src/content/client/FollowSlaveClient.ts b/src/content/client/FollowSlaveClient.ts index 4360200..eb9651a 100644 --- a/src/content/client/FollowSlaveClient.ts +++ b/src/content/client/FollowSlaveClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; interface Size { width: number; @@ -69,6 +69,6 @@ export class FollowSlaveClientImpl implements FollowSlaveClient { } private postMessage(msg: messages.Message): void { - this.target.postMessage(JSON.stringify(msg), '*'); + this.target.postMessage(JSON.stringify(msg), "*"); } } diff --git a/src/content/client/FollowSlaveClientFactory.ts b/src/content/client/FollowSlaveClientFactory.ts index 166dfca..beaa77a 100644 --- a/src/content/client/FollowSlaveClientFactory.ts +++ b/src/content/client/FollowSlaveClientFactory.ts @@ -1,4 +1,4 @@ -import FollowSlaveClient, { FollowSlaveClientImpl } from './FollowSlaveClient'; +import FollowSlaveClient, { FollowSlaveClientImpl } from "./FollowSlaveClient"; export default interface FollowSlaveClientFactory { create(window: Window): FollowSlaveClient; diff --git a/src/content/client/MarkClient.ts b/src/content/client/MarkClient.ts index c6295c0..d1f00ae 100644 --- a/src/content/client/MarkClient.ts +++ b/src/content/client/MarkClient.ts @@ -1,5 +1,5 @@ -import Mark from '../domains/Mark'; -import * as messages from '../../shared/messages'; +import Mark from "../domains/Mark"; +import * as messages from "../../shared/messages"; export default interface MarkClient { setGloablMark(key: string, mark: Mark): Promise<void>; diff --git a/src/content/client/OperationClient.ts b/src/content/client/OperationClient.ts index 9c72c75..2bc7aee 100644 --- a/src/content/client/OperationClient.ts +++ b/src/content/client/OperationClient.ts @@ -1,11 +1,13 @@ -import * as operations from '../../shared/operations'; -import * as messages from '../../shared/messages'; +import * as operations from "../../shared/operations"; +import * as messages from "../../shared/messages"; export default interface OperationClient { execBackgroundOp(repeat: number, op: operations.Operation): Promise<void>; internalOpenUrl( - url: string, newTab?: boolean, background?: boolean, + url: string, + newTab?: boolean, + background?: boolean ): Promise<void>; } @@ -19,7 +21,9 @@ export class OperationClientImpl implements OperationClient { } internalOpenUrl( - url: string, newTab?: boolean, background?: boolean, + url: string, + newTab?: boolean, + background?: boolean ): Promise<void> { return browser.runtime.sendMessage({ type: messages.BACKGROUND_OPERATION, diff --git a/src/content/client/SettingClient.ts b/src/content/client/SettingClient.ts index f89f3cd..11d7075 100644 --- a/src/content/client/SettingClient.ts +++ b/src/content/client/SettingClient.ts @@ -1,5 +1,5 @@ -import Settings from '../../shared/settings/Settings'; -import * as messages from '../../shared/messages'; +import Settings from "../../shared/settings/Settings"; +import * as messages from "../../shared/messages"; export default interface SettingClient { load(): Promise<Settings>; diff --git a/src/content/client/TabsClient.ts b/src/content/client/TabsClient.ts index 39348df..9169a3d 100644 --- a/src/content/client/TabsClient.ts +++ b/src/content/client/TabsClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface TabsClient { openUrl(url: string, newTab: boolean, background?: boolean): Promise<void>; @@ -8,7 +8,7 @@ export class TabsClientImpl implements TabsClient { async openUrl( url: string, newTab: boolean, - background?: boolean, + background?: boolean ): Promise<void> { await browser.runtime.sendMessage({ type: messages.OPEN_URL, diff --git a/src/content/controllers/AddonEnabledController.ts b/src/content/controllers/AddonEnabledController.ts index 59b45fa..9ef56a9 100644 --- a/src/content/controllers/AddonEnabledController.ts +++ b/src/content/controllers/AddonEnabledController.ts @@ -1,16 +1,13 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; @injectable() export default class AddonEnabledController { - constructor( - private addonEnabledUseCase: AddonEnabledUseCase, - ) { - } + constructor(private addonEnabledUseCase: AddonEnabledUseCase) {} getAddonEnabled( - _message: messages.AddonEnabledQueryMessage, + _message: messages.AddonEnabledQueryMessage ): Promise<boolean> { const enabled = this.addonEnabledUseCase.getEnabled(); return Promise.resolve(enabled); diff --git a/src/content/controllers/ConsoleFrameController.ts b/src/content/controllers/ConsoleFrameController.ts index ae26b7c..84e0ce6 100644 --- a/src/content/controllers/ConsoleFrameController.ts +++ b/src/content/controllers/ConsoleFrameController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import ConsoleFrameUseCase from '../usecases/ConsoleFrameUseCase'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import ConsoleFrameUseCase from "../usecases/ConsoleFrameUseCase"; +import * as messages from "../../shared/messages"; @injectable() export default class ConsoleFrameController { - constructor( - private consoleFrameUseCase: ConsoleFrameUseCase, - ) { - } + constructor(private consoleFrameUseCase: ConsoleFrameUseCase) {} unfocus(_message: messages.Message) { this.consoleFrameUseCase.unfocus(); diff --git a/src/content/controllers/FindController.ts b/src/content/controllers/FindController.ts index 7735176..3087d5d 100644 --- a/src/content/controllers/FindController.ts +++ b/src/content/controllers/FindController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import FindUseCase from '../usecases/FindUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import FindUseCase from "../usecases/FindUseCase"; @injectable() export default class FindController { - constructor( - private findUseCase: FindUseCase, - ) { - } + constructor(private findUseCase: FindUseCase) {} async start(m: messages.ConsoleEnterFindMessage): Promise<void> { await this.findUseCase.startFind(m.text); diff --git a/src/content/controllers/FollowKeyController.ts b/src/content/controllers/FollowKeyController.ts index 0fd94ff..45d202a 100644 --- a/src/content/controllers/FollowKeyController.ts +++ b/src/content/controllers/FollowKeyController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import FollowSlaveUseCase from '../usecases/FollowSlaveUseCase'; -import Key from '../../shared/settings/Key'; +import { injectable } from "tsyringe"; +import FollowSlaveUseCase from "../usecases/FollowSlaveUseCase"; +import Key from "../../shared/settings/Key"; @injectable() export default class FollowKeyController { - constructor( - private followSlaveUseCase: FollowSlaveUseCase, - ) { - } + constructor(private followSlaveUseCase: FollowSlaveUseCase) {} press(key: Key): boolean { if (!this.followSlaveUseCase.isFollowMode()) { diff --git a/src/content/controllers/FollowMasterController.ts b/src/content/controllers/FollowMasterController.ts index fa99820..e7895fa 100644 --- a/src/content/controllers/FollowMasterController.ts +++ b/src/content/controllers/FollowMasterController.ts @@ -1,30 +1,27 @@ -import { injectable } from 'tsyringe'; -import FollowMasterUseCase from '../usecases/FollowMasterUseCase'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import FollowMasterUseCase from "../usecases/FollowMasterUseCase"; +import * as messages from "../../shared/messages"; @injectable() export default class FollowMasterController { - constructor( - private followMasterUseCase: FollowMasterUseCase, - ) { - } + constructor(private followMasterUseCase: FollowMasterUseCase) {} followStart(m: messages.FollowStartMessage): void { this.followMasterUseCase.startFollow(m.newTab, m.background); } responseCountTargets( - m: messages.FollowResponseCountTargetsMessage, sender: Window, + m: messages.FollowResponseCountTargetsMessage, + sender: Window ): void { this.followMasterUseCase.createSlaveHints(m.count, sender); } keyPress(message: messages.FollowKeyPressMessage): void { - if (message.key === '[' && message.ctrlKey) { + if (message.key === "[" && message.ctrlKey) { this.followMasterUseCase.cancelFollow(); } else { this.followMasterUseCase.enqueue(message.key); } } } - diff --git a/src/content/controllers/FollowSlaveController.ts b/src/content/controllers/FollowSlaveController.ts index 65ce477..25f0505 100644 --- a/src/content/controllers/FollowSlaveController.ts +++ b/src/content/controllers/FollowSlaveController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import FollowSlaveUseCase from '../usecases/FollowSlaveUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import FollowSlaveUseCase from "../usecases/FollowSlaveUseCase"; @injectable() export default class FollowSlaveController { - constructor( - private usecase: FollowSlaveUseCase, - ) { - } + constructor(private usecase: FollowSlaveUseCase) {} countTargets(m: messages.FollowRequestCountTargetsMessage): void { this.usecase.countTargets(m.viewSize, m.framePosition); diff --git a/src/content/controllers/KeymapController.ts b/src/content/controllers/KeymapController.ts index 639b4a1..092e55c 100644 --- a/src/content/controllers/KeymapController.ts +++ b/src/content/controllers/KeymapController.ts @@ -1,15 +1,15 @@ -import { injectable, inject } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import KeymapUseCase from '../usecases/KeymapUseCase'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; -import FindSlaveUseCase from '../usecases/FindSlaveUseCase'; -import ScrollUseCase from '../usecases/ScrollUseCase'; -import FocusUseCase from '../usecases/FocusUseCase'; -import ClipboardUseCase from '../usecases/ClipboardUseCase'; -import OperationClient from '../client/OperationClient'; -import MarkKeyyUseCase from '../usecases/MarkKeyUseCase'; -import FollowMasterClient from '../client/FollowMasterClient'; -import Key from '../../shared/settings/Key'; +import { injectable, inject } from "tsyringe"; +import * as operations from "../../shared/operations"; +import KeymapUseCase from "../usecases/KeymapUseCase"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; +import FindSlaveUseCase from "../usecases/FindSlaveUseCase"; +import ScrollUseCase from "../usecases/ScrollUseCase"; +import FocusUseCase from "../usecases/FocusUseCase"; +import ClipboardUseCase from "../usecases/ClipboardUseCase"; +import OperationClient from "../client/OperationClient"; +import MarkKeyyUseCase from "../usecases/MarkKeyUseCase"; +import FollowMasterClient from "../client/FollowMasterClient"; +import Key from "../../shared/settings/Key"; @injectable() export default class KeymapController { @@ -22,13 +22,12 @@ export default class KeymapController { private clipbaordUseCase: ClipboardUseCase, private markKeyUseCase: MarkKeyyUseCase, - @inject('OperationClient') + @inject("OperationClient") private operationClient: OperationClient, - @inject('FollowMasterClient') - private followMasterClient: FollowMasterClient, - ) { - } + @inject("FollowMasterClient") + private followMasterClient: FollowMasterClient + ) {} // eslint-disable-next-line complexity, max-lines-per-function press(key: Key): boolean { @@ -43,47 +42,46 @@ export default class KeymapController { const doFunc = ((op: operations.Operation) => { switch (op.type) { - case operations.ADDON_ENABLE: - return () => this.addonEnabledUseCase.enable(); - case operations.ADDON_DISABLE: - return () => this.addonEnabledUseCase.disable(); - case operations.ADDON_TOGGLE_ENABLED: - return () => this.addonEnabledUseCase.toggle(); - case operations.FIND_NEXT: - return () => this.findSlaveUseCase.findNext(); - case operations.FIND_PREV: - return () => this.findSlaveUseCase.findPrev(); - case operations.SCROLL_VERTICALLY: - return () => this.scrollUseCase.scrollVertically(op.count); - case operations.SCROLL_HORIZONALLY: - return () => this.scrollUseCase.scrollHorizonally(op.count); - case operations.SCROLL_PAGES: - return () => this.scrollUseCase.scrollPages(op.count); - case operations.SCROLL_TOP: - return () => this.scrollUseCase.scrollToTop(); - case operations.SCROLL_BOTTOM: - return () => this.scrollUseCase.scrollToBottom(); - case operations.SCROLL_HOME: - return () => this.scrollUseCase.scrollToHome(); - case operations.SCROLL_END: - return () => this.scrollUseCase.scrollToEnd(); - case operations.FOLLOW_START: - return () => this.followMasterClient.startFollow( - op.newTab, op.background); - case operations.MARK_SET_PREFIX: - return () => this.markKeyUseCase.enableSetMode(); - case operations.MARK_JUMP_PREFIX: - return () => this.markKeyUseCase.enableJumpMode(); - case operations.FOCUS_INPUT: - return () => this.focusUseCase.focusFirstInput(); - case operations.URLS_YANK: - return () => this.clipbaordUseCase.yankCurrentURL(); - case operations.URLS_PASTE: - return () => this.clipbaordUseCase.openOrSearch( - op.newTab ? op.newTab : false, - ); - default: - return null; + case operations.ADDON_ENABLE: + return () => this.addonEnabledUseCase.enable(); + case operations.ADDON_DISABLE: + return () => this.addonEnabledUseCase.disable(); + case operations.ADDON_TOGGLE_ENABLED: + return () => this.addonEnabledUseCase.toggle(); + case operations.FIND_NEXT: + return () => this.findSlaveUseCase.findNext(); + case operations.FIND_PREV: + return () => this.findSlaveUseCase.findPrev(); + case operations.SCROLL_VERTICALLY: + return () => this.scrollUseCase.scrollVertically(op.count); + case operations.SCROLL_HORIZONALLY: + return () => this.scrollUseCase.scrollHorizonally(op.count); + case operations.SCROLL_PAGES: + return () => this.scrollUseCase.scrollPages(op.count); + case operations.SCROLL_TOP: + return () => this.scrollUseCase.scrollToTop(); + case operations.SCROLL_BOTTOM: + return () => this.scrollUseCase.scrollToBottom(); + case operations.SCROLL_HOME: + return () => this.scrollUseCase.scrollToHome(); + case operations.SCROLL_END: + return () => this.scrollUseCase.scrollToEnd(); + case operations.FOLLOW_START: + return () => + this.followMasterClient.startFollow(op.newTab, op.background); + case operations.MARK_SET_PREFIX: + return () => this.markKeyUseCase.enableSetMode(); + case operations.MARK_JUMP_PREFIX: + return () => this.markKeyUseCase.enableJumpMode(); + case operations.FOCUS_INPUT: + return () => this.focusUseCase.focusFirstInput(); + case operations.URLS_YANK: + return () => this.clipbaordUseCase.yankCurrentURL(); + case operations.URLS_PASTE: + return () => + this.clipbaordUseCase.openOrSearch(op.newTab ? op.newTab : false); + default: + return null; } })(nextOp.op); diff --git a/src/content/controllers/MarkController.ts b/src/content/controllers/MarkController.ts index 5eb898a..05a0c75 100644 --- a/src/content/controllers/MarkController.ts +++ b/src/content/controllers/MarkController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import MarkUseCase from '../usecases/MarkUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import MarkUseCase from "../usecases/MarkUseCase"; @injectable() export default class MarkController { - constructor( - private markUseCase: MarkUseCase, - ) { - } + constructor(private markUseCase: MarkUseCase) {} scrollTo(message: messages.TabScrollToMessage) { this.markUseCase.scroll(message.x, message.y); diff --git a/src/content/controllers/MarkKeyController.ts b/src/content/controllers/MarkKeyController.ts index e7653ee..a011af1 100644 --- a/src/content/controllers/MarkKeyController.ts +++ b/src/content/controllers/MarkKeyController.ts @@ -1,15 +1,14 @@ -import { injectable } from 'tsyringe'; -import MarkUseCase from '../usecases/MarkUseCase'; -import MarkKeyyUseCase from '../usecases/MarkKeyUseCase'; -import Key from '../../shared/settings/Key'; +import { injectable } from "tsyringe"; +import MarkUseCase from "../usecases/MarkUseCase"; +import MarkKeyyUseCase from "../usecases/MarkKeyUseCase"; +import Key from "../../shared/settings/Key"; @injectable() export default class MarkKeyController { constructor( private markUseCase: MarkUseCase, - private markKeyUseCase: MarkKeyyUseCase, - ) { - } + private markKeyUseCase: MarkKeyyUseCase + ) {} press(key: Key): boolean { if (this.markKeyUseCase.isSetMode()) { diff --git a/src/content/controllers/NavigateController.ts b/src/content/controllers/NavigateController.ts index 3f2df7a..5b66a39 100644 --- a/src/content/controllers/NavigateController.ts +++ b/src/content/controllers/NavigateController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import { Message } from '../../shared/messages'; -import NavigateUseCase from '../usecases/NavigateUseCase'; +import { injectable } from "tsyringe"; +import { Message } from "../../shared/messages"; +import NavigateUseCase from "../usecases/NavigateUseCase"; @injectable() export default class NavigateController { - constructor( - private navigateUseCase: NavigateUseCase, - ) { - } + constructor(private navigateUseCase: NavigateUseCase) {} openHistoryNext(_m: Message): Promise<void> { this.navigateUseCase.openHistoryNext(); diff --git a/src/content/controllers/SettingController.ts b/src/content/controllers/SettingController.ts index 2d32c09..72d484c 100644 --- a/src/content/controllers/SettingController.ts +++ b/src/content/controllers/SettingController.ts @@ -1,16 +1,14 @@ -import { injectable } from 'tsyringe'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; -import SettingUseCase from '../usecases/SettingUseCase'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; +import SettingUseCase from "../usecases/SettingUseCase"; +import * as messages from "../../shared/messages"; @injectable() export default class SettingController { - constructor( private addonEnabledUseCase: AddonEnabledUseCase, - private settingUseCase: SettingUseCase, - ) { - } + private settingUseCase: SettingUseCase + ) {} async initSettings(): Promise<void> { try { diff --git a/src/content/di.ts b/src/content/di.ts index 63103a1..cc10c78 100644 --- a/src/content/di.ts +++ b/src/content/di.ts @@ -1,58 +1,78 @@ /* eslint-disable max-len */ -import { AddonEnabledRepositoryImpl } from './repositories/AddonEnabledRepository'; -import { AddonIndicatorClientImpl } from './client/AddonIndicatorClient'; -import { AddressRepositoryImpl } from './repositories/AddressRepository'; -import { ClipboardRepositoryImpl } from './repositories/ClipboardRepository'; -import { ConsoleClientImpl } from './client/ConsoleClient'; -import { ConsoleFramePresenterImpl } from './presenters/ConsoleFramePresenter'; -import { FindClientImpl } from './client/FindClient'; -import { FindMasterClientImpl } from './client/FindMasterClient'; -import { FindPresenterImpl } from './presenters/FindPresenter'; -import { FindRepositoryImpl } from './repositories/FindRepository'; -import { FocusPresenterImpl } from './presenters/FocusPresenter'; -import { FollowKeyRepositoryImpl } from './repositories/FollowKeyRepository'; -import { FollowMasterClientImpl } from './client/FollowMasterClient'; -import { FollowMasterRepositoryImpl } from './repositories/FollowMasterRepository'; -import { FollowPresenterImpl } from './presenters/FollowPresenter'; -import { FollowSlaveClientFactoryImpl } from './client/FollowSlaveClientFactory'; -import { FollowSlaveRepositoryImpl } from './repositories/FollowSlaveRepository'; -import { KeymapRepositoryImpl } from './repositories/KeymapRepository'; -import { MarkClientImpl } from './client/MarkClient'; -import { MarkKeyRepositoryImpl } from './repositories/MarkKeyRepository'; -import { MarkRepositoryImpl } from './repositories/MarkRepository'; -import { NavigationPresenterImpl } from './presenters/NavigationPresenter'; -import { OperationClientImpl } from './client/OperationClient'; -import { ScrollPresenterImpl } from './presenters/ScrollPresenter'; -import { SettingClientImpl } from './client/SettingClient'; -import { SettingRepositoryImpl } from './repositories/SettingRepository'; -import { TabsClientImpl } from './client/TabsClient'; -import { container } from 'tsyringe'; +import { AddonEnabledRepositoryImpl } from "./repositories/AddonEnabledRepository"; +import { AddonIndicatorClientImpl } from "./client/AddonIndicatorClient"; +import { AddressRepositoryImpl } from "./repositories/AddressRepository"; +import { ClipboardRepositoryImpl } from "./repositories/ClipboardRepository"; +import { ConsoleClientImpl } from "./client/ConsoleClient"; +import { ConsoleFramePresenterImpl } from "./presenters/ConsoleFramePresenter"; +import { FindClientImpl } from "./client/FindClient"; +import { FindMasterClientImpl } from "./client/FindMasterClient"; +import { FindPresenterImpl } from "./presenters/FindPresenter"; +import { FindRepositoryImpl } from "./repositories/FindRepository"; +import { FocusPresenterImpl } from "./presenters/FocusPresenter"; +import { FollowKeyRepositoryImpl } from "./repositories/FollowKeyRepository"; +import { FollowMasterClientImpl } from "./client/FollowMasterClient"; +import { FollowMasterRepositoryImpl } from "./repositories/FollowMasterRepository"; +import { FollowPresenterImpl } from "./presenters/FollowPresenter"; +import { FollowSlaveClientFactoryImpl } from "./client/FollowSlaveClientFactory"; +import { FollowSlaveRepositoryImpl } from "./repositories/FollowSlaveRepository"; +import { KeymapRepositoryImpl } from "./repositories/KeymapRepository"; +import { MarkClientImpl } from "./client/MarkClient"; +import { MarkKeyRepositoryImpl } from "./repositories/MarkKeyRepository"; +import { MarkRepositoryImpl } from "./repositories/MarkRepository"; +import { NavigationPresenterImpl } from "./presenters/NavigationPresenter"; +import { OperationClientImpl } from "./client/OperationClient"; +import { ScrollPresenterImpl } from "./presenters/ScrollPresenter"; +import { SettingClientImpl } from "./client/SettingClient"; +import { SettingRepositoryImpl } from "./repositories/SettingRepository"; +import { TabsClientImpl } from "./client/TabsClient"; +import { container } from "tsyringe"; -container.register('FollowMasterClient', { useValue: new FollowMasterClientImpl(window.top) }); -container.register('AddonEnabledRepository', { useClass: AddonEnabledRepositoryImpl }); -container.register('AddonIndicatorClient', { useClass: AddonIndicatorClientImpl }); -container.register('AddressRepository', { useClass: AddressRepositoryImpl }); -container.register('ClipboardRepository', { useClass: ClipboardRepositoryImpl }); -container.register('ConsoleClient', { useClass: ConsoleClientImpl }); -container.register('ConsoleFramePresenter', { useClass: ConsoleFramePresenterImpl }); -container.register('FindClient', { useClass: FindClientImpl }); -container.register('FindMasterClient', { useClass: FindMasterClientImpl }); -container.register('FindPresenter', { useClass: FindPresenterImpl }); -container.register('FindRepository', { useClass: FindRepositoryImpl }); -container.register('FocusPresenter', { useClass: FocusPresenterImpl }); -container.register('FollowKeyRepository', { useClass: FollowKeyRepositoryImpl }); -container.register('FollowMasterRepository', { useClass: FollowMasterRepositoryImpl }); -container.register('FollowPresenter', { useClass: FollowPresenterImpl }); -container.register('FollowSlaveClientFactory', { useClass: FollowSlaveClientFactoryImpl }); -container.register('FollowSlaveRepository', { useClass: FollowSlaveRepositoryImpl }); -container.register('KeymapRepository', { useClass: KeymapRepositoryImpl }); -container.register('MarkClient', { useClass: MarkClientImpl }); -container.register('MarkKeyRepository', { useClass: MarkKeyRepositoryImpl }); -container.register('MarkRepository', { useClass: MarkRepositoryImpl }); -container.register('NavigationPresenter', { useClass: NavigationPresenterImpl }); -container.register('OperationClient', { useClass: OperationClientImpl }); -container.register('ScrollPresenter', { useClass: ScrollPresenterImpl }); -container.register('SettingClient', { useClass: SettingClientImpl }); -container.register('SettingRepository', { useClass: SettingRepositoryImpl }); -container.register('TabsClient', { useClass: TabsClientImpl }); +container.register("FollowMasterClient", { + useValue: new FollowMasterClientImpl(window.top), +}); +container.register("AddonEnabledRepository", { + useClass: AddonEnabledRepositoryImpl, +}); +container.register("AddonIndicatorClient", { + useClass: AddonIndicatorClientImpl, +}); +container.register("AddressRepository", { useClass: AddressRepositoryImpl }); +container.register("ClipboardRepository", { + useClass: ClipboardRepositoryImpl, +}); +container.register("ConsoleClient", { useClass: ConsoleClientImpl }); +container.register("ConsoleFramePresenter", { + useClass: ConsoleFramePresenterImpl, +}); +container.register("FindClient", { useClass: FindClientImpl }); +container.register("FindMasterClient", { useClass: FindMasterClientImpl }); +container.register("FindPresenter", { useClass: FindPresenterImpl }); +container.register("FindRepository", { useClass: FindRepositoryImpl }); +container.register("FocusPresenter", { useClass: FocusPresenterImpl }); +container.register("FollowKeyRepository", { + useClass: FollowKeyRepositoryImpl, +}); +container.register("FollowMasterRepository", { + useClass: FollowMasterRepositoryImpl, +}); +container.register("FollowPresenter", { useClass: FollowPresenterImpl }); +container.register("FollowSlaveClientFactory", { + useClass: FollowSlaveClientFactoryImpl, +}); +container.register("FollowSlaveRepository", { + useClass: FollowSlaveRepositoryImpl, +}); +container.register("KeymapRepository", { useClass: KeymapRepositoryImpl }); +container.register("MarkClient", { useClass: MarkClientImpl }); +container.register("MarkKeyRepository", { useClass: MarkKeyRepositoryImpl }); +container.register("MarkRepository", { useClass: MarkRepositoryImpl }); +container.register("NavigationPresenter", { + useClass: NavigationPresenterImpl, +}); +container.register("OperationClient", { useClass: OperationClientImpl }); +container.register("ScrollPresenter", { useClass: ScrollPresenterImpl }); +container.register("SettingClient", { useClass: SettingClientImpl }); +container.register("SettingRepository", { useClass: SettingRepositoryImpl }); +container.register("TabsClient", { useClass: TabsClientImpl }); diff --git a/src/content/domains/KeySequence.ts b/src/content/domains/KeySequence.ts index cf59125..5819fc5 100644 --- a/src/content/domains/KeySequence.ts +++ b/src/content/domains/KeySequence.ts @@ -1,10 +1,7 @@ -import Key from '../../shared/settings/Key'; +import Key from "../../shared/settings/Key"; export default class KeySequence { - constructor( - public readonly keys: Key[], - ) { - } + constructor(public readonly keys: Key[]) {} push(key: Key): number { return this.keys.push(key); @@ -27,25 +24,26 @@ export default class KeySequence { } isDigitOnly(): boolean { - return this.keys.every(key => key.isDigit()); + return this.keys.every((key) => key.isDigit()); } repeatCount(): number { - let nonDigitAt = this.keys.findIndex(key => !key.isDigit()); + let nonDigitAt = this.keys.findIndex((key) => !key.isDigit()); if (this.keys.length === 0 || nonDigitAt === 0) { return 1; } if (nonDigitAt === -1) { nonDigitAt = this.keys.length; } - const digits = this.keys.slice(0, nonDigitAt) - .map(key => key.key) - .join(''); + const digits = this.keys + .slice(0, nonDigitAt) + .map((key) => key.key) + .join(""); return Number(digits); } trimNumericPrefix(): KeySequence { - let nonDigitAt = this.keys.findIndex(key => !key.isDigit()); + let nonDigitAt = this.keys.findIndex((key) => !key.isDigit()); if (nonDigitAt === -1) { nonDigitAt = this.keys.length; } @@ -53,7 +51,7 @@ export default class KeySequence { } splitNumericPrefix(): [KeySequence, KeySequence] { - const nonDigitIndex = this.keys.findIndex(key => !key.isDigit()); + const nonDigitIndex = this.keys.findIndex((key) => !key.isDigit()); if (nonDigitIndex === -1) { return [this, new KeySequence([])]; } @@ -65,15 +63,16 @@ export default class KeySequence { static fromMapKeys(keys: string): KeySequence { const fromMapKeysRecursive = ( - remaining: string, mappedKeys: Key[], + remaining: string, + mappedKeys: Key[] ): Key[] => { if (remaining.length === 0) { return mappedKeys; } let nextPos = 1; - if (remaining.startsWith('<')) { - const ltPos = remaining.indexOf('>'); + if (remaining.startsWith("<")) { + const ltPos = remaining.indexOf(">"); if (ltPos > 0) { nextPos = ltPos + 1; } diff --git a/src/content/domains/Mark.ts b/src/content/domains/Mark.ts index 0c40988..68ed226 100644 --- a/src/content/domains/Mark.ts +++ b/src/content/domains/Mark.ts @@ -2,4 +2,3 @@ export default interface Mark { x: number; y: number; } - diff --git a/src/content/hint-key-producer.ts b/src/content/hint-key-producer.ts index 3c9482f..a5e2877 100644 --- a/src/content/hint-key-producer.ts +++ b/src/content/hint-key-producer.ts @@ -5,7 +5,7 @@ export default class HintKeyProducer { constructor(charset: string) { if (charset.length === 0) { - throw new TypeError('charset is empty'); + throw new TypeError("charset is empty"); } this.charset = charset; @@ -15,12 +15,12 @@ export default class HintKeyProducer { produce(): string { this.increment(); - return this.counter.map(x => this.charset[x]).join(''); + return this.counter.map((x) => this.charset[x]).join(""); } private increment(): void { const max = this.charset.length - 1; - if (this.counter.every(x => x === max)) { + if (this.counter.every((x) => x === max)) { this.counter = new Array(this.counter.length + 1).fill(0); return; } diff --git a/src/content/index.ts b/src/content/index.ts index 176a157..b575e0d 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -1,10 +1,10 @@ -import 'reflect-metadata'; +import "reflect-metadata"; -import Application from './Application'; -import consoleFrameStyle from './site-style'; -import { ConsoleFramePresenterImpl } from './presenters/ConsoleFramePresenter'; -import { container } from 'tsyringe'; -import './di'; +import Application from "./Application"; +import consoleFrameStyle from "./site-style"; +import { ConsoleFramePresenterImpl } from "./presenters/ConsoleFramePresenter"; +import { container } from "tsyringe"; +import "./di"; if (window.self === window.top) { new ConsoleFramePresenterImpl().initialize(); @@ -13,8 +13,10 @@ if (window.self === window.top) { try { const app = container.resolve(Application); app.run(); -} catch (e) { console.error(e); } +} catch (e) { + console.error(e); +} -const style = window.document.createElement('style'); +const style = window.document.createElement("style"); style.textContent = consoleFrameStyle; window.document.head.appendChild(style); diff --git a/src/content/presenters/ConsoleFramePresenter.ts b/src/content/presenters/ConsoleFramePresenter.ts index 63c78fb..26522c4 100644 --- a/src/content/presenters/ConsoleFramePresenter.ts +++ b/src/content/presenters/ConsoleFramePresenter.ts @@ -6,17 +6,17 @@ export default interface ConsoleFramePresenter { export class ConsoleFramePresenterImpl implements ConsoleFramePresenter { initialize(): void { - const iframe = document.createElement('iframe'); - iframe.src = browser.runtime.getURL('build/console.html'); - iframe.id = 'vimvixen-console-frame'; - iframe.className = 'vimvixen-console-frame'; + const iframe = document.createElement("iframe"); + iframe.src = browser.runtime.getURL("build/console.html"); + iframe.id = "vimvixen-console-frame"; + iframe.className = "vimvixen-console-frame"; document.body.append(iframe); } blur(): void { - const ele = document.getElementById('vimvixen-console-frame'); + const ele = document.getElementById("vimvixen-console-frame"); if (!ele) { - throw new Error('console frame not created'); + throw new Error("console frame not created"); } ele.blur(); } diff --git a/src/content/presenters/FindPresenter.ts b/src/content/presenters/FindPresenter.ts index 98d8088..117142c 100644 --- a/src/content/presenters/FindPresenter.ts +++ b/src/content/presenters/FindPresenter.ts @@ -1,4 +1,3 @@ - export default interface FindPresenter { find(keyword: string, backwards: boolean): boolean; @@ -18,7 +17,8 @@ interface MyWindow extends Window { aWrapAround?: boolean, aWholeWord?: boolean, aSearchInFrames?: boolean, - aShowDialog?: boolean): boolean; + aShowDialog?: boolean + ): boolean; } // eslint-disable-next-line no-var, vars-on-top, init-declarations @@ -29,7 +29,6 @@ export class FindPresenterImpl implements FindPresenter { const caseSensitive = false; const wrapScan = true; - // NOTE: aWholeWord dows not implemented, and aSearchInFrames does not work // because of same origin policy const found = window.find(keyword, caseSensitive, backwards, wrapScan); diff --git a/src/content/presenters/FocusPresenter.ts b/src/content/presenters/FocusPresenter.ts index 842c41e..4d70a6e 100644 --- a/src/content/presenters/FocusPresenter.ts +++ b/src/content/presenters/FocusPresenter.ts @@ -1,4 +1,4 @@ -import * as doms from '../../shared/utils/dom'; +import * as doms from "../../shared/utils/dom"; export default interface FocusPresenter { focusFirstElement(): boolean; @@ -6,9 +6,13 @@ export default interface FocusPresenter { export class FocusPresenterImpl implements FocusPresenter { focusFirstElement(): boolean { - const inputTypes = ['email', 'number', 'search', 'tel', 'text', 'url']; - const inputSelector = inputTypes.map(type => `input[type=${type}]`).join(','); - const targets = window.document.querySelectorAll(inputSelector + ',textarea'); + const inputTypes = ["email", "number", "search", "tel", "text", "url"]; + const inputSelector = inputTypes + .map((type) => `input[type=${type}]`) + .join(","); + const targets = window.document.querySelectorAll( + inputSelector + ",textarea" + ); const target = Array.from(targets).find(doms.isVisible); if (target instanceof HTMLInputElement) { target.focus(); @@ -20,4 +24,3 @@ export class FocusPresenterImpl implements FocusPresenter { return false; } } - diff --git a/src/content/presenters/FollowPresenter.ts b/src/content/presenters/FollowPresenter.ts index fef8140..8aef819 100644 --- a/src/content/presenters/FollowPresenter.ts +++ b/src/content/presenters/FollowPresenter.ts @@ -1,11 +1,18 @@ -import Hint, { InputHint, LinkHint } from './Hint'; -import * as doms from '../../shared/utils/dom'; +import Hint, { InputHint, LinkHint } from "./Hint"; +import * as doms from "../../shared/utils/dom"; const TARGET_SELECTOR = [ - 'a', 'button', 'input', 'textarea', 'area', - '[contenteditable=true]', '[contenteditable=""]', '[tabindex]', - '[role="button"]', 'summary' -].join(','); + "a", + "button", + "input", + "textarea", + "area", + "[contenteditable=true]", + '[contenteditable=""]', + "[tabindex]", + '[role="button"]', + "summary", +].join(","); interface Size { width: number; @@ -21,11 +28,9 @@ const inViewport = ( win: Window, element: Element, viewSize: Size, - framePosition: Point, + framePosition: Point ): boolean => { - const { - top, left, bottom, right - } = doms.viewportRect(element); + const { top, left, bottom, right } = doms.viewportRect(element); const doc = win.document; const frameWidth = doc.documentElement.clientWidth; const frameHeight = doc.documentElement.clientHeight; @@ -34,9 +39,12 @@ const inViewport = ( // out of frame return false; } - if (right + framePosition.x < 0 || bottom + framePosition.y < 0 || - left + framePosition.x > viewSize.width || - top + framePosition.y > viewSize.height) { + if ( + right + framePosition.x < 0 || + bottom + framePosition.y < 0 || + left + framePosition.x > viewSize.width || + top + framePosition.y > viewSize.height + ) { // out of viewport return false; } @@ -47,11 +55,11 @@ const isAriaHiddenOrAriaDisabled = (win: Window, element: Element): boolean => { if (!element || win.document.documentElement === element) { return false; } - for (const attr of ['aria-hidden', 'aria-disabled']) { + for (const attr of ["aria-hidden", "aria-disabled"]) { const value = element.getAttribute(attr); if (value !== null) { const hidden = value.toLowerCase(); - if (hidden === '' || hidden === 'true') { + if (hidden === "" || hidden === "true") { return true; } } @@ -88,8 +96,10 @@ export class FollowPresenterImpl implements FollowPresenter { const min = Math.min(targets.length, tags.length); for (let i = 0; i < min; ++i) { const target = targets[i]; - if (target instanceof HTMLAnchorElement || - target instanceof HTMLAreaElement) { + if ( + target instanceof HTMLAnchorElement || + target instanceof HTMLAreaElement + ) { this.hints.push(new LinkHint(target, tags[i])); } else { this.hints.push(new InputHint(target, tags[i])); @@ -98,35 +108,40 @@ export class FollowPresenterImpl implements FollowPresenter { } filterHints(prefix: string): void { - const shown = this.hints.filter(h => h.getTag().startsWith(prefix)); - const hidden = this.hints.filter(h => !h.getTag().startsWith(prefix)); + const shown = this.hints.filter((h) => h.getTag().startsWith(prefix)); + const hidden = this.hints.filter((h) => !h.getTag().startsWith(prefix)); - shown.forEach(h => h.show()); - hidden.forEach(h => h.hide()); + shown.forEach((h) => h.show()); + hidden.forEach((h) => h.hide()); } clearHints(): void { - this.hints.forEach(h => h.remove()); + this.hints.forEach((h) => h.remove()); this.hints = []; } getHint(tag: string): Hint | undefined { - return this.hints.find(h => h.getTag() === tag); + return this.hints.find((h) => h.getTag() === tag); } private getTargets(viewSize: Size, framePosition: Point): HTMLElement[] { const all = window.document.querySelectorAll(TARGET_SELECTOR); - const filtered = Array.prototype.filter.call(all, (element: HTMLElement) => { - const style = window.getComputedStyle(element); - - // AREA's 'display' in Browser style is 'none' - return (element.tagName === 'AREA' || style.display !== 'none') && - style.visibility !== 'hidden' && - (element as HTMLInputElement).type !== 'hidden' && - element.offsetHeight > 0 && - !isAriaHiddenOrAriaDisabled(window, element) && - inViewport(window, element, viewSize, framePosition); - }); + const filtered = Array.prototype.filter.call( + all, + (element: HTMLElement) => { + const style = window.getComputedStyle(element); + + // AREA's 'display' in Browser style is 'none' + return ( + (element.tagName === "AREA" || style.display !== "none") && + style.visibility !== "hidden" && + (element as HTMLInputElement).type !== "hidden" && + element.offsetHeight > 0 && + !isAriaHiddenOrAriaDisabled(window, element) && + inViewport(window, element, viewSize, framePosition) + ); + } + ); return filtered; } } diff --git a/src/content/presenters/Hint.ts b/src/content/presenters/Hint.ts index 44b8185..3f39060 100644 --- a/src/content/presenters/Hint.ts +++ b/src/content/presenters/Hint.ts @@ -1,4 +1,4 @@ -import * as doms from '../../shared/utils/dom'; +import * as doms from "../../shared/utils/dom"; interface Point { x: number; @@ -8,7 +8,7 @@ interface Point { const hintPosition = (element: Element): Point => { const { left, top, right, bottom } = doms.viewportRect(element); - if (element.tagName !== 'AREA') { + if (element.tagName !== "AREA") { return { x: left, y: top }; } @@ -28,17 +28,17 @@ export default abstract class Hint { const doc = target.ownerDocument; if (doc === null) { - throw new TypeError('ownerDocument is null'); + throw new TypeError("ownerDocument is null"); } const { x, y } = hintPosition(target); const { scrollX, scrollY } = window; - const hint = doc.createElement('span'); - hint.className = 'vimvixen-hint'; + const hint = doc.createElement("span"); + hint.className = "vimvixen-hint"; hint.textContent = tag; - hint.style.left = x + scrollX + 'px'; - hint.style.top = y + scrollY + 'px'; + hint.style.left = x + scrollX + "px"; + hint.style.top = y + scrollY + "px"; doc.body.append(hint); @@ -47,11 +47,11 @@ export default abstract class Hint { } show(): void { - this.hint.style.display = 'inline'; + this.hint.style.display = "inline"; } hide(): void { - this.hint.style.display = 'none'; + this.hint.style.display = "none"; } remove(): void { @@ -77,7 +77,7 @@ export class LinkHint extends Hint { } getLinkTarget(): string | null { - return this.target.getAttribute('target'); + return this.target.getAttribute("target"); } click(): void { @@ -97,31 +97,31 @@ export class InputHint extends Hint { activate(): void { const target = this.target; switch (target.tagName.toLowerCase()) { - case 'input': - switch ((target as HTMLInputElement).type) { - case 'file': - case 'checkbox': - case 'radio': - case 'submit': - case 'reset': - case 'button': - case 'image': - case 'color': - return target.click(); - default: + case "input": + switch ((target as HTMLInputElement).type) { + case "file": + case "checkbox": + case "radio": + case "submit": + case "reset": + case "button": + case "image": + case "color": + return target.click(); + default: + return target.focus(); + } + case "textarea": return target.focus(); - } - case 'textarea': - return target.focus(); - case 'button': - case 'summary': - return target.click(); - default: - if (doms.isContentEditable(target)) { - return target.focus(); - } else if (target.hasAttribute('tabindex')) { + case "button": + case "summary": return target.click(); - } + default: + if (doms.isContentEditable(target)) { + return target.focus(); + } else if (target.hasAttribute("tabindex")) { + return target.click(); + } } } } diff --git a/src/content/presenters/NavigationPresenter.ts b/src/content/presenters/NavigationPresenter.ts index 951e62a..3edcd12 100644 --- a/src/content/presenters/NavigationPresenter.ts +++ b/src/content/presenters/NavigationPresenter.ts @@ -8,7 +8,7 @@ export default interface NavigationPresenter { openLinkNext(): void; } -const REL_PATTERN: {[key: string]: RegExp} = { +const REL_PATTERN: { [key: string]: RegExp } = { prev: /^(?:prev(?:ious)?|older)\b|\u2039|\u2190|\xab|\u226a|<</i, next: /^(?:next|newer)\b|\u203a|\u2192|\xbb|\u226b|>>/i, }; @@ -18,7 +18,7 @@ const REL_PATTERN: {[key: string]: RegExp} = { // eslint-disable-next-line func-style function selectLast<E extends Element>( selector: string, - filter?: (e: E) => boolean, + filter?: (e: E) => boolean ): E | null { let nodes = Array.from( window.document.querySelectorAll(selector) as NodeListOf<E> @@ -40,15 +40,15 @@ export class NavigationPresenterImpl implements NavigationPresenter { } openLinkPrev(): void { - this.linkRel('prev'); + this.linkRel("prev"); } openLinkNext(): void { - this.linkRel('next'); + this.linkRel("next"); } // Code common to linkPrev and linkNext which navigates to the specified page. - private linkRel(rel: 'prev' | 'next'): void { + private linkRel(rel: "prev" | "next"): void { const link = selectLast<HTMLLinkElement>(`link[rel~=${rel}][href]`); if (link) { window.location.href = link.href; @@ -57,10 +57,11 @@ export class NavigationPresenterImpl implements NavigationPresenter { const pattern = REL_PATTERN[rel]; - const a = selectLast<HTMLAnchorElement>(`a[rel~=${rel}][href]`) || - // `innerText` is much slower than `textContent`, but produces much better - // (i.e. less unexpected) results - selectLast('a[href]', lnk => pattern.test(lnk.innerText)); + const a = + selectLast<HTMLAnchorElement>(`a[rel~=${rel}][href]`) || + // `innerText` is much slower than `textContent`, but produces much better + // (i.e. less unexpected) results + selectLast("a[href]", (lnk) => pattern.test(lnk.innerText)); if (a) { a.click(); diff --git a/src/content/presenters/ScrollPresenter.ts b/src/content/presenters/ScrollPresenter.ts index 387ab62..f1a6402 100644 --- a/src/content/presenters/ScrollPresenter.ts +++ b/src/content/presenters/ScrollPresenter.ts @@ -1,4 +1,4 @@ -import * as doms from '../../shared/utils/dom'; +import * as doms from "../../shared/utils/dom"; const SCROLL_DELTA_X = 64; const SCROLL_DELTA_Y = 64; @@ -9,13 +9,19 @@ let lastTimeoutId: number | null = null; const isScrollableStyle = (element: Element): boolean => { const { overflowX, overflowY } = window.getComputedStyle(element); - return !(overflowX !== 'scroll' && overflowX !== 'auto' && - overflowY !== 'scroll' && overflowY !== 'auto'); + return !( + overflowX !== "scroll" && + overflowX !== "auto" && + overflowY !== "scroll" && + overflowY !== "auto" + ); }; const isOverflowed = (element: Element): boolean => { - return element.scrollWidth > element.clientWidth || - element.scrollHeight > element.clientHeight; + return ( + element.scrollWidth > element.clientWidth || + element.scrollHeight > element.clientHeight + ); }; // Find a visiable and scrollable element by depth-first search. Currently @@ -73,7 +79,7 @@ class Scroller { this.element.scrollTo({ left: x, top: y, - behavior: 'smooth', + behavior: "smooth", }); this.prepareReset(); } @@ -94,7 +100,7 @@ class Scroller { } } -export type Point = { x: number, y: number }; +export type Point = { x: number; y: number }; export default interface ScrollPresenter { getScroll(): Point; diff --git a/src/content/repositories/AddressRepository.ts b/src/content/repositories/AddressRepository.ts index 6f9487b..f200bf2 100644 --- a/src/content/repositories/AddressRepository.ts +++ b/src/content/repositories/AddressRepository.ts @@ -1,5 +1,5 @@ export default interface AddressRepository { - getCurrentURL(): URL + getCurrentURL(): URL; } export class AddressRepositoryImpl implements AddressRepository { diff --git a/src/content/repositories/ClipboardRepository.ts b/src/content/repositories/ClipboardRepository.ts index 8219835..a700543 100644 --- a/src/content/repositories/ClipboardRepository.ts +++ b/src/content/repositories/ClipboardRepository.ts @@ -6,39 +6,39 @@ export default interface ClipboardRepository { export class ClipboardRepositoryImpl { read(): string { - const textarea = window.document.createElement('textarea'); + const textarea = window.document.createElement("textarea"); window.document.body.append(textarea); - textarea.style.position = 'fixed'; - textarea.style.top = '-100px'; - textarea.contentEditable = 'true'; + textarea.style.position = "fixed"; + textarea.style.top = "-100px"; + textarea.contentEditable = "true"; textarea.focus(); - const ok = window.document.execCommand('paste'); + const ok = window.document.execCommand("paste"); const value = textarea.textContent!!; textarea.remove(); if (!ok) { - throw new Error('failed to access clipbaord'); + throw new Error("failed to access clipbaord"); } return value; } write(text: string): void { - const input = window.document.createElement('input'); + const input = window.document.createElement("input"); window.document.body.append(input); - input.style.position = 'fixed'; - input.style.top = '-100px'; + input.style.position = "fixed"; + input.style.top = "-100px"; input.value = text; input.select(); - const ok = window.document.execCommand('copy'); + const ok = window.document.execCommand("copy"); input.remove(); if (!ok) { - throw new Error('failed to access clipbaord'); + throw new Error("failed to access clipbaord"); } } } diff --git a/src/content/repositories/FollowMasterRepository.ts b/src/content/repositories/FollowMasterRepository.ts index da2402c..cc49e5f 100644 --- a/src/content/repositories/FollowMasterRepository.ts +++ b/src/content/repositories/FollowMasterRepository.ts @@ -35,7 +35,7 @@ export class FollowMasterRepositoryImpl implements FollowMasterRepository { } getTagsByPrefix(prefix: string): string[] { - return current.tags.filter(t => t.startsWith(prefix)); + return current.tags.filter((t) => t.startsWith(prefix)); } addTag(tag: string): void { @@ -54,4 +54,3 @@ export class FollowMasterRepositoryImpl implements FollowMasterRepository { return current.background; } } - diff --git a/src/content/repositories/FollowSlaveRepository.ts b/src/content/repositories/FollowSlaveRepository.ts index 42a0710..0dc9e89 100644 --- a/src/content/repositories/FollowSlaveRepository.ts +++ b/src/content/repositories/FollowSlaveRepository.ts @@ -25,5 +25,3 @@ export class FollowSlaveRepositoryImpl implements FollowSlaveRepository { return current.enabled; } } - - diff --git a/src/content/repositories/KeymapRepository.ts b/src/content/repositories/KeymapRepository.ts index 2944723..6a7d656 100644 --- a/src/content/repositories/KeymapRepository.ts +++ b/src/content/repositories/KeymapRepository.ts @@ -1,5 +1,5 @@ -import Key from '../../shared/settings/Key'; -import KeySequence from '../domains/KeySequence'; +import Key from "../../shared/settings/Key"; +import KeySequence from "../domains/KeySequence"; export default interface KeymapRepository { enqueueKey(key: Key): KeySequence; @@ -10,7 +10,6 @@ export default interface KeymapRepository { let current: KeySequence = new KeySequence([]); export class KeymapRepositoryImpl { - enqueueKey(key: Key): KeySequence { current.push(key); return current; diff --git a/src/content/repositories/MarkKeyRepository.ts b/src/content/repositories/MarkKeyRepository.ts index 18c3e23..c351c13 100644 --- a/src/content/repositories/MarkKeyRepository.ts +++ b/src/content/repositories/MarkKeyRepository.ts @@ -23,7 +23,6 @@ const current: Mode = { }; export class MarkKeyRepositoryImpl implements MarkKeyRepository { - isSetMode(): boolean { return current.setMode; } diff --git a/src/content/repositories/MarkRepository.ts b/src/content/repositories/MarkRepository.ts index afa980a..e48db25 100644 --- a/src/content/repositories/MarkRepository.ts +++ b/src/content/repositories/MarkRepository.ts @@ -1,4 +1,4 @@ -import Mark from '../domains/Mark'; +import Mark from "../domains/Mark"; export default interface MarkRepository { set(key: string, mark: Mark): void; @@ -6,7 +6,7 @@ export default interface MarkRepository { get(key: string): Mark | null; } -const saved: {[key: string]: Mark} = {}; +const saved: { [key: string]: Mark } = {}; export class MarkRepositoryImpl implements MarkRepository { set(key: string, mark: Mark): void { diff --git a/src/content/repositories/SettingRepository.ts b/src/content/repositories/SettingRepository.ts index 4ba26e0..1e393cd 100644 --- a/src/content/repositories/SettingRepository.ts +++ b/src/content/repositories/SettingRepository.ts @@ -1,4 +1,4 @@ -import Settings, { DefaultSetting } from '../../shared/settings/Settings'; +import Settings, { DefaultSetting } from "../../shared/settings/Settings"; let current: Settings = DefaultSetting; diff --git a/src/content/usecases/AddonEnabledUseCase.ts b/src/content/usecases/AddonEnabledUseCase.ts index 608a401..f7e78c5 100644 --- a/src/content/usecases/AddonEnabledUseCase.ts +++ b/src/content/usecases/AddonEnabledUseCase.ts @@ -1,18 +1,16 @@ -import { injectable, inject } from 'tsyringe'; -import AddonIndicatorClient from '../client/AddonIndicatorClient'; -import AddonEnabledRepository from '../repositories/AddonEnabledRepository'; +import { injectable, inject } from "tsyringe"; +import AddonIndicatorClient from "../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../repositories/AddonEnabledRepository"; @injectable() export default class AddonEnabledUseCase { - constructor( - @inject('AddonIndicatorClient') + @inject("AddonIndicatorClient") private indicator: AddonIndicatorClient, - @inject('AddonEnabledRepository') - private repository: AddonEnabledRepository, - ) { - } + @inject("AddonEnabledRepository") + private repository: AddonEnabledRepository + ) {} async enable(): Promise<void> { await this.setEnabled(true); diff --git a/src/content/usecases/ClipboardUseCase.ts b/src/content/usecases/ClipboardUseCase.ts index 7f16f68..875fc11 100644 --- a/src/content/usecases/ClipboardUseCase.ts +++ b/src/content/usecases/ClipboardUseCase.ts @@ -1,24 +1,23 @@ -import { injectable, inject } from 'tsyringe'; -import * as urls from '../../shared/urls'; -import ClipboardRepository from '../repositories/ClipboardRepository'; -import SettingRepository from '../repositories/SettingRepository'; -import ConsoleClient from '../client/ConsoleClient'; -import OperationClient from '../client/OperationClient'; +import { injectable, inject } from "tsyringe"; +import * as urls from "../../shared/urls"; +import ClipboardRepository from "../repositories/ClipboardRepository"; +import SettingRepository from "../repositories/SettingRepository"; +import ConsoleClient from "../client/ConsoleClient"; +import OperationClient from "../client/OperationClient"; @injectable() export default class ClipboardUseCase { constructor( - @inject('ClipboardRepository') private repository: ClipboardRepository, - @inject('SettingRepository') private settingRepository: SettingRepository, - @inject('ConsoleClient') private consoleClient: ConsoleClient, - @inject('OperationClient') private operationClinet: OperationClient, - ) { - } + @inject("ClipboardRepository") private repository: ClipboardRepository, + @inject("SettingRepository") private settingRepository: SettingRepository, + @inject("ConsoleClient") private consoleClient: ConsoleClient, + @inject("OperationClient") private operationClinet: OperationClient + ) {} async yankCurrentURL(): Promise<string> { const url = window.location.href; this.repository.write(url); - await this.consoleClient.info('Yanked ' + url); + await this.consoleClient.info("Yanked " + url); return Promise.resolve(url); } diff --git a/src/content/usecases/ConsoleFrameUseCase.ts b/src/content/usecases/ConsoleFrameUseCase.ts index 3c4b0a1..b118c7f 100644 --- a/src/content/usecases/ConsoleFrameUseCase.ts +++ b/src/content/usecases/ConsoleFrameUseCase.ts @@ -1,13 +1,12 @@ -import { injectable, inject } from 'tsyringe'; -import ConsoleFramePresenter from '../presenters/ConsoleFramePresenter'; +import { injectable, inject } from "tsyringe"; +import ConsoleFramePresenter from "../presenters/ConsoleFramePresenter"; @injectable() export default class ConsoleFrameUseCase { constructor( - @inject('ConsoleFramePresenter') - private consoleFramePresenter: ConsoleFramePresenter, - ) { - } + @inject("ConsoleFramePresenter") + private consoleFramePresenter: ConsoleFramePresenter + ) {} unfocus() { window.focus(); diff --git a/src/content/usecases/FindSlaveUseCase.ts b/src/content/usecases/FindSlaveUseCase.ts index 0a5c2ce..3b8c4b4 100644 --- a/src/content/usecases/FindSlaveUseCase.ts +++ b/src/content/usecases/FindSlaveUseCase.ts @@ -1,12 +1,11 @@ -import { injectable, inject } from 'tsyringe'; -import FindMasterClient from '../client/FindMasterClient'; +import { injectable, inject } from "tsyringe"; +import FindMasterClient from "../client/FindMasterClient"; @injectable() export default class FindSlaveUseCase { constructor( - @inject('FindMasterClient') private findMasterClient: FindMasterClient, - ) { - } + @inject("FindMasterClient") private findMasterClient: FindMasterClient + ) {} findNext() { this.findMasterClient.findNext(); diff --git a/src/content/usecases/FindUseCase.ts b/src/content/usecases/FindUseCase.ts index c6a478f..bff0eee 100644 --- a/src/content/usecases/FindUseCase.ts +++ b/src/content/usecases/FindUseCase.ts @@ -1,18 +1,17 @@ -import { injectable, inject } from 'tsyringe'; -import FindPresenter from '../presenters/FindPresenter'; -import FindRepository from '../repositories/FindRepository'; -import FindClient from '../client/FindClient'; -import ConsoleClient from '../client/ConsoleClient'; +import { injectable, inject } from "tsyringe"; +import FindPresenter from "../presenters/FindPresenter"; +import FindRepository from "../repositories/FindRepository"; +import FindClient from "../client/FindClient"; +import ConsoleClient from "../client/ConsoleClient"; @injectable() export default class FindUseCase { constructor( - @inject('FindPresenter') private presenter: FindPresenter, - @inject('FindRepository') private repository: FindRepository, - @inject('FindClient') private client: FindClient, - @inject('ConsoleClient') private consoleClient: ConsoleClient, - ) { - } + @inject("FindPresenter") private presenter: FindPresenter, + @inject("FindRepository") private repository: FindRepository, + @inject("FindClient") private client: FindClient, + @inject("ConsoleClient") private consoleClient: ConsoleClient + ) {} async startFind(keyword?: string): Promise<void> { this.presenter.clearSelection(); @@ -36,18 +35,16 @@ export default class FindUseCase { return this.findNextPrev(true); } - private async findNextPrev( - backwards: boolean, - ): Promise<void> { + private async findNextPrev(backwards: boolean): Promise<void> { const keyword = await this.getKeyword(); if (!keyword) { return this.showNoLastKeywordError(); } const found = this.presenter.find(keyword, backwards); if (found) { - this.consoleClient.info('Pattern found: ' + keyword); + this.consoleClient.info("Pattern found: " + keyword); } else { - this.consoleClient.error('Pattern not found: ' + keyword); + this.consoleClient.error("Pattern not found: " + keyword); } } @@ -65,6 +62,6 @@ export default class FindUseCase { } private async showNoLastKeywordError(): Promise<void> { - await this.consoleClient.error('No previous search keywords'); + await this.consoleClient.error("No previous search keywords"); } } diff --git a/src/content/usecases/FocusUseCase.ts b/src/content/usecases/FocusUseCase.ts index 0158672..8c62003 100644 --- a/src/content/usecases/FocusUseCase.ts +++ b/src/content/usecases/FocusUseCase.ts @@ -1,12 +1,9 @@ -import { injectable, inject } from 'tsyringe'; -import FocusPresenter from '../presenters/FocusPresenter'; +import { injectable, inject } from "tsyringe"; +import FocusPresenter from "../presenters/FocusPresenter"; @injectable() export default class FocusUseCases { - constructor( - @inject('FocusPresenter') private presenter: FocusPresenter, - ) { - } + constructor(@inject("FocusPresenter") private presenter: FocusPresenter) {} focusFirstInput() { this.presenter.focusFirstElement(); diff --git a/src/content/usecases/FollowMasterUseCase.ts b/src/content/usecases/FollowMasterUseCase.ts index 0e7f394..329f05a 100644 --- a/src/content/usecases/FollowMasterUseCase.ts +++ b/src/content/usecases/FollowMasterUseCase.ts @@ -1,10 +1,10 @@ -import { injectable, inject } from 'tsyringe'; -import FollowKeyRepository from '../repositories/FollowKeyRepository'; -import FollowMasterRepository from '../repositories/FollowMasterRepository'; -import FollowSlaveClient from '../client/FollowSlaveClient'; -import FollowSlaveClientFactory from '../client/FollowSlaveClientFactory'; -import SettingRepository from '../repositories/SettingRepository'; -import HintKeyProducer from './HintKeyProducer'; +import { injectable, inject } from "tsyringe"; +import FollowKeyRepository from "../repositories/FollowKeyRepository"; +import FollowMasterRepository from "../repositories/FollowMasterRepository"; +import FollowSlaveClient from "../client/FollowSlaveClient"; +import FollowSlaveClientFactory from "../client/FollowSlaveClientFactory"; +import SettingRepository from "../repositories/SettingRepository"; +import HintKeyProducer from "./HintKeyProducer"; @injectable() export default class FollowMasterUseCase { @@ -12,17 +12,17 @@ export default class FollowMasterUseCase { private producer: HintKeyProducer | null; constructor( - @inject('FollowKeyRepository') + @inject("FollowKeyRepository") private followKeyRepository: FollowKeyRepository, - @inject('FollowMasterRepository') + @inject("FollowMasterRepository") private followMasterRepository: FollowMasterRepository, - @inject('SettingRepository') + @inject("SettingRepository") private settingRepository: SettingRepository, - @inject('FollowSlaveClientFactory') - private followSlaveClientFactory: FollowSlaveClientFactory, + @inject("FollowSlaveClientFactory") + private followSlaveClientFactory: FollowSlaveClientFactory ) { this.producer = null; } @@ -36,19 +36,21 @@ export default class FollowMasterUseCase { const viewWidth = window.top.innerWidth; const viewHeight = window.top.innerHeight; - this.followSlaveClientFactory.create(window.top).requestHintCount( - { width: viewWidth, height: viewHeight }, - { x: 0, y: 0 }, - ); + this.followSlaveClientFactory + .create(window.top) + .requestHintCount( + { width: viewWidth, height: viewHeight }, + { x: 0, y: 0 } + ); - const frameElements = window.document.querySelectorAll('iframe'); + const frameElements = window.document.querySelectorAll("iframe"); for (let i = 0; i < frameElements.length; ++i) { const ele = frameElements[i] as HTMLFrameElement | HTMLIFrameElement; const { left: frameX, top: frameY } = ele.getBoundingClientRect(); const client = this.followSlaveClientFactory.create(ele.contentWindow!!); client.requestHintCount( { width: viewWidth, height: viewHeight }, - { x: frameX, y: frameY }, + { x: frameX, y: frameY } ); } } @@ -67,8 +69,10 @@ export default class FollowMasterUseCase { const viewHeight = window.innerHeight || doc.documentElement.clientHeight; let pos = { x: 0, y: 0 }; if (sender !== window) { - const frameElements = window.document.querySelectorAll('iframe'); - const ele = Array.from(frameElements).find(e => e.contentWindow === sender); + const frameElements = window.document.querySelectorAll("iframe"); + const ele = Array.from(frameElements).find( + (e) => e.contentWindow === sender + ); if (!ele) { // elements of the sender is gone return; @@ -77,11 +81,7 @@ export default class FollowMasterUseCase { pos = { x: frameX, y: frameY }; } const client = this.followSlaveClientFactory.create(sender); - client.createHints( - { width: viewWidth, height: viewHeight }, - pos, - produced, - ); + client.createHints({ width: viewWidth, height: viewHeight }, pos, produced); } cancelFollow(): void { @@ -110,17 +110,17 @@ export default class FollowMasterUseCase { enqueue(key: string): void { switch (key) { - case 'Enter': - this.activate(this.getCurrentTag()); - return; - case 'Esc': - this.cancelFollow(); - return; - case 'Backspace': - case 'Delete': - this.followKeyRepository.popKey(); - this.filter(this.getCurrentTag()); - return; + case "Enter": + this.activate(this.getCurrentTag()); + return; + case "Esc": + this.cancelFollow(); + return; + case "Backspace": + case "Delete": + this.followKeyRepository.popKey(); + this.filter(this.getCurrentTag()); + return; } this.followKeyRepository.pushKey(key); @@ -138,13 +138,15 @@ export default class FollowMasterUseCase { private broadcastToSlaves(handler: (client: FollowSlaveClient) => void) { const allFrames = [window.self].concat(Array.from(window.frames as any)); - const clients = allFrames.map(w => this.followSlaveClientFactory.create(w)); + const clients = allFrames.map((w) => + this.followSlaveClientFactory.create(w) + ); for (const client of clients) { handler(client); } } private getCurrentTag(): string { - return this.followKeyRepository.getKeys().join(''); + return this.followKeyRepository.getKeys().join(""); } } diff --git a/src/content/usecases/FollowSlaveUseCase.ts b/src/content/usecases/FollowSlaveUseCase.ts index fb805b9..971ecee 100644 --- a/src/content/usecases/FollowSlaveUseCase.ts +++ b/src/content/usecases/FollowSlaveUseCase.ts @@ -1,10 +1,10 @@ -import { injectable, inject } from 'tsyringe'; -import FollowSlaveRepository from '../repositories/FollowSlaveRepository'; -import FollowPresenter from '../presenters/FollowPresenter'; -import TabsClient from '../client/TabsClient'; -import FollowMasterClient from '../client/FollowMasterClient'; -import { LinkHint, InputHint } from '../presenters/Hint'; -import Key from '../../shared/settings/Key'; +import { injectable, inject } from "tsyringe"; +import FollowSlaveRepository from "../repositories/FollowSlaveRepository"; +import FollowPresenter from "../presenters/FollowPresenter"; +import TabsClient from "../client/TabsClient"; +import FollowMasterClient from "../client/FollowMasterClient"; +import { LinkHint, InputHint } from "../presenters/Hint"; +import Key from "../../shared/settings/Key"; interface Size { width: number; @@ -19,19 +19,18 @@ interface Point { @injectable() export default class FollowSlaveUseCase { constructor( - @inject('FollowPresenter') + @inject("FollowPresenter") private presenter: FollowPresenter, - @inject('TabsClient') + @inject("TabsClient") private tabsClient: TabsClient, - @inject('FollowMasterClient') + @inject("FollowMasterClient") private followMasterClient: FollowMasterClient, - @inject('FollowSlaveRepository') - private followSlaveRepository: FollowSlaveRepository, - ) { - } + @inject("FollowSlaveRepository") + private followSlaveRepository: FollowSlaveRepository + ) {} countTargets(viewSize: Size, framePosition: Point): void { const count = this.presenter.getTargetCount(viewSize, framePosition); @@ -65,11 +64,11 @@ export default class FollowSlaveUseCase { const url = hint.getLink(); let openNewTab = newTab; // Open link by background script in order to prevent a popup block - if (hint.getLinkTarget() === '_blank') { + if (hint.getLinkTarget() === "_blank") { openNewTab = true; } // eslint-disable-next-line no-script-url - if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) { + if (!url || url === "#" || url.toLowerCase().startsWith("javascript:")) { return; } await this.tabsClient.openUrl(url, openNewTab, background); diff --git a/src/content/usecases/HintKeyProducer.ts b/src/content/usecases/HintKeyProducer.ts index 68f3fbd..a5e2877 100644 --- a/src/content/usecases/HintKeyProducer.ts +++ b/src/content/usecases/HintKeyProducer.ts @@ -5,7 +5,7 @@ export default class HintKeyProducer { constructor(charset: string) { if (charset.length === 0) { - throw new TypeError('charset is empty'); + throw new TypeError("charset is empty"); } this.charset = charset; @@ -15,12 +15,12 @@ export default class HintKeyProducer { produce(): string { this.increment(); - return this.counter.map(x => this.charset[x]).join(''); + return this.counter.map((x) => this.charset[x]).join(""); } private increment(): void { const max = this.charset.length - 1; - if (this.counter.every(x => x === max)) { + if (this.counter.every((x) => x === max)) { this.counter = new Array(this.counter.length + 1).fill(0); return; } @@ -35,4 +35,3 @@ export default class HintKeyProducer { this.counter.reverse(); } } - diff --git a/src/content/usecases/KeymapUseCase.ts b/src/content/usecases/KeymapUseCase.ts index e02bc48..3cbadcb 100644 --- a/src/content/usecases/KeymapUseCase.ts +++ b/src/content/usecases/KeymapUseCase.ts @@ -1,16 +1,16 @@ -import { injectable, inject } from 'tsyringe'; -import KeymapRepository from '../repositories/KeymapRepository'; -import SettingRepository from '../repositories/SettingRepository'; -import AddonEnabledRepository from '../repositories/AddonEnabledRepository'; -import * as operations from '../../shared/operations'; -import Keymaps from '../../shared/settings/Keymaps'; -import Key from '../../shared/settings/Key'; -import KeySequence from '../domains/KeySequence'; -import AddressRepository from '../repositories/AddressRepository'; +import { injectable, inject } from "tsyringe"; +import KeymapRepository from "../repositories/KeymapRepository"; +import SettingRepository from "../repositories/SettingRepository"; +import AddonEnabledRepository from "../repositories/AddonEnabledRepository"; +import * as operations from "../../shared/operations"; +import Keymaps from "../../shared/settings/Keymaps"; +import Key from "../../shared/settings/Key"; +import KeySequence from "../domains/KeySequence"; +import AddressRepository from "../repositories/AddressRepository"; const reservedKeymaps = Keymaps.fromJSON({ - '<Esc>': { type: operations.CANCEL }, - '<C-[>': { type: operations.CANCEL }, + "<Esc>": { type: operations.CANCEL }, + "<C-[>": { type: operations.CANCEL }, }); const enableAddonOps = [ @@ -21,22 +21,21 @@ const enableAddonOps = [ @injectable() export default class KeymapUseCase { constructor( - @inject('KeymapRepository') + @inject("KeymapRepository") private repository: KeymapRepository, - @inject('SettingRepository') + @inject("SettingRepository") private settingRepository: SettingRepository, - @inject('AddonEnabledRepository') + @inject("AddonEnabledRepository") private addonEnabledRepository: AddonEnabledRepository, - @inject('AddressRepository') - private addressRepository: AddressRepository, - ) { - } + @inject("AddressRepository") + private addressRepository: AddressRepository + ) {} // eslint-disable-next-line max-statements - nextOps(key: Key): { repeat: number, op: operations.Operation } | null { + nextOps(key: Key): { repeat: number; op: operations.Operation } | null { const sequence = this.repository.enqueueKey(key); const baseSequence = sequence.trimNumericPrefix(); const keymaps = this.keymapEntityMap(); @@ -49,14 +48,14 @@ export default class KeymapUseCase { return null; } - if (matched.length === 1 && - sequence.length() === matched[0][0].length()) { + if (matched.length === 1 && sequence.length() === matched[0][0].length()) { // keys are matched with an operation this.repository.clear(); return { repeat: 1, op: matched[0][1] }; } else if ( baseMatched.length === 1 && - baseSequence.length() === baseMatched[0][0].length()) { + baseSequence.length() === baseMatched[0][0].length() + ) { // keys are matched with an operation with a numeric prefix this.repository.clear(); return { repeat: sequence.repeatCount(), op: baseMatched[0][1] }; @@ -75,15 +74,20 @@ export default class KeymapUseCase { } private keymapEntityMap(): [KeySequence, operations.Operation][] { - const keymaps = this.settingRepository.get().keymaps.combine(reservedKeymaps); - let entries = keymaps.entries().map( - ([keys, op]) => [KeySequence.fromMapKeys(keys), op] - ) as [KeySequence, operations.Operation][]; + const keymaps = this.settingRepository + .get() + .keymaps.combine(reservedKeymaps); + let entries = keymaps + .entries() + .map(([keys, op]) => [KeySequence.fromMapKeys(keys), op]) as [ + KeySequence, + operations.Operation + ][]; if (!this.addonEnabledRepository.get()) { // available keymaps are only ADDON_ENABLE and ADDON_TOGGLE_ENABLED if // the addon disabled - entries = entries.filter( - ([_seq, { type }]) => enableAddonOps.includes(type) + entries = entries.filter(([_seq, { type }]) => + enableAddonOps.includes(type) ); } return entries; diff --git a/src/content/usecases/MarkKeyUseCase.ts b/src/content/usecases/MarkKeyUseCase.ts index 6cef6f2..b807c74 100644 --- a/src/content/usecases/MarkKeyUseCase.ts +++ b/src/content/usecases/MarkKeyUseCase.ts @@ -1,12 +1,11 @@ -import { injectable, inject } from 'tsyringe'; -import MarkKeyRepository from '../repositories/MarkKeyRepository'; +import { injectable, inject } from "tsyringe"; +import MarkKeyRepository from "../repositories/MarkKeyRepository"; @injectable() export default class MarkKeyUseCase { constructor( - @inject('MarkKeyRepository') private repository: MarkKeyRepository, - ) { - } + @inject("MarkKeyRepository") private repository: MarkKeyRepository + ) {} isSetMode(): boolean { return this.repository.isSetMode(); diff --git a/src/content/usecases/MarkUseCase.ts b/src/content/usecases/MarkUseCase.ts index 8cd0c72..002fdee 100644 --- a/src/content/usecases/MarkUseCase.ts +++ b/src/content/usecases/MarkUseCase.ts @@ -1,20 +1,19 @@ -import { injectable, inject } from 'tsyringe'; -import ScrollPresenter from '../presenters/ScrollPresenter'; -import MarkClient from '../client/MarkClient'; -import MarkRepository from '../repositories/MarkRepository'; -import SettingRepository from '../repositories/SettingRepository'; -import ConsoleClient from '../client/ConsoleClient'; +import { injectable, inject } from "tsyringe"; +import ScrollPresenter from "../presenters/ScrollPresenter"; +import MarkClient from "../client/MarkClient"; +import MarkRepository from "../repositories/MarkRepository"; +import SettingRepository from "../repositories/SettingRepository"; +import ConsoleClient from "../client/ConsoleClient"; @injectable() export default class MarkUseCase { constructor( - @inject('ScrollPresenter') private scrollPresenter: ScrollPresenter, - @inject('MarkClient') private client: MarkClient, - @inject('MarkRepository') private repository: MarkRepository, - @inject('SettingRepository') private settingRepository: SettingRepository, - @inject('ConsoleClient') private consoleClient: ConsoleClient, - ) { - } + @inject("ScrollPresenter") private scrollPresenter: ScrollPresenter, + @inject("MarkClient") private client: MarkClient, + @inject("MarkRepository") private repository: MarkRepository, + @inject("SettingRepository") private settingRepository: SettingRepository, + @inject("ConsoleClient") private consoleClient: ConsoleClient + ) {} async set(key: string): Promise<void> { const pos = this.scrollPresenter.getScroll(); @@ -33,7 +32,7 @@ export default class MarkUseCase { } else { const pos = this.repository.get(key); if (!pos) { - throw new Error('Mark is not set'); + throw new Error("Mark is not set"); } this.scroll(pos.x, pos.y); } @@ -45,6 +44,6 @@ export default class MarkUseCase { } private globalKey(key: string) { - return (/^[A-Z0-9]$/).test(key); + return /^[A-Z0-9]$/.test(key); } } diff --git a/src/content/usecases/NavigateUseCase.ts b/src/content/usecases/NavigateUseCase.ts index 7adccfd..c704980 100644 --- a/src/content/usecases/NavigateUseCase.ts +++ b/src/content/usecases/NavigateUseCase.ts @@ -1,13 +1,12 @@ -import { injectable, inject } from 'tsyringe'; -import NavigationPresenter from '../presenters/NavigationPresenter'; +import { injectable, inject } from "tsyringe"; +import NavigationPresenter from "../presenters/NavigationPresenter"; @injectable() export default class NavigateUseCase { constructor( - @inject('NavigationPresenter') - private navigationPresenter: NavigationPresenter, - ) { - } + @inject("NavigationPresenter") + private navigationPresenter: NavigationPresenter + ) {} openHistoryPrev(): void { this.navigationPresenter.openHistoryPrev(); diff --git a/src/content/usecases/ScrollUseCase.ts b/src/content/usecases/ScrollUseCase.ts index c68c889..319c8b4 100644 --- a/src/content/usecases/ScrollUseCase.ts +++ b/src/content/usecases/ScrollUseCase.ts @@ -1,14 +1,13 @@ -import { injectable, inject } from 'tsyringe'; -import ScrollPresenter from '../presenters/ScrollPresenter'; -import SettingRepository from '../repositories/SettingRepository'; +import { injectable, inject } from "tsyringe"; +import ScrollPresenter from "../presenters/ScrollPresenter"; +import SettingRepository from "../repositories/SettingRepository"; @injectable() export default class ScrollUseCase { constructor( - @inject('ScrollPresenter') private presenter: ScrollPresenter, - @inject('SettingRepository') private settingRepository: SettingRepository, - ) { - } + @inject("ScrollPresenter") private presenter: ScrollPresenter, + @inject("SettingRepository") private settingRepository: SettingRepository + ) {} scrollVertically(count: number): void { const smooth = this.getSmoothScroll(); diff --git a/src/content/usecases/SettingUseCase.ts b/src/content/usecases/SettingUseCase.ts index 67d1be6..b2b24aa 100644 --- a/src/content/usecases/SettingUseCase.ts +++ b/src/content/usecases/SettingUseCase.ts @@ -1,15 +1,14 @@ -import { injectable, inject } from 'tsyringe'; -import SettingRepository from '../repositories/SettingRepository'; -import SettingClient from '../client/SettingClient'; -import Settings from '../../shared/settings/Settings'; +import { injectable, inject } from "tsyringe"; +import SettingRepository from "../repositories/SettingRepository"; +import SettingClient from "../client/SettingClient"; +import Settings from "../../shared/settings/Settings"; @injectable() export default class SettingUseCase { constructor( - @inject('SettingRepository') private repository: SettingRepository, - @inject('SettingClient') private client: SettingClient, - ) { - } + @inject("SettingRepository") private repository: SettingRepository, + @inject("SettingClient") private client: SettingClient + ) {} async reload(): Promise<Settings> { const settings = await this.client.load(); diff --git a/src/settings/actions/index.ts b/src/settings/actions/index.ts index dfa41c4..6b06ef8 100644 --- a/src/settings/actions/index.ts +++ b/src/settings/actions/index.ts @@ -1,12 +1,14 @@ import { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; // Settings -export const SETTING_SET_SETTINGS = 'setting.set.settings'; -export const SETTING_SHOW_ERROR = 'setting.show.error'; -export const SETTING_SWITCH_TO_FORM = 'setting.switch.to.form'; -export const SETTING_SWITCH_TO_JSON = 'setting.switch.to.json'; +export const SETTING_SET_SETTINGS = "setting.set.settings"; +export const SETTING_SHOW_ERROR = "setting.show.error"; +export const SETTING_SWITCH_TO_FORM = "setting.switch.to.form"; +export const SETTING_SWITCH_TO_JSON = "setting.switch.to.json"; interface SettingSetSettingsAcion { type: typeof SETTING_SET_SETTINGS; @@ -23,14 +25,16 @@ interface SettingShowErrorAction { interface SettingSwitchToFormAction { type: typeof SETTING_SWITCH_TO_FORM; - form: FormSettings, + form: FormSettings; } interface SettingSwitchToJsonAction { type: typeof SETTING_SWITCH_TO_JSON; - json: JSONTextSettings, + json: JSONTextSettings; } export type SettingAction = - SettingSetSettingsAcion | SettingShowErrorAction | - SettingSwitchToFormAction | SettingSwitchToJsonAction; + | SettingSetSettingsAcion + | SettingShowErrorAction + | SettingSwitchToFormAction + | SettingSwitchToJsonAction; diff --git a/src/settings/actions/setting.ts b/src/settings/actions/setting.ts index 93ca5f8..e880ae4 100644 --- a/src/settings/actions/setting.ts +++ b/src/settings/actions/setting.ts @@ -1,15 +1,17 @@ -import * as actions from './index'; -import * as storages from '../storage'; +import * as actions from "./index"; +import * as storages from "../storage"; import SettingData, { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; -const load = async(): Promise<actions.SettingAction> => { +const load = async (): Promise<actions.SettingAction> => { const data = await storages.load(); return set(data); }; -const save = async(data: SettingData): Promise<actions.SettingAction> => { +const save = async (data: SettingData): Promise<actions.SettingAction> => { try { if (data.getSource() === SettingSource.JSON) { // toSettings exercise validation @@ -26,7 +28,6 @@ const save = async(data: SettingData): Promise<actions.SettingAction> => { return set(data); }; - const switchToForm = (json: JSONTextSettings): actions.SettingAction => { try { // toSettings exercise validation @@ -55,18 +56,18 @@ const switchToJson = (form: FormSettings): actions.SettingAction => { const set = (data: SettingData): actions.SettingAction => { const source = data.getSource(); switch (source) { - case SettingSource.JSON: - return { - type: actions.SETTING_SET_SETTINGS, - source: source, - json: data.getJSON(), - }; - case SettingSource.Form: - return { - type: actions.SETTING_SET_SETTINGS, - source: source, - form: data.getForm(), - }; + case SettingSource.JSON: + return { + type: actions.SETTING_SET_SETTINGS, + source: source, + json: data.getJSON(), + }; + case SettingSource.Form: + return { + type: actions.SETTING_SET_SETTINGS, + source: source, + form: data.getForm(), + }; } throw new Error(`unknown source: ${source}`); }; diff --git a/src/settings/components/form/BlacklistForm.tsx b/src/settings/components/form/BlacklistForm.tsx index 51c32f4..859cb9f 100644 --- a/src/settings/components/form/BlacklistForm.tsx +++ b/src/settings/components/form/BlacklistForm.tsx @@ -1,8 +1,8 @@ -import './BlacklistForm.scss'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import React from 'react'; -import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist'; +import "./BlacklistForm.scss"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import React from "react"; +import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; interface Props { value: Blacklist; @@ -18,45 +18,56 @@ class BlacklistForm extends React.Component<Props> { }; render() { - return <div className='form-blacklist-form'> - { - this.props.value.items.map((item, index) => { + return ( + <div className="form-blacklist-form"> + {this.props.value.items.map((item, index) => { if (item.partial) { return null; } - return <div key={index} className='form-blacklist-form-row'> - <input data-index={index} type='text' name='url' - className='column-url' value={item.pattern} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + return ( + <div key={index} className="form-blacklist-form-row"> + <input + data-index={index} + type="text" + name="url" + className="column-url" + value={item.pattern} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + </div> + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } bindValue(e: any) { const name = e.target.name; - const index = e.target.getAttribute('data-index'); + const index = e.target.getAttribute("data-index"); const items = this.props.value.items; - if (name === 'url') { + if (name === "url") { items[index] = new BlacklistItem(e.target.value, false, []); - } else if (name === 'add') { - items.push(new BlacklistItem('', false, [])); - } else if (name === 'delete') { + } else if (name === "add") { + items.push(new BlacklistItem("", false, [])); + } else if (name === "delete") { items.splice(index, 1); } this.props.onChange(new Blacklist(items)); - if (name === 'delete') { + if (name === "delete") { this.props.onBlur(); } } diff --git a/src/settings/components/form/KeymapsForm.tsx b/src/settings/components/form/KeymapsForm.tsx index dc74de3..b9af0df 100644 --- a/src/settings/components/form/KeymapsForm.tsx +++ b/src/settings/components/form/KeymapsForm.tsx @@ -1,8 +1,8 @@ -import './KeymapsForm.scss'; -import React from 'react'; -import Input from '../ui/Input'; -import keymaps from '../../keymaps'; -import { FormKeymaps } from '../../../shared/SettingData'; +import "./KeymapsForm.scss"; +import React from "react"; +import Input from "../ui/Input"; +import keymaps from "../../keymaps"; +import { FormKeymaps } from "../../../shared/SettingData"; interface Props { value: FormKeymaps; @@ -19,25 +19,31 @@ class KeymapsForm extends React.Component<Props> { render() { const values = this.props.value.toJSON(); - return <div className='form-keymaps-form'> - { - keymaps.fields.map((group, index) => { - return <div key={index} className='form-keymaps-form-field-group'> - { - group.map(([name, label]) => { - const value = values[name] || ''; - return <Input - type='text' id={name} name={name} key={name} - label={label} value={value} - onValueChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - />; - }) - } - </div>; - }) - } - </div>; + return ( + <div className="form-keymaps-form"> + {keymaps.fields.map((group, index) => { + return ( + <div key={index} className="form-keymaps-form-field-group"> + {group.map(([name, label]) => { + const value = values[name] || ""; + return ( + <Input + type="text" + id={name} + name={name} + key={name} + label={label} + value={value} + onValueChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + ); + })} + </div> + ); + })} + </div> + ); } bindValue(name: string, value: string) { diff --git a/src/settings/components/form/PartialBlacklistForm.tsx b/src/settings/components/form/PartialBlacklistForm.tsx index 1807e28..95beee8 100644 --- a/src/settings/components/form/PartialBlacklistForm.tsx +++ b/src/settings/components/form/PartialBlacklistForm.tsx @@ -1,8 +1,8 @@ -import './PartialBlacklistForm.scss'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import React from 'react'; -import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist'; +import "./PartialBlacklistForm.scss"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import React from "react"; +import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; interface Props { value: Blacklist; @@ -18,59 +18,77 @@ class PartialBlacklistForm extends React.Component<Props> { }; render() { - return <div className='form-partial-blacklist-form'> - <div className='form-partial-blacklist-form-header'> - <div className='column-url'>URL</div> - <div className='column-keys'>Keys</div> - </div> - { - this.props.value.items.map((item, index) => { + return ( + <div className="form-partial-blacklist-form"> + <div className="form-partial-blacklist-form-header"> + <div className="column-url">URL</div> + <div className="column-keys">Keys</div> + </div> + {this.props.value.items.map((item, index) => { if (!item.partial) { return null; } - return <div key={index} className='form-partial-blacklist-form-row'> - <input data-index={index} type='text' name='url' - className='column-url' value={item.pattern} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <input data-index={index} type='text' name='keys' - className='column-keys' value={item.keys.join(',')} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + return ( + <div key={index} className="form-partial-blacklist-form-row"> + <input + data-index={index} + type="text" + name="url" + className="column-url" + value={item.pattern} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <input + data-index={index} + type="text" + name="keys" + className="column-keys" + value={item.keys.join(",")} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + </div> + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } bindValue(e: any) { const name = e.target.name; - const index = e.target.getAttribute('data-index'); + const index = e.target.getAttribute("data-index"); const items = this.props.value.items; - if (name === 'url') { + if (name === "url") { const current = items[index]; items[index] = new BlacklistItem(e.target.value, true, current.keys); - } else if (name === 'keys') { + } else if (name === "keys") { const current = items[index]; items[index] = new BlacklistItem( - current.pattern, true, e.target.value.split(',')); - } else if (name === 'add') { - items.push(new BlacklistItem('', true, [])); - } else if (name === 'delete') { + current.pattern, + true, + e.target.value.split(",") + ); + } else if (name === "add") { + items.push(new BlacklistItem("", true, [])); + } else if (name === "delete") { items.splice(index, 1); } this.props.onChange(new Blacklist(items)); - if (name === 'delete') { + if (name === "delete") { this.props.onBlur(); } } diff --git a/src/settings/components/form/PropertiesForm.tsx b/src/settings/components/form/PropertiesForm.tsx index e648971..aebd9b1 100644 --- a/src/settings/components/form/PropertiesForm.tsx +++ b/src/settings/components/form/PropertiesForm.tsx @@ -1,9 +1,9 @@ -import './PropertiesForm.scss'; -import React from 'react'; +import "./PropertiesForm.scss"; +import React from "react"; interface Props { - types: {[key: string]: string}; - value: {[key: string]: any}; + types: { [key: string]: string }; + value: { [key: string]: any }; onChange: (value: any) => void; onBlur: () => void; } @@ -20,18 +20,18 @@ class PropertiesForm extends React.Component<Props> { const types = this.props.types; const values = this.props.value; - return <div className='form-properties-form'> - { - Object.keys(types).map((name) => { + return ( + <div className="form-properties-form"> + {Object.keys(types).map((name) => { const type = types[name]; - let inputType = ''; + let inputType = ""; let onChange = this.bindValue.bind(this); - if (type === 'string') { - inputType = 'text'; - } else if (type === 'number') { - inputType = 'number'; - } else if (type === 'boolean') { - inputType = 'checkbox'; + if (type === "string") { + inputType = "text"; + } else if (type === "number") { + inputType = "number"; + } else if (type === "boolean") { + inputType = "checkbox"; // Settings are saved onBlur, but checkbox does not fire it onChange = (e) => { @@ -41,29 +41,33 @@ class PropertiesForm extends React.Component<Props> { } else { return null; } - return <div key={name} className='form-properties-form-row'> - <label> - <span className='column-name'>{name}</span> - <input type={inputType} name={name} - className='column-input' - value={values[name] ? values[name] : ''} - onChange={onChange} - onBlur={this.props.onBlur} - checked={values[name]} - /> - </label> - </div>; - }) - } - </div>; + return ( + <div key={name} className="form-properties-form-row"> + <label> + <span className="column-name">{name}</span> + <input + type={inputType} + name={name} + className="column-input" + value={values[name] ? values[name] : ""} + onChange={onChange} + onBlur={this.props.onBlur} + checked={values[name]} + /> + </label> + </div> + ); + })} + </div> + ); } bindValue(e: React.ChangeEvent<HTMLInputElement>) { const name = e.target.name; const next = { ...this.props.value }; - if (e.target.type.toLowerCase() === 'checkbox') { + if (e.target.type.toLowerCase() === "checkbox") { next[name] = e.target.checked; - } else if (e.target.type.toLowerCase() === 'number') { + } else if (e.target.type.toLowerCase() === "number") { next[name] = Number(e.target.value); } else { next[name] = e.target.value; diff --git a/src/settings/components/form/SearchForm.tsx b/src/settings/components/form/SearchForm.tsx index 5dc786b..a4d923d 100644 --- a/src/settings/components/form/SearchForm.tsx +++ b/src/settings/components/form/SearchForm.tsx @@ -1,8 +1,8 @@ -import './SearchForm.scss'; -import React from 'react'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import { FormSearch } from '../../../shared/SettingData'; +import "./SearchForm.scss"; +import React from "react"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import { FormSearch } from "../../../shared/SettingData"; interface Props { value: FormSearch; @@ -12,68 +12,88 @@ interface Props { class SearchForm extends React.Component<Props> { public static defaultProps: Props = { - value: FormSearch.fromJSON({ default: '', engines: []}), + value: FormSearch.fromJSON({ default: "", engines: [] }), onChange: () => {}, onBlur: () => {}, }; render() { const value = this.props.value.toJSON(); - return <div className='form-search-form'> - <div className='form-search-form-header'> - <div className='column-name'>Name</div> - <div className='column-url'>URL</div> - <div className='column-option'>Default</div> - </div> - { - value.engines.map((engine, index) => { - return <div key={index} className='form-search-form-row'> - <input data-index={index} type='text' name='name' - className='column-name' value={engine[0]} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <input data-index={index} type='text' name='url' - placeholder='http://example.com/?q={}' - className='column-url' value={engine[1]} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <div className='column-option'> - <input data-index={index} type='radio' name='default' - checked={value.default === engine[0]} - onChange={this.bindValue.bind(this)} /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} /> + return ( + <div className="form-search-form"> + <div className="form-search-form-header"> + <div className="column-name">Name</div> + <div className="column-url">URL</div> + <div className="column-option">Default</div> + </div> + {value.engines.map((engine, index) => { + return ( + <div key={index} className="form-search-form-row"> + <input + data-index={index} + type="text" + name="name" + className="column-name" + value={engine[0]} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <input + data-index={index} + type="text" + name="url" + placeholder="http://example.com/?q={}" + className="column-url" + value={engine[1]} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <div className="column-option"> + <input + data-index={index} + type="radio" + name="default" + checked={value.default === engine[0]} + onChange={this.bindValue.bind(this)} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + /> + </div> </div> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } // eslint-disable-next-line max-statements bindValue(e: any) { const value = this.props.value.toJSON(); const name = e.target.name; - const index = Number(e.target.getAttribute('data-index')); + const index = Number(e.target.getAttribute("data-index")); const next: typeof value = { default: value.default, engines: value.engines.slice(), }; - if (name === 'name') { + if (name === "name") { next.engines[index][0] = e.target.value; next.default = value.engines[index][0]; - } else if (name === 'url') { + } else if (name === "url") { next.engines[index][1] = e.target.value; - } else if (name === 'default') { + } else if (name === "default") { next.default = value.engines[index][0]; - } else if (name === 'add') { - next.engines.push(['', '']); - } else if (name === 'delete' && value.engines.length > 1) { + } else if (name === "add") { + next.engines.push(["", ""]); + } else if (name === "delete" && value.engines.length > 1) { next.engines.splice(index, 1); if (value.engines[index][0] === value.default) { const nextIndex = Math.min(index, next.engines.length - 1); @@ -82,7 +102,7 @@ class SearchForm extends React.Component<Props> { } this.props.onChange(FormSearch.fromJSON(next)); - if (name === 'delete' || name === 'default') { + if (name === "delete" || name === "default") { this.props.onBlur(); } } diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index f4f0326..5793a8f 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -1,32 +1,36 @@ -import './site.scss'; -import React from 'react'; -import { connect } from 'react-redux'; -import Input from './ui/Input'; -import SearchForm from './form/SearchForm'; -import KeymapsForm from './form/KeymapsForm'; -import BlacklistForm from './form/BlacklistForm'; -import PropertiesForm from './form/PropertiesForm'; -import PartialBlacklistForm from './form/PartialBlacklistForm'; -import * as settingActions from '../../settings/actions/setting'; +import "./site.scss"; +import React from "react"; +import { connect } from "react-redux"; +import Input from "./ui/Input"; +import SearchForm from "./form/SearchForm"; +import KeymapsForm from "./form/KeymapsForm"; +import BlacklistForm from "./form/BlacklistForm"; +import PropertiesForm from "./form/PropertiesForm"; +import PartialBlacklistForm from "./form/PartialBlacklistForm"; +import * as settingActions from "../../settings/actions/setting"; import SettingData, { - FormKeymaps, FormSearch, FormSettings, JSONTextSettings, -} from '../../shared/SettingData'; -import { State as AppState } from '../reducers/setting'; -import Properties from '../../shared/settings/Properties'; -import Blacklist from '../../shared/settings/Blacklist'; + FormKeymaps, + FormSearch, + FormSettings, + JSONTextSettings, +} from "../../shared/SettingData"; +import { State as AppState } from "../reducers/setting"; +import Properties from "../../shared/settings/Properties"; +import Blacklist from "../../shared/settings/Blacklist"; const DO_YOU_WANT_TO_CONTINUE = - 'Some settings in JSON can be lost when migrating. ' + - 'Do you want to continue?'; + "Some settings in JSON can be lost when migrating. " + + "Do you want to continue?"; type StateProps = ReturnType<typeof mapStateToProps>; interface DispatchProps { - dispatch: (action: any) => void, + dispatch: (action: any) => void; } -type Props = StateProps & DispatchProps & { - // FIXME - store: any; -}; +type Props = StateProps & + DispatchProps & { + // FIXME + store: any; + }; class SettingsComponent extends React.Component<Props> { componentDidMount() { @@ -34,97 +38,103 @@ class SettingsComponent extends React.Component<Props> { } renderFormFields(form: FormSettings) { - return <div> - <fieldset> - <legend>Keybindings</legend> - <KeymapsForm - value={form.keymaps} - onChange={this.bindKeymapsForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Search Engines</legend> - <SearchForm - value={form.search} - onChange={this.bindSearchForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Blacklist</legend> - <BlacklistForm - value={form.blacklist} - onChange={this.bindBlacklistForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Partial blacklist</legend> - <PartialBlacklistForm - value={form.blacklist} - onChange={this.bindBlacklistForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Properties</legend> - <PropertiesForm - types={Properties.types()} - value={form.properties.toJSON()} - onChange={this.bindPropertiesForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - </div>; + return ( + <div> + <fieldset> + <legend>Keybindings</legend> + <KeymapsForm + value={form.keymaps} + onChange={this.bindKeymapsForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Search Engines</legend> + <SearchForm + value={form.search} + onChange={this.bindSearchForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Blacklist</legend> + <BlacklistForm + value={form.blacklist} + onChange={this.bindBlacklistForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Partial blacklist</legend> + <PartialBlacklistForm + value={form.blacklist} + onChange={this.bindBlacklistForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Properties</legend> + <PropertiesForm + types={Properties.types()} + value={form.properties.toJSON()} + onChange={this.bindPropertiesForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + </div> + ); } renderJsonFields(json: JSONTextSettings, error: string) { - return <div> - <Input - type='textarea' - name='json' - label='Plain JSON' - spellCheck={false} - error={error} - onValueChange={this.bindJson.bind(this)} - onBlur={this.save.bind(this)} - value={json.toJSONText()} - /> - </div>; + return ( + <div> + <Input + type="textarea" + name="json" + label="Plain JSON" + spellCheck={false} + error={error} + onValueChange={this.bindJson.bind(this)} + onBlur={this.save.bind(this)} + value={json.toJSONText()} + /> + </div> + ); } render() { let fields = null; const disabled = this.props.error.length > 0; - if (this.props.source === 'form') { + if (this.props.source === "form") { fields = this.renderFormFields(this.props.form!!); - } else if (this.props.source === 'json') { + } else if (this.props.source === "json") { fields = this.renderJsonFields(this.props.json!!, this.props.error); } return ( <div> <h1>Configure Vim-Vixen</h1> - <form className='vimvixen-settings-form'> + <form className="vimvixen-settings-form"> <Input - type='radio' - id='setting-source-form' - name='source' - label='Use form' - checked={this.props.source === 'form'} - value='form' + type="radio" + id="setting-source-form" + name="source" + label="Use form" + checked={this.props.source === "form"} + value="form" onValueChange={this.bindSource.bind(this)} - disabled={disabled} /> + disabled={disabled} + /> <Input - type='radio' - name='source' - label='Use plain JSON' - checked={this.props.source === 'json'} - value='json' + type="radio" + name="source" + label="Use plain JSON" + checked={this.props.source === "json"} + value="json" onValueChange={this.bindSource.bind(this)} - disabled={disabled} /> - { fields } + disabled={disabled} + /> + {fields} </form> </div> ); @@ -142,7 +152,8 @@ class SettingsComponent extends React.Component<Props> { const data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithSearch( - FormSearch.fromJSON(value)), + FormSearch.fromJSON(value) + ), }); this.props.dispatch(settingActions.set(data)); } @@ -159,7 +170,8 @@ class SettingsComponent extends React.Component<Props> { const data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithProperties( - Properties.fromJSON(value)) + Properties.fromJSON(value) + ), }); this.props.dispatch(settingActions.set(data)); } @@ -174,27 +186,29 @@ class SettingsComponent extends React.Component<Props> { bindSource(_name: string, value: string) { const from = this.props.source; - if (from === 'form' && value === 'json') { - this.props.dispatch(settingActions.switchToJson( - this.props.form as FormSettings)); + if (from === "form" && value === "json") { + this.props.dispatch( + settingActions.switchToJson(this.props.form as FormSettings) + ); this.save(); - } else if (from === 'json' && value === 'form') { + } else if (from === "json" && value === "form") { const b = window.confirm(DO_YOU_WANT_TO_CONTINUE); if (!b) { this.forceUpdate(); return; } this.props.dispatch( - settingActions.switchToForm(this.props.json as JSONTextSettings)); + settingActions.switchToForm(this.props.json as JSONTextSettings) + ); this.save(); } } save() { const { source, json, form } = this.props.store.getState(); - this.props.dispatch(settingActions.save( - new SettingData({ source, json, form }), - )); + this.props.dispatch( + settingActions.save(new SettingData({ source, json, form })) + ); } } diff --git a/src/settings/components/ui/AddButton.tsx b/src/settings/components/ui/AddButton.tsx index bb76d08..c15a732 100644 --- a/src/settings/components/ui/AddButton.tsx +++ b/src/settings/components/ui/AddButton.tsx @@ -1,13 +1,18 @@ -import './AddButton.scss'; -import React from 'react'; +import "./AddButton.scss"; +import React from "react"; type Props = React.AllHTMLAttributes<HTMLInputElement>; class AddButton extends React.Component<Props> { render() { - return <input - className='ui-add-button' type='button' value='✚' - {...this.props} />; + return ( + <input + className="ui-add-button" + type="button" + value="✚" + {...this.props} + /> + ); } } diff --git a/src/settings/components/ui/DeleteButton.tsx b/src/settings/components/ui/DeleteButton.tsx index e666426..df8976e 100644 --- a/src/settings/components/ui/DeleteButton.tsx +++ b/src/settings/components/ui/DeleteButton.tsx @@ -1,13 +1,18 @@ -import './DeleteButton.scss'; -import React from 'react'; +import "./DeleteButton.scss"; +import React from "react"; type Props = React.AllHTMLAttributes<HTMLInputElement>; class DeleteButton extends React.Component<Props> { render() { - return <input - className='ui-delete-button' type='button' value='✖' - {...this.props} />; + return ( + <input + className="ui-delete-button" + type="button" + value="✖" + {...this.props} + /> + ); } } diff --git a/src/settings/components/ui/Input.tsx b/src/settings/components/ui/Input.tsx index 69c14b3..6819ddb 100644 --- a/src/settings/components/ui/Input.tsx +++ b/src/settings/components/ui/Input.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import './Input.scss'; +import React from "react"; +import "./Input.scss"; interface Props extends React.AllHTMLAttributes<HTMLElement> { name: string; @@ -13,66 +13,75 @@ interface Props extends React.AllHTMLAttributes<HTMLElement> { class Input extends React.Component<Props> { renderText(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label htmlFor={props.id}>{ props.label }</label> - <input - type='text' className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - </div>; + return ( + <div className="settings-ui-input"> + <label htmlFor={props.id}>{props.label}</label> + <input + type="text" + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + </div> + ); } renderRadio(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label> - <input - type='radio' className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - { props.label } - </label> - </div>; + return ( + <div className="settings-ui-input"> + <label> + <input + type="radio" + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + {props.label} + </label> + </div> + ); } renderTextArea(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label - htmlFor={props.id} - >{ props.label }</label> - <textarea - className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - <p className='settings-ui-input-error'>{ this.props.error }</p> - </div>; + return ( + <div className="settings-ui-input"> + <label htmlFor={props.id}>{props.label}</label> + <textarea + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + <p className="settings-ui-input-error">{this.props.error}</p> + </div> + ); } render() { const { type } = this.props; switch (this.props.type) { - case 'text': - return this.renderText(this.props); - case 'radio': - return this.renderRadio(this.props); - case 'textarea': - return this.renderTextArea(this.props); - default: - console.warn(`Unsupported input type ${type}`); + case "text": + return this.renderText(this.props); + case "radio": + return this.renderRadio(this.props); + case "textarea": + return this.renderTextArea(this.props); + default: + console.warn(`Unsupported input type ${type}`); } return null; } - bindOnChange(e: React.ChangeEvent<HTMLInputElement|HTMLTextAreaElement>) { + bindOnChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) { if (this.props.onValueChange) { this.props.onValueChange(e.target.name, e.target.value); } diff --git a/src/settings/index.tsx b/src/settings/index.tsx index cde4488..0d3364b 100644 --- a/src/settings/index.tsx +++ b/src/settings/index.tsx @@ -1,18 +1,15 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import SettingsComponent from './components'; -import reducer from './reducers/setting'; -import { Provider } from 'react-redux'; -import promise from 'redux-promise'; -import { createStore, applyMiddleware } from 'redux'; +import React from "react"; +import ReactDOM from "react-dom"; +import SettingsComponent from "./components"; +import reducer from "./reducers/setting"; +import { Provider } from "react-redux"; +import promise from "redux-promise"; +import { createStore, applyMiddleware } from "redux"; -const store = createStore( - reducer, - applyMiddleware(promise), -); +const store = createStore(reducer, applyMiddleware(promise)); -document.addEventListener('DOMContentLoaded', () => { - const wrapper = document.getElementById('vimvixen-settings'); +document.addEventListener("DOMContentLoaded", () => { + const wrapper = document.getElementById("vimvixen-settings"); ReactDOM.render( <Provider store={store}> <SettingsComponent store={store} /> diff --git a/src/settings/keymaps.ts b/src/settings/keymaps.ts index 24ba1a5..25c7a51 100644 --- a/src/settings/keymaps.ts +++ b/src/settings/keymaps.ts @@ -2,70 +2,79 @@ const fields = [ [ - ['scroll.vertically?{"count":1}', 'Scroll down'], - ['scroll.vertically?{"count":-1}', 'Scroll up'], - ['scroll.horizonally?{"count":-1}', 'Scroll left'], - ['scroll.horizonally?{"count":1}', 'Scroll right'], - ['scroll.home', 'Scroll to leftmost'], - ['scroll.end', 'Scroll to rightmost'], - ['scroll.top', 'Scroll to top'], - ['scroll.bottom', 'Scroll to bottom'], - ['scroll.pages?{"count":-0.5}', 'Scroll up by half of screen'], - ['scroll.pages?{"count":0.5}', 'Scroll down by half of screen'], - ['scroll.pages?{"count":-1}', 'Scroll up by a screen'], - ['scroll.pages?{"count":1}', 'Scroll down by a screen'], - ], [ - ['mark.set.prefix', 'Set mark at current position'], - ['mark.jump.prefix', 'Jump to the mark'], - ], [ - ['tabs.close?{"select":"right"}', 'Close a tab'], - ['tabs.close.right', 'Close all tabs to the right'], - ['tabs.reopen', 'Reopen closed tab'], - ['tabs.next', 'Select next tab'], - ['tabs.prev', 'Select prev tab'], - ['tabs.first', 'Select first tab'], - ['tabs.last', 'Select last tab'], - ['tabs.reload?{"cache":false}', 'Reload current tab'], - ['tabs.reload?{"cache":true}', 'Reload with no caches'], - ['tabs.pin.toggle', 'Toggle pinned state'], - ['tabs.duplicate', 'Duplicate a tab'], - ], [ - ['follow.start?{"newTab":false,"background":false}', 'Follow a link'], - ['follow.start?{"newTab":true,"background":false}', 'Follow a link in new tab'], - ['navigate.history.prev', 'Go back in histories'], - ['navigate.history.next', 'Go forward in histories'], - ['navigate.link.next', 'Open next link'], - ['navigate.link.prev', 'Open previous link'], - ['navigate.parent', 'Go to parent directory'], - ['navigate.root', 'Go to root directory'], - ['page.source', 'Open page source'], - ['page.home?{"newTab":false}', 'Open start page to current tab'], - ['page.home?{"newTab":true}', 'Open start page in new tab'], - ['focus.input', 'Focus input'], - ], [ - ['find.start', 'Start find mode'], - ['find.next', 'Find next word'], - ['find.prev', 'Find previous word'], - ], [ - ['command.show', 'Open console'], - ['command.show.open?{"alter":false}', 'Open URL'], - ['command.show.open?{"alter":true}', 'Alter URL'], - ['command.show.tabopen?{"alter":false}', 'Open URL in new tab'], - ['command.show.tabopen?{"alter":true}', 'Alter URL in new tab'], - ['command.show.winopen?{"alter":false}', 'Open URL in new window'], - ['command.show.winopen?{"alter":true}', 'Alter URL in new window'], - ['command.show.buffer', 'Open buffer command'], - ['command.show.addbookmark?{"alter":true}', 'Open addbookmark command'], - ], [ - ['addon.toggle.enabled', 'Enable or disable'], - ['urls.yank', 'Copy current URL'], - ['urls.paste?{"newTab":false}', 'Open clipboard\'s URL in current tab'], - ['urls.paste?{"newTab":true}', 'Open clipboard\'s URL in new tab'], - ['zoom.in', 'Zoom-in'], - ['zoom.out', 'Zoom-out'], - ['zoom.neutral', 'Reset zoom level'], - ['repeat.last', 'Repeat last change'], - ] + ['scroll.vertically?{"count":1}', "Scroll down"], + ['scroll.vertically?{"count":-1}', "Scroll up"], + ['scroll.horizonally?{"count":-1}', "Scroll left"], + ['scroll.horizonally?{"count":1}', "Scroll right"], + ["scroll.home", "Scroll to leftmost"], + ["scroll.end", "Scroll to rightmost"], + ["scroll.top", "Scroll to top"], + ["scroll.bottom", "Scroll to bottom"], + ['scroll.pages?{"count":-0.5}', "Scroll up by half of screen"], + ['scroll.pages?{"count":0.5}', "Scroll down by half of screen"], + ['scroll.pages?{"count":-1}', "Scroll up by a screen"], + ['scroll.pages?{"count":1}', "Scroll down by a screen"], + ], + [ + ["mark.set.prefix", "Set mark at current position"], + ["mark.jump.prefix", "Jump to the mark"], + ], + [ + ['tabs.close?{"select":"right"}', "Close a tab"], + ["tabs.close.right", "Close all tabs to the right"], + ["tabs.reopen", "Reopen closed tab"], + ["tabs.next", "Select next tab"], + ["tabs.prev", "Select prev tab"], + ["tabs.first", "Select first tab"], + ["tabs.last", "Select last tab"], + ['tabs.reload?{"cache":false}', "Reload current tab"], + ['tabs.reload?{"cache":true}', "Reload with no caches"], + ["tabs.pin.toggle", "Toggle pinned state"], + ["tabs.duplicate", "Duplicate a tab"], + ], + [ + ['follow.start?{"newTab":false,"background":false}', "Follow a link"], + [ + 'follow.start?{"newTab":true,"background":false}', + "Follow a link in new tab", + ], + ["navigate.history.prev", "Go back in histories"], + ["navigate.history.next", "Go forward in histories"], + ["navigate.link.next", "Open next link"], + ["navigate.link.prev", "Open previous link"], + ["navigate.parent", "Go to parent directory"], + ["navigate.root", "Go to root directory"], + ["page.source", "Open page source"], + ['page.home?{"newTab":false}', "Open start page to current tab"], + ['page.home?{"newTab":true}', "Open start page in new tab"], + ["focus.input", "Focus input"], + ], + [ + ["find.start", "Start find mode"], + ["find.next", "Find next word"], + ["find.prev", "Find previous word"], + ], + [ + ["command.show", "Open console"], + ['command.show.open?{"alter":false}', "Open URL"], + ['command.show.open?{"alter":true}', "Alter URL"], + ['command.show.tabopen?{"alter":false}', "Open URL in new tab"], + ['command.show.tabopen?{"alter":true}', "Alter URL in new tab"], + ['command.show.winopen?{"alter":false}', "Open URL in new window"], + ['command.show.winopen?{"alter":true}', "Alter URL in new window"], + ["command.show.buffer", "Open buffer command"], + ['command.show.addbookmark?{"alter":true}', "Open addbookmark command"], + ], + [ + ["addon.toggle.enabled", "Enable or disable"], + ["urls.yank", "Copy current URL"], + ['urls.paste?{"newTab":false}', "Open clipboard's URL in current tab"], + ['urls.paste?{"newTab":true}', "Open clipboard's URL in new tab"], + ["zoom.in", "Zoom-in"], + ["zoom.out", "Zoom-out"], + ["zoom.neutral", "Reset zoom level"], + ["repeat.last", "Repeat last change"], + ], ]; export default { diff --git a/src/settings/reducers/setting.ts b/src/settings/reducers/setting.ts index 804853f..31544bb 100644 --- a/src/settings/reducers/setting.ts +++ b/src/settings/reducers/setting.ts @@ -1,8 +1,10 @@ -import * as actions from '../actions'; +import * as actions from "../actions"; import { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; -import { DefaultSetting } from '../../shared/settings/Settings'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; +import { DefaultSetting } from "../../shared/settings/Settings"; export interface State { source: SettingSource; @@ -13,37 +15,41 @@ export interface State { const defaultState: State = { source: SettingSource.JSON, - json: JSONTextSettings.fromText(''), + json: JSONTextSettings.fromText(""), form: FormSettings.fromSettings(DefaultSetting), - error: '', + error: "", }; export default function reducer( state = defaultState, - action: actions.SettingAction, + action: actions.SettingAction ): State { switch (action.type) { - case actions.SETTING_SET_SETTINGS: - return { ...state, - source: action.source, - json: action.json, - form: action.form, - error: '', }; - case actions.SETTING_SHOW_ERROR: - return { ...state, - error: action.error, - json: action.json, }; - case actions.SETTING_SWITCH_TO_FORM: - return { ...state, - error: '', - source: SettingSource.Form, - form: action.form, }; - case actions.SETTING_SWITCH_TO_JSON: - return { ...state, - error: '', - source: SettingSource.JSON, - json: action.json, }; - default: - return state; + case actions.SETTING_SET_SETTINGS: + return { + ...state, + source: action.source, + json: action.json, + form: action.form, + error: "", + }; + case actions.SETTING_SHOW_ERROR: + return { ...state, error: action.error, json: action.json }; + case actions.SETTING_SWITCH_TO_FORM: + return { + ...state, + error: "", + source: SettingSource.Form, + form: action.form, + }; + case actions.SETTING_SWITCH_TO_JSON: + return { + ...state, + error: "", + source: SettingSource.JSON, + json: action.json, + }; + default: + return state; } } diff --git a/src/settings/storage.ts b/src/settings/storage.ts index 55cca96..da67ecc 100644 --- a/src/settings/storage.ts +++ b/src/settings/storage.ts @@ -1,22 +1,24 @@ -import SettingData, { DefaultSettingData } from '../shared/SettingData'; +import SettingData, { DefaultSettingData } from "../shared/SettingData"; -const loadSettingData = async(): Promise<SettingData> => { - const { settings: syncSettings } = await browser.storage.sync.get('settings'); +const loadSettingData = async (): Promise<SettingData> => { + const { settings: syncSettings } = await browser.storage.sync.get("settings"); if (syncSettings) { return SettingData.fromJSON(syncSettings as any); } - const { settings: localSettings } = await browser.storage.local.get('settings'); + const { settings: localSettings } = await browser.storage.local.get( + "settings" + ); if (localSettings) { return SettingData.fromJSON(localSettings as any); } - return DefaultSettingData + return DefaultSettingData; }; -export const load = async(): Promise<SettingData> => { +export const load = async (): Promise<SettingData> => { try { return loadSettingData(); } catch (e) { - console.error('unable to load settings', e); + console.error("unable to load settings", e); return DefaultSettingData; } }; diff --git a/src/shared/Command.ts b/src/shared/Command.ts index b8c21ce..05b8b83 100644 --- a/src/shared/Command.ts +++ b/src/shared/Command.ts @@ -1,40 +1,40 @@ export enum Command { - Open = "open", - TabOpen = "tabopen", - WindowOpen = "winopen", - Buffer = "buffer", - BufferDelete = "bdelete", - BufferDeleteForce = "bdelete!", - BuffersDelete = "bdeletes", - BuffersDeleteForce = "bdeletes!", - AddBookmark = "addbookmark", - Quit = "quit", - QuitAll = "quitall", - Set = "set", - Help = "help", + Open = "open", + TabOpen = "tabopen", + WindowOpen = "winopen", + Buffer = "buffer", + BufferDelete = "bdelete", + BufferDeleteForce = "bdelete!", + BuffersDelete = "bdeletes", + BuffersDeleteForce = "bdeletes!", + AddBookmark = "addbookmark", + Quit = "quit", + QuitAll = "quitall", + Set = "set", + Help = "help", } export namespace Command { export function members(): Command[] { return [ - Command.Open , - Command.TabOpen , - Command.WindowOpen , - Command.Buffer , - Command.BufferDelete , - Command.BufferDeleteForce , - Command.BuffersDelete , - Command.BuffersDeleteForce , - Command.AddBookmark , - Command.Quit , - Command.QuitAll , - Command.Set , - Command.Help , - ] + Command.Open, + Command.TabOpen, + Command.WindowOpen, + Command.Buffer, + Command.BufferDelete, + Command.BufferDeleteForce, + Command.BuffersDelete, + Command.BuffersDeleteForce, + Command.AddBookmark, + Command.Quit, + Command.QuitAll, + Command.Set, + Command.Help, + ]; } export function valueOf(value: string): Command { - const map = new Map(members().map(cmd => [cmd.toString(), cmd])); + const map = new Map(members().map((cmd) => [cmd.toString(), cmd])); const cmd = map.get(value); if (!cmd) { throw new Error(`unknown command '${value}`); diff --git a/src/shared/CompletionType.ts b/src/shared/CompletionType.ts index e104455..8ca04a7 100644 --- a/src/shared/CompletionType.ts +++ b/src/shared/CompletionType.ts @@ -4,4 +4,4 @@ enum CompletionType { Bookmarks, } -export default CompletionType;
\ No newline at end of file +export default CompletionType; diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index 5ad360e..a7bdf80 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -1,21 +1,21 @@ -import * as operations from './operations'; -import Settings, { DefaultSettingJSONText } from './settings/Settings'; -import Keymaps from './settings/Keymaps'; -import Search from './settings/Search'; -import Properties from './settings/Properties'; -import Blacklist from './settings/Blacklist'; +import * as operations from "./operations"; +import Settings, { DefaultSettingJSONText } from "./settings/Settings"; +import Keymaps from "./settings/Keymaps"; +import Search from "./settings/Search"; +import Properties from "./settings/Properties"; +import Blacklist from "./settings/Blacklist"; export class FormKeymaps { - private readonly data: {[op: string]: string}; + private readonly data: { [op: string]: string }; - private constructor(data: {[op: string]: string}) { + private constructor(data: { [op: string]: string }) { this.data = data; } toKeymaps(): Keymaps { const keymaps: { [key: string]: operations.Operation } = {}; for (const name of Object.keys(this.data)) { - const [type, argStr] = name.split('?'); + const [type, argStr] = name.split("?"); let args = {}; if (argStr) { args = JSON.parse(argStr); @@ -26,7 +26,7 @@ export class FormKeymaps { return Keymaps.fromJSON(keymaps); } - toJSON(): {[op: string]: string} { + toJSON(): { [op: string]: string } { return this.data; } @@ -38,8 +38,8 @@ export class FormKeymaps { return new FormKeymaps(newData); } - static fromJSON(o: ReturnType<FormKeymaps['toJSON']>): FormKeymaps { - const data: {[op: string]: string} = {}; + static fromJSON(o: ReturnType<FormKeymaps["toJSON"]>): FormKeymaps { + const data: { [op: string]: string } = {}; for (const op of Object.keys(o)) { data[op] = o[op] as string; } @@ -48,7 +48,7 @@ export class FormKeymaps { static fromKeymaps(keymaps: Keymaps): FormKeymaps { const json = keymaps.toJSON(); - const data: {[op: string]: string} = {}; + const data: { [op: string]: string } = {}; for (const key of Object.keys(json)) { const op = json[key]; const args = { ...op }; @@ -56,7 +56,7 @@ export class FormKeymaps { let name = op.type; if (Object.keys(args).length > 0) { - name += '?' + JSON.stringify(args); + name += "?" + JSON.stringify(args); } data[name] = key; } @@ -85,18 +85,18 @@ export class FormSearch { toJSON(): { default: string; engines: string[][]; - } { + } { return { default: this.default, engines: this.engines, }; } - static fromJSON(o: ReturnType<FormSearch['toJSON']>): FormSearch { - if (!Object.prototype.hasOwnProperty.call(o, 'default')) { + static fromJSON(o: ReturnType<FormSearch["toJSON"]>): FormSearch { + if (!Object.prototype.hasOwnProperty.call(o, "default")) { throw new TypeError(`"default" field not set`); } - if (!Object.prototype.hasOwnProperty.call(o, 'engines')) { + if (!Object.prototype.hasOwnProperty.call(o, "engines")) { throw new TypeError(`"engines" field not set`); } return new FormSearch(o.default, o.engines); @@ -106,16 +106,15 @@ export class FormSearch { const engines = Object.entries(search.engines).reduce( (o: string[][], [name, url]) => { return o.concat([[name, url]]); - }, []); + }, + [] + ); return new FormSearch(search.defaultEngine, engines); } } export class JSONTextSettings { - constructor( - private json: string, - ) { - } + constructor(private json: string) {} toSettings(): Settings { return Settings.fromJSON(JSON.parse(this.json)); @@ -153,7 +152,7 @@ export class FormSettings { keymaps: FormKeymaps, search: FormSearch, properties: Properties, - blacklist: Blacklist, + blacklist: Blacklist ) { this.keymaps = keymaps; this.search = search; @@ -166,7 +165,7 @@ export class FormSettings { keymaps, this.search, this.properties, - this.blacklist, + this.blacklist ); } @@ -175,17 +174,12 @@ export class FormSettings { this.keymaps, search, this.properties, - this.blacklist, + this.blacklist ); } buildWithProperties(props: Properties): FormSettings { - return new FormSettings( - this.keymaps, - this.search, - props, - this.blacklist, - ); + return new FormSettings(this.keymaps, this.search, props, this.blacklist); } buildWithBlacklist(blacklist: Blacklist): FormSettings { @@ -193,7 +187,7 @@ export class FormSettings { this.keymaps, this.search, this.properties, - blacklist, + blacklist ); } @@ -207,11 +201,11 @@ export class FormSettings { } toJSON(): { - keymaps: ReturnType<FormKeymaps['toJSON']>; - search: ReturnType<FormSearch['toJSON']>; - properties: ReturnType<Properties['toJSON']>; - blacklist: ReturnType<Blacklist['toJSON']>; - } { + keymaps: ReturnType<FormKeymaps["toJSON"]>; + search: ReturnType<FormSearch["toJSON"]>; + properties: ReturnType<Properties["toJSON"]>; + blacklist: ReturnType<Blacklist["toJSON"]>; + } { return { keymaps: this.keymaps.toJSON(), search: this.search.toJSON(), @@ -220,8 +214,8 @@ export class FormSettings { }; } - static fromJSON(o: ReturnType<FormSettings['toJSON']>): FormSettings { - for (const name of ['keymaps', 'search', 'properties', 'blacklist']) { + static fromJSON(o: ReturnType<FormSettings["toJSON"]>): FormSettings { + for (const name of ["keymaps", "search", "properties", "blacklist"]) { if (!Object.prototype.hasOwnProperty.call(o, name)) { throw new Error(`"${name}" field not set`); } @@ -230,7 +224,7 @@ export class FormSettings { FormKeymaps.fromJSON(o.keymaps), FormSearch.fromJSON(o.search), Properties.fromJSON(o.properties), - Blacklist.fromJSON(o.blacklist), + Blacklist.fromJSON(o.blacklist) ); } @@ -239,13 +233,14 @@ export class FormSettings { FormKeymaps.fromKeymaps(data.keymaps), FormSearch.fromSearch(data.search), data.properties, - data.blacklist); + data.blacklist + ); } } export enum SettingSource { - JSON = 'json', - Form = 'form', + JSON = "json", + Form = "form", } export default class SettingData { @@ -256,11 +251,13 @@ export default class SettingData { private form?: FormSettings; constructor({ - source, json, form + source, + json, + form, }: { - source: SettingSource, - json?: JSONTextSettings, - form?: FormSettings, + source: SettingSource; + json?: JSONTextSettings; + form?: FormSettings; }) { this.source = source; this.json = json; @@ -273,40 +270,40 @@ export default class SettingData { getJSON(): JSONTextSettings { if (!this.json) { - throw new TypeError('json settings not set'); + throw new TypeError("json settings not set"); } return this.json; } getForm(): FormSettings { if (!this.form) { - throw new TypeError('form settings not set'); + throw new TypeError("form settings not set"); } return this.form; } toJSON(): any { switch (this.source) { - case SettingSource.JSON: - return { - source: this.source, - json: (this.json as JSONTextSettings).toJSONText(), - }; - case SettingSource.Form: - return { - source: this.source, - form: (this.form as FormSettings).toJSON(), - }; + case SettingSource.JSON: + return { + source: this.source, + json: (this.json as JSONTextSettings).toJSONText(), + }; + case SettingSource.Form: + return { + source: this.source, + form: (this.form as FormSettings).toJSON(), + }; } throw new Error(`unknown settings source: ${this.source}`); } toSettings(): Settings { switch (this.source) { - case SettingSource.JSON: - return this.getJSON().toSettings(); - case SettingSource.Form: - return this.getForm().toSettings(); + case SettingSource.JSON: + return this.getJSON().toSettings(); + case SettingSource.Form: + return this.getForm().toSettings(); } throw new Error(`unknown settings source: ${this.source}`); } @@ -314,27 +311,29 @@ export default class SettingData { static fromJSON(o: { source: string; json?: string; - form?: ReturnType<FormSettings['toJSON']>; + form?: ReturnType<FormSettings["toJSON"]>; }): SettingData { switch (o.source) { - case SettingSource.JSON: - return new SettingData({ - source: o.source, - json: JSONTextSettings.fromText( - o.json as ReturnType<JSONTextSettings['toJSONText']>), - }); - case SettingSource.Form: - return new SettingData({ - source: o.source, - form: FormSettings.fromJSON( - o.form as ReturnType<FormSettings['toJSON']>), - }); + case SettingSource.JSON: + return new SettingData({ + source: o.source, + json: JSONTextSettings.fromText( + o.json as ReturnType<JSONTextSettings["toJSONText"]> + ), + }); + case SettingSource.Form: + return new SettingData({ + source: o.source, + form: FormSettings.fromJSON( + o.form as ReturnType<FormSettings["toJSON"]> + ), + }); } throw new Error(`unknown settings source: ${o.source}`); } } export const DefaultSettingData: SettingData = SettingData.fromJSON({ - source: 'json', + source: "json", json: DefaultSettingJSONText, }); diff --git a/src/shared/TabFlag.ts b/src/shared/TabFlag.ts index b10d5c6..eb4e116 100644 --- a/src/shared/TabFlag.ts +++ b/src/shared/TabFlag.ts @@ -1,7 +1,7 @@ enum TabFlag { - CurrentTab = '%', - LastTab = '#', - None = '', + CurrentTab = "%", + LastTab = "#", + None = "", } -export default TabFlag
\ No newline at end of file +export default TabFlag; diff --git a/src/shared/messages.ts b/src/shared/messages.ts index edb7935..f876b99 100644 --- a/src/shared/messages.ts +++ b/src/shared/messages.ts @@ -1,58 +1,59 @@ -import * as operations from './operations'; +import * as operations from "./operations"; import CompletionType from "./CompletionType"; import TabFlag from "./TabFlag"; -export const BACKGROUND_OPERATION = 'background.operation'; - -export const CONSOLE_UNFOCUS = 'console.unfocus'; -export const CONSOLE_ENTER_COMMAND = 'console.enter.command'; -export const CONSOLE_ENTER_FIND = 'console.enter.find'; -export const CONSOLE_SHOW_COMMAND = 'console.show.command'; -export const CONSOLE_SHOW_ERROR = 'console.show.error'; -export const CONSOLE_SHOW_INFO = 'console.show.info'; -export const CONSOLE_SHOW_FIND = 'console.show.find'; -export const CONSOLE_HIDE = 'console.hide'; -export const CONSOLE_GET_COMPLETION_TYPES = 'console.get.completion.types'; -export const CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE = 'console.qresut.searchEngines'; -export const CONSOLE_REQUEST_BOOKMARKS = 'console.request.bookmarks'; -export const CONSOLE_REQUEST_HISTORY = 'console.request.history'; -export const CONSOLE_REQUEST_TABS = 'console.request.tabs'; -export const CONSOLE_GET_PROPERTIES = 'console.get.properties'; - -export const FOLLOW_START = 'follow.start'; -export const FOLLOW_REQUEST_COUNT_TARGETS = 'follow.request.count.targets'; -export const FOLLOW_RESPONSE_COUNT_TARGETS = 'follow.response.count.targets'; -export const FOLLOW_CREATE_HINTS = 'follow.create.hints'; -export const FOLLOW_SHOW_HINTS = 'follow.update.hints'; -export const FOLLOW_REMOVE_HINTS = 'follow.remove.hints'; -export const FOLLOW_ACTIVATE = 'follow.activate'; -export const FOLLOW_KEY_PRESS = 'follow.key.press'; - -export const MARK_SET_GLOBAL = 'mark.set.global'; -export const MARK_JUMP_GLOBAL = 'mark.jump.global'; - -export const TAB_SCROLL_TO = 'tab.scroll.to'; - -export const FIND_NEXT = 'find.next'; -export const FIND_PREV = 'find.prev'; -export const FIND_GET_KEYWORD = 'find.get.keyword'; -export const FIND_SET_KEYWORD = 'find.set.keyword'; - -export const ADDON_ENABLED_QUERY = 'addon.enabled.query'; -export const ADDON_ENABLED_RESPONSE = 'addon.enabled.response'; -export const ADDON_TOGGLE_ENABLED = 'addon.toggle.enabled'; - -export const OPEN_URL = 'open.url'; - -export const SETTINGS_CHANGED = 'settings.changed'; -export const SETTINGS_QUERY = 'settings.query'; - -export const CONSOLE_FRAME_MESSAGE = 'console.frame.message'; - -export const NAVIGATE_HISTORY_NEXT = 'navigate.history.next'; -export const NAVIGATE_HISTORY_PREV = 'navigate.history.prev'; -export const NAVIGATE_LINK_NEXT = 'navigate.link.next'; -export const NAVIGATE_LINK_PREV = 'navigate.link.prev'; +export const BACKGROUND_OPERATION = "background.operation"; + +export const CONSOLE_UNFOCUS = "console.unfocus"; +export const CONSOLE_ENTER_COMMAND = "console.enter.command"; +export const CONSOLE_ENTER_FIND = "console.enter.find"; +export const CONSOLE_SHOW_COMMAND = "console.show.command"; +export const CONSOLE_SHOW_ERROR = "console.show.error"; +export const CONSOLE_SHOW_INFO = "console.show.info"; +export const CONSOLE_SHOW_FIND = "console.show.find"; +export const CONSOLE_HIDE = "console.hide"; +export const CONSOLE_GET_COMPLETION_TYPES = "console.get.completion.types"; +export const CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE = + "console.qresut.searchEngines"; +export const CONSOLE_REQUEST_BOOKMARKS = "console.request.bookmarks"; +export const CONSOLE_REQUEST_HISTORY = "console.request.history"; +export const CONSOLE_REQUEST_TABS = "console.request.tabs"; +export const CONSOLE_GET_PROPERTIES = "console.get.properties"; + +export const FOLLOW_START = "follow.start"; +export const FOLLOW_REQUEST_COUNT_TARGETS = "follow.request.count.targets"; +export const FOLLOW_RESPONSE_COUNT_TARGETS = "follow.response.count.targets"; +export const FOLLOW_CREATE_HINTS = "follow.create.hints"; +export const FOLLOW_SHOW_HINTS = "follow.update.hints"; +export const FOLLOW_REMOVE_HINTS = "follow.remove.hints"; +export const FOLLOW_ACTIVATE = "follow.activate"; +export const FOLLOW_KEY_PRESS = "follow.key.press"; + +export const MARK_SET_GLOBAL = "mark.set.global"; +export const MARK_JUMP_GLOBAL = "mark.jump.global"; + +export const TAB_SCROLL_TO = "tab.scroll.to"; + +export const FIND_NEXT = "find.next"; +export const FIND_PREV = "find.prev"; +export const FIND_GET_KEYWORD = "find.get.keyword"; +export const FIND_SET_KEYWORD = "find.set.keyword"; + +export const ADDON_ENABLED_QUERY = "addon.enabled.query"; +export const ADDON_ENABLED_RESPONSE = "addon.enabled.response"; +export const ADDON_TOGGLE_ENABLED = "addon.toggle.enabled"; + +export const OPEN_URL = "open.url"; + +export const SETTINGS_CHANGED = "settings.changed"; +export const SETTINGS_QUERY = "settings.query"; + +export const CONSOLE_FRAME_MESSAGE = "console.frame.message"; + +export const NAVIGATE_HISTORY_NEXT = "navigate.history.next"; +export const NAVIGATE_HISTORY_PREV = "navigate.history.prev"; +export const NAVIGATE_LINK_NEXT = "navigate.link.next"; +export const NAVIGATE_LINK_PREV = "navigate.link.prev"; export interface BackgroundOperationMessage { type: typeof BACKGROUND_OPERATION; @@ -103,7 +104,7 @@ export interface ConsoleGetCompletionTypesMessage { export interface ConsoleRequestSearchEnginesMessage { type: typeof CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE; - query: string + query: string; } export interface ConsoleRequestBookmarksMessage { @@ -127,33 +128,33 @@ export interface ConsoleGetPropertiesMessage { } export type ConsoleRequesttabsResponse = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -}[] + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}[]; export type ConsoleGetCompletionTypesResponse = CompletionType[]; export type ConsoleRequestSearchEnginesResponse = { title: string; -}[] +}[]; export type ConsoleRequestBookmarksResponse = { - title: string; - url: string; -}[] + title: string; + url: string; +}[]; export type ConsoleRequestHistoryResponse = { title: string; url: string; -}[] +}[]; export type ConsoleGetPropertiesResponse = { - name: string - type: 'string' | 'boolean' | 'number' -}[] + name: string; + type: "string" | "boolean" | "number"; +}[]; export interface FollowStartMessage { type: typeof FOLLOW_START; @@ -163,8 +164,8 @@ export interface FollowStartMessage { export interface FollowRequestCountTargetsMessage { type: typeof FOLLOW_REQUEST_COUNT_TARGETS; - viewSize: { width: number, height: number }; - framePosition: { x: number, y: number }; + viewSize: { width: number; height: number }; + framePosition: { x: number; y: number }; } export interface FollowResponseCountTargetsMessage { @@ -175,8 +176,8 @@ export interface FollowResponseCountTargetsMessage { export interface FollowCreateHintsMessage { type: typeof FOLLOW_CREATE_HINTS; tags: string[]; - viewSize: { width: number, height: number }; - framePosition: { x: number, y: number }; + viewSize: { width: number; height: number }; + framePosition: { x: number; y: number }; } export interface FollowShowHintsMessage { @@ -287,86 +288,86 @@ export interface NavigateLinkPrev { } export type Message = - BackgroundOperationMessage | - ConsoleUnfocusMessage | - ConsoleEnterCommandMessage | - ConsoleEnterFindMessage | - ConsoleShowCommandMessage | - ConsoleShowErrorMessage | - ConsoleShowInfoMessage | - ConsoleShowFindMessage | - ConsoleHideMessage | - ConsoleRequestBookmarksMessage | - ConsoleRequestHistoryMessage | - ConsoleRequestTabsMessage | - ConsoleGetPropertiesMessage | - ConsoleGetCompletionTypesMessage | - ConsoleRequestSearchEnginesMessage | - FollowStartMessage | - FollowRequestCountTargetsMessage | - FollowResponseCountTargetsMessage | - FollowCreateHintsMessage | - FollowShowHintsMessage | - FollowRemoveHintsMessage | - FollowActivateMessage | - FollowKeyPressMessage | - MarkSetGlobalMessage | - MarkJumpGlobalMessage | - TabScrollToMessage | - FindNextMessage | - FindPrevMessage | - FindGetKeywordMessage | - FindSetKeywordMessage | - AddonEnabledQueryMessage | - AddonEnabledResponseMessage | - AddonToggleEnabledMessage | - OpenUrlMessage | - SettingsChangedMessage | - SettingsQueryMessage | - ConsoleFrameMessageMessage | - NavigateHistoryNextMessage | - NavigateHistoryPrevMessage | - NavigateLinkNext | - NavigateLinkPrev; + | BackgroundOperationMessage + | ConsoleUnfocusMessage + | ConsoleEnterCommandMessage + | ConsoleEnterFindMessage + | ConsoleShowCommandMessage + | ConsoleShowErrorMessage + | ConsoleShowInfoMessage + | ConsoleShowFindMessage + | ConsoleHideMessage + | ConsoleRequestBookmarksMessage + | ConsoleRequestHistoryMessage + | ConsoleRequestTabsMessage + | ConsoleGetPropertiesMessage + | ConsoleGetCompletionTypesMessage + | ConsoleRequestSearchEnginesMessage + | FollowStartMessage + | FollowRequestCountTargetsMessage + | FollowResponseCountTargetsMessage + | FollowCreateHintsMessage + | FollowShowHintsMessage + | FollowRemoveHintsMessage + | FollowActivateMessage + | FollowKeyPressMessage + | MarkSetGlobalMessage + | MarkJumpGlobalMessage + | TabScrollToMessage + | FindNextMessage + | FindPrevMessage + | FindGetKeywordMessage + | FindSetKeywordMessage + | AddonEnabledQueryMessage + | AddonEnabledResponseMessage + | AddonToggleEnabledMessage + | OpenUrlMessage + | SettingsChangedMessage + | SettingsQueryMessage + | ConsoleFrameMessageMessage + | NavigateHistoryNextMessage + | NavigateHistoryPrevMessage + | NavigateLinkNext + | NavigateLinkPrev; // eslint-disable-next-line complexity export const valueOf = (o: any): Message => { switch (o.type) { - case CONSOLE_UNFOCUS: - case CONSOLE_ENTER_COMMAND: - case CONSOLE_ENTER_FIND: - case CONSOLE_SHOW_COMMAND: - case CONSOLE_SHOW_ERROR: - case CONSOLE_SHOW_INFO: - case CONSOLE_SHOW_FIND: - case CONSOLE_HIDE: - case FOLLOW_START: - case FOLLOW_REQUEST_COUNT_TARGETS: - case FOLLOW_RESPONSE_COUNT_TARGETS: - case FOLLOW_CREATE_HINTS: - case FOLLOW_SHOW_HINTS: - case FOLLOW_REMOVE_HINTS: - case FOLLOW_ACTIVATE: - case FOLLOW_KEY_PRESS: - case MARK_SET_GLOBAL: - case MARK_JUMP_GLOBAL: - case TAB_SCROLL_TO: - case FIND_NEXT: - case FIND_PREV: - case FIND_GET_KEYWORD: - case FIND_SET_KEYWORD: - case ADDON_ENABLED_QUERY: - case ADDON_ENABLED_RESPONSE: - case ADDON_TOGGLE_ENABLED: - case OPEN_URL: - case SETTINGS_CHANGED: - case SETTINGS_QUERY: - case CONSOLE_FRAME_MESSAGE: - case NAVIGATE_HISTORY_NEXT: - case NAVIGATE_HISTORY_PREV: - case NAVIGATE_LINK_NEXT: - case NAVIGATE_LINK_PREV: - return o; + case CONSOLE_UNFOCUS: + case CONSOLE_ENTER_COMMAND: + case CONSOLE_ENTER_FIND: + case CONSOLE_SHOW_COMMAND: + case CONSOLE_SHOW_ERROR: + case CONSOLE_SHOW_INFO: + case CONSOLE_SHOW_FIND: + case CONSOLE_HIDE: + case FOLLOW_START: + case FOLLOW_REQUEST_COUNT_TARGETS: + case FOLLOW_RESPONSE_COUNT_TARGETS: + case FOLLOW_CREATE_HINTS: + case FOLLOW_SHOW_HINTS: + case FOLLOW_REMOVE_HINTS: + case FOLLOW_ACTIVATE: + case FOLLOW_KEY_PRESS: + case MARK_SET_GLOBAL: + case MARK_JUMP_GLOBAL: + case TAB_SCROLL_TO: + case FIND_NEXT: + case FIND_PREV: + case FIND_GET_KEYWORD: + case FIND_SET_KEYWORD: + case ADDON_ENABLED_QUERY: + case ADDON_ENABLED_RESPONSE: + case ADDON_TOGGLE_ENABLED: + case OPEN_URL: + case SETTINGS_CHANGED: + case SETTINGS_QUERY: + case CONSOLE_FRAME_MESSAGE: + case NAVIGATE_HISTORY_NEXT: + case NAVIGATE_HISTORY_PREV: + case NAVIGATE_LINK_NEXT: + case NAVIGATE_LINK_PREV: + return o; } - throw new Error('unknown operation type: ' + o.type); + throw new Error("unknown operation type: " + o.type); }; diff --git a/src/shared/operations.ts b/src/shared/operations.ts index beca7b9..3544502 100644 --- a/src/shared/operations.ts +++ b/src/shared/operations.ts @@ -1,85 +1,85 @@ // Hide console; or cancel some user actions -export const CANCEL = 'cancel'; +export const CANCEL = "cancel"; // Addons -export const ADDON_ENABLE = 'addon.enable'; -export const ADDON_DISABLE = 'addon.disable'; -export const ADDON_TOGGLE_ENABLED = 'addon.toggle.enabled'; +export const ADDON_ENABLE = "addon.enable"; +export const ADDON_DISABLE = "addon.disable"; +export const ADDON_TOGGLE_ENABLED = "addon.toggle.enabled"; // Command -export const COMMAND_SHOW = 'command.show'; -export const COMMAND_SHOW_OPEN = 'command.show.open'; -export const COMMAND_SHOW_TABOPEN = 'command.show.tabopen'; -export const COMMAND_SHOW_WINOPEN = 'command.show.winopen'; -export const COMMAND_SHOW_BUFFER = 'command.show.buffer'; -export const COMMAND_SHOW_ADDBOOKMARK = 'command.show.addbookmark'; +export const COMMAND_SHOW = "command.show"; +export const COMMAND_SHOW_OPEN = "command.show.open"; +export const COMMAND_SHOW_TABOPEN = "command.show.tabopen"; +export const COMMAND_SHOW_WINOPEN = "command.show.winopen"; +export const COMMAND_SHOW_BUFFER = "command.show.buffer"; +export const COMMAND_SHOW_ADDBOOKMARK = "command.show.addbookmark"; // Scrolls -export const SCROLL_VERTICALLY = 'scroll.vertically'; -export const SCROLL_HORIZONALLY = 'scroll.horizonally'; -export const SCROLL_PAGES = 'scroll.pages'; -export const SCROLL_TOP = 'scroll.top'; -export const SCROLL_BOTTOM = 'scroll.bottom'; -export const SCROLL_HOME = 'scroll.home'; -export const SCROLL_END = 'scroll.end'; +export const SCROLL_VERTICALLY = "scroll.vertically"; +export const SCROLL_HORIZONALLY = "scroll.horizonally"; +export const SCROLL_PAGES = "scroll.pages"; +export const SCROLL_TOP = "scroll.top"; +export const SCROLL_BOTTOM = "scroll.bottom"; +export const SCROLL_HOME = "scroll.home"; +export const SCROLL_END = "scroll.end"; // Follows -export const FOLLOW_START = 'follow.start'; +export const FOLLOW_START = "follow.start"; // Navigations -export const NAVIGATE_HISTORY_PREV = 'navigate.history.prev'; -export const NAVIGATE_HISTORY_NEXT = 'navigate.history.next'; -export const NAVIGATE_LINK_PREV = 'navigate.link.prev'; -export const NAVIGATE_LINK_NEXT = 'navigate.link.next'; -export const NAVIGATE_PARENT = 'navigate.parent'; -export const NAVIGATE_ROOT = 'navigate.root'; +export const NAVIGATE_HISTORY_PREV = "navigate.history.prev"; +export const NAVIGATE_HISTORY_NEXT = "navigate.history.next"; +export const NAVIGATE_LINK_PREV = "navigate.link.prev"; +export const NAVIGATE_LINK_NEXT = "navigate.link.next"; +export const NAVIGATE_PARENT = "navigate.parent"; +export const NAVIGATE_ROOT = "navigate.root"; // Focus -export const FOCUS_INPUT = 'focus.input'; +export const FOCUS_INPUT = "focus.input"; // Page -export const PAGE_SOURCE = 'page.source'; -export const PAGE_HOME = 'page.home'; +export const PAGE_SOURCE = "page.source"; +export const PAGE_HOME = "page.home"; // Tabs -export const TAB_CLOSE = 'tabs.close'; -export const TAB_CLOSE_FORCE = 'tabs.close.force'; -export const TAB_CLOSE_RIGHT = 'tabs.close.right'; -export const TAB_REOPEN = 'tabs.reopen'; -export const TAB_PREV = 'tabs.prev'; -export const TAB_NEXT = 'tabs.next'; -export const TAB_FIRST = 'tabs.first'; -export const TAB_LAST = 'tabs.last'; -export const TAB_PREV_SEL = 'tabs.prevsel'; -export const TAB_RELOAD = 'tabs.reload'; -export const TAB_PIN = 'tabs.pin'; -export const TAB_UNPIN = 'tabs.unpin'; -export const TAB_TOGGLE_PINNED = 'tabs.pin.toggle'; -export const TAB_DUPLICATE = 'tabs.duplicate'; +export const TAB_CLOSE = "tabs.close"; +export const TAB_CLOSE_FORCE = "tabs.close.force"; +export const TAB_CLOSE_RIGHT = "tabs.close.right"; +export const TAB_REOPEN = "tabs.reopen"; +export const TAB_PREV = "tabs.prev"; +export const TAB_NEXT = "tabs.next"; +export const TAB_FIRST = "tabs.first"; +export const TAB_LAST = "tabs.last"; +export const TAB_PREV_SEL = "tabs.prevsel"; +export const TAB_RELOAD = "tabs.reload"; +export const TAB_PIN = "tabs.pin"; +export const TAB_UNPIN = "tabs.unpin"; +export const TAB_TOGGLE_PINNED = "tabs.pin.toggle"; +export const TAB_DUPLICATE = "tabs.duplicate"; // Zooms -export const ZOOM_IN = 'zoom.in'; -export const ZOOM_OUT = 'zoom.out'; -export const ZOOM_NEUTRAL = 'zoom.neutral'; +export const ZOOM_IN = "zoom.in"; +export const ZOOM_OUT = "zoom.out"; +export const ZOOM_NEUTRAL = "zoom.neutral"; // Url yank/paste -export const URLS_YANK = 'urls.yank'; -export const URLS_PASTE = 'urls.paste'; +export const URLS_YANK = "urls.yank"; +export const URLS_PASTE = "urls.paste"; // Find -export const FIND_START = 'find.start'; -export const FIND_NEXT = 'find.next'; -export const FIND_PREV = 'find.prev'; +export const FIND_START = "find.start"; +export const FIND_NEXT = "find.next"; +export const FIND_PREV = "find.prev"; // Mark -export const MARK_SET_PREFIX = 'mark.set.prefix'; -export const MARK_JUMP_PREFIX = 'mark.jump.prefix'; +export const MARK_SET_PREFIX = "mark.set.prefix"; +export const MARK_JUMP_PREFIX = "mark.jump.prefix"; // Repeat -export const REPEAT_LAST = 'repeat.last'; +export const REPEAT_LAST = "repeat.last"; // Internal -export const INTERNAL_OPEN_URL = 'internal.open.url'; +export const INTERNAL_OPEN_URL = "internal.open.url"; export interface CancelOperation { type: typeof CANCEL; @@ -201,7 +201,7 @@ export interface PageHomeOperation { export interface TabCloseOperation { type: typeof TAB_CLOSE; - select?: 'left' | 'right'; + select?: "left" | "right"; } export interface TabCloseForceOperation { @@ -311,65 +311,67 @@ export interface InternalOpenUrl { } export type Operation = - CancelOperation | - AddonEnableOperation | - AddonDisableOperation | - AddonToggleEnabledOperation | - CommandShowOperation | - CommandShowOpenOperation | - CommandShowTabopenOperation | - CommandShowWinopenOperation | - CommandShowBufferOperation | - CommandShowAddbookmarkOperation | - ScrollVerticallyOperation | - ScrollHorizonallyOperation | - ScrollPagesOperation | - ScrollTopOperation | - ScrollBottomOperation | - ScrollHomeOperation | - ScrollEndOperation | - FollowStartOperation | - NavigateHistoryPrevOperation | - NavigateHistoryNextOperation | - NavigateLinkPrevOperation | - NavigateLinkNextOperation | - NavigateParentOperation | - NavigateRootOperation | - FocusInputOperation | - PageSourceOperation | - PageHomeOperation | - TabCloseOperation | - TabCloseForceOperation | - TabCloseRightOperation | - TabReopenOperation | - TabPrevOperation | - TabNextOperation | - TabFirstOperation | - TabLastOperation | - TabPrevSelOperation | - TabReloadOperation | - TabPinOperation | - TabUnpinOperation | - TabTogglePinnedOperation | - TabDuplicateOperation | - ZoomInOperation | - ZoomOutOperation | - ZoomNeutralOperation | - UrlsYankOperation | - UrlsPasteOperation | - FindStartOperation | - FindNextOperation | - FindPrevOperation | - MarkSetPrefixOperation | - MarkJumpPrefixOperation | - RepeatLastOperation | - InternalOpenUrl; + | CancelOperation + | AddonEnableOperation + | AddonDisableOperation + | AddonToggleEnabledOperation + | CommandShowOperation + | CommandShowOpenOperation + | CommandShowTabopenOperation + | CommandShowWinopenOperation + | CommandShowBufferOperation + | CommandShowAddbookmarkOperation + | ScrollVerticallyOperation + | ScrollHorizonallyOperation + | ScrollPagesOperation + | ScrollTopOperation + | ScrollBottomOperation + | ScrollHomeOperation + | ScrollEndOperation + | FollowStartOperation + | NavigateHistoryPrevOperation + | NavigateHistoryNextOperation + | NavigateLinkPrevOperation + | NavigateLinkNextOperation + | NavigateParentOperation + | NavigateRootOperation + | FocusInputOperation + | PageSourceOperation + | PageHomeOperation + | TabCloseOperation + | TabCloseForceOperation + | TabCloseRightOperation + | TabReopenOperation + | TabPrevOperation + | TabNextOperation + | TabFirstOperation + | TabLastOperation + | TabPrevSelOperation + | TabReloadOperation + | TabPinOperation + | TabUnpinOperation + | TabTogglePinnedOperation + | TabDuplicateOperation + | ZoomInOperation + | ZoomOutOperation + | ZoomNeutralOperation + | UrlsYankOperation + | UrlsPasteOperation + | FindStartOperation + | FindNextOperation + | FindPrevOperation + | MarkSetPrefixOperation + | MarkJumpPrefixOperation + | RepeatLastOperation + | InternalOpenUrl; const assertOptionalBoolean = (obj: any, name: string) => { - if (Object.prototype.hasOwnProperty.call(obj, name) && - typeof obj[name] !== 'boolean') { + if ( + Object.prototype.hasOwnProperty.call(obj, name) && + typeof obj[name] !== "boolean" + ) { throw new TypeError( - `Not a boolean parameter: '${name} (${typeof obj[name]})'`, + `Not a boolean parameter: '${name} (${typeof obj[name]})'` ); } }; @@ -377,9 +379,9 @@ const assertOptionalBoolean = (obj: any, name: string) => { const assertOptionalString = (obj: any, name: string, values?: string[]) => { if (Object.prototype.hasOwnProperty.call(obj, name)) { const value = obj[name]; - if (typeof value !== 'string') { + if (typeof value !== "string") { throw new TypeError( - `Not a string parameter: '${name}' (${typeof value})`, + `Not a string parameter: '${name}' (${typeof value})` ); } if (values && values.length && values.indexOf(value) === -1) { @@ -390,147 +392,157 @@ const assertOptionalString = (obj: any, name: string, values?: string[]) => { }; const assertRequiredNumber = (obj: any, name: string) => { - if (!Object.prototype.hasOwnProperty.call(obj, name) || - typeof obj[name] !== 'number') { + if ( + !Object.prototype.hasOwnProperty.call(obj, name) || + typeof obj[name] !== "number" + ) { throw new TypeError(`Missing number parameter: '${name}`); } }; const assertRequiredString = (obj: any, name: string) => { - if (!Object.prototype.hasOwnProperty.call(obj, name) || - typeof obj[name] !== 'string') { + if ( + !Object.prototype.hasOwnProperty.call(obj, name) || + typeof obj[name] !== "string" + ) { throw new TypeError(`Missing string parameter: '${name}`); } }; // eslint-disable-next-line complexity, max-lines-per-function export const valueOf = (o: any): Operation => { - if (!Object.prototype.hasOwnProperty.call(o, 'type')) { + if (!Object.prototype.hasOwnProperty.call(o, "type")) { throw new TypeError(`Missing 'type' field`); } switch (o.type) { - case COMMAND_SHOW_OPEN: - case COMMAND_SHOW_TABOPEN: - case COMMAND_SHOW_WINOPEN: - case COMMAND_SHOW_ADDBOOKMARK: - assertOptionalBoolean(o, 'alter'); - return { type: o.type, alter: Boolean(o.alter) }; - case SCROLL_VERTICALLY: - case SCROLL_HORIZONALLY: - case SCROLL_PAGES: - assertRequiredNumber(o, 'count'); - return { type: o.type, count: Number(o.count) }; - case FOLLOW_START: - assertOptionalBoolean(o, 'newTab'); - assertOptionalBoolean(o, 'background'); - return { - type: FOLLOW_START, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - background: Boolean(typeof o.background === 'undefined' ? true : o.background), // eslint-disable-line max-len - }; - case PAGE_HOME: - assertOptionalBoolean(o, 'newTab'); - return { - type: PAGE_HOME, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - }; - case TAB_CLOSE: - assertOptionalString(o, 'select', ['left', 'right']); - return { - type: TAB_CLOSE, - select: (typeof o.select === 'undefined' ? 'right' : o.select), - }; - case TAB_RELOAD: - assertOptionalBoolean(o, 'cache'); - return { - type: TAB_RELOAD, - cache: Boolean(typeof o.cache === 'undefined' ? false : o.cache), - }; - case URLS_PASTE: - assertOptionalBoolean(o, 'newTab'); - return { - type: URLS_PASTE, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - }; - case INTERNAL_OPEN_URL: - assertOptionalBoolean(o, 'newTab'); - assertOptionalBoolean(o, 'newWindow'); - assertOptionalBoolean(o, 'background'); - assertRequiredString(o, 'url'); - return { - type: INTERNAL_OPEN_URL, - url: o.url, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - newWindow: Boolean(typeof o.newWindow === 'undefined' ? false : o.newWindow), // eslint-disable-line max-len - background: Boolean(typeof o.background === 'undefined' ? true : o.background), // eslint-disable-line max-len - }; - case CANCEL: - case ADDON_ENABLE: - case ADDON_DISABLE: - case ADDON_TOGGLE_ENABLED: - case COMMAND_SHOW: - case COMMAND_SHOW_BUFFER: - case SCROLL_TOP: - case SCROLL_BOTTOM: - case SCROLL_HOME: - case SCROLL_END: - case NAVIGATE_HISTORY_PREV: - case NAVIGATE_HISTORY_NEXT: - case NAVIGATE_LINK_PREV: - case NAVIGATE_LINK_NEXT: - case NAVIGATE_PARENT: - case NAVIGATE_ROOT: - case FOCUS_INPUT: - case PAGE_SOURCE: - case TAB_CLOSE_FORCE: - case TAB_CLOSE_RIGHT: - case TAB_REOPEN: - case TAB_PREV: - case TAB_NEXT: - case TAB_FIRST: - case TAB_LAST: - case TAB_PREV_SEL: - case TAB_PIN: - case TAB_UNPIN: - case TAB_TOGGLE_PINNED: - case TAB_DUPLICATE: - case ZOOM_IN: - case ZOOM_OUT: - case ZOOM_NEUTRAL: - case URLS_YANK: - case FIND_START: - case FIND_NEXT: - case FIND_PREV: - case MARK_SET_PREFIX: - case MARK_JUMP_PREFIX: - case REPEAT_LAST: - return { type: o.type }; + case COMMAND_SHOW_OPEN: + case COMMAND_SHOW_TABOPEN: + case COMMAND_SHOW_WINOPEN: + case COMMAND_SHOW_ADDBOOKMARK: + assertOptionalBoolean(o, "alter"); + return { type: o.type, alter: Boolean(o.alter) }; + case SCROLL_VERTICALLY: + case SCROLL_HORIZONALLY: + case SCROLL_PAGES: + assertRequiredNumber(o, "count"); + return { type: o.type, count: Number(o.count) }; + case FOLLOW_START: + assertOptionalBoolean(o, "newTab"); + assertOptionalBoolean(o, "background"); + return { + type: FOLLOW_START, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + background: Boolean( + typeof o.background === "undefined" ? true : o.background + ), // eslint-disable-line max-len + }; + case PAGE_HOME: + assertOptionalBoolean(o, "newTab"); + return { + type: PAGE_HOME, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + }; + case TAB_CLOSE: + assertOptionalString(o, "select", ["left", "right"]); + return { + type: TAB_CLOSE, + select: typeof o.select === "undefined" ? "right" : o.select, + }; + case TAB_RELOAD: + assertOptionalBoolean(o, "cache"); + return { + type: TAB_RELOAD, + cache: Boolean(typeof o.cache === "undefined" ? false : o.cache), + }; + case URLS_PASTE: + assertOptionalBoolean(o, "newTab"); + return { + type: URLS_PASTE, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + }; + case INTERNAL_OPEN_URL: + assertOptionalBoolean(o, "newTab"); + assertOptionalBoolean(o, "newWindow"); + assertOptionalBoolean(o, "background"); + assertRequiredString(o, "url"); + return { + type: INTERNAL_OPEN_URL, + url: o.url, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + newWindow: Boolean( + typeof o.newWindow === "undefined" ? false : o.newWindow + ), // eslint-disable-line max-len + background: Boolean( + typeof o.background === "undefined" ? true : o.background + ), // eslint-disable-line max-len + }; + case CANCEL: + case ADDON_ENABLE: + case ADDON_DISABLE: + case ADDON_TOGGLE_ENABLED: + case COMMAND_SHOW: + case COMMAND_SHOW_BUFFER: + case SCROLL_TOP: + case SCROLL_BOTTOM: + case SCROLL_HOME: + case SCROLL_END: + case NAVIGATE_HISTORY_PREV: + case NAVIGATE_HISTORY_NEXT: + case NAVIGATE_LINK_PREV: + case NAVIGATE_LINK_NEXT: + case NAVIGATE_PARENT: + case NAVIGATE_ROOT: + case FOCUS_INPUT: + case PAGE_SOURCE: + case TAB_CLOSE_FORCE: + case TAB_CLOSE_RIGHT: + case TAB_REOPEN: + case TAB_PREV: + case TAB_NEXT: + case TAB_FIRST: + case TAB_LAST: + case TAB_PREV_SEL: + case TAB_PIN: + case TAB_UNPIN: + case TAB_TOGGLE_PINNED: + case TAB_DUPLICATE: + case ZOOM_IN: + case ZOOM_OUT: + case ZOOM_NEUTRAL: + case URLS_YANK: + case FIND_START: + case FIND_NEXT: + case FIND_PREV: + case MARK_SET_PREFIX: + case MARK_JUMP_PREFIX: + case REPEAT_LAST: + return { type: o.type }; } - throw new TypeError('Unknown operation type: ' + o.type); + throw new TypeError("Unknown operation type: " + o.type); }; export const isNRepeatable = (type: string): boolean => { switch (type) { - case SCROLL_VERTICALLY: - case SCROLL_HORIZONALLY: - case SCROLL_PAGES: - case NAVIGATE_HISTORY_PREV: - case NAVIGATE_HISTORY_NEXT: - case NAVIGATE_PARENT: - case TAB_CLOSE: - case TAB_CLOSE_FORCE: - case TAB_CLOSE_RIGHT: - case TAB_REOPEN: - case TAB_PREV: - case TAB_NEXT: - case TAB_DUPLICATE: - case ZOOM_IN: - case ZOOM_OUT: - case URLS_PASTE: - case FIND_NEXT: - case FIND_PREV: - case REPEAT_LAST: - return true; + case SCROLL_VERTICALLY: + case SCROLL_HORIZONALLY: + case SCROLL_PAGES: + case NAVIGATE_HISTORY_PREV: + case NAVIGATE_HISTORY_NEXT: + case NAVIGATE_PARENT: + case TAB_CLOSE: + case TAB_CLOSE_FORCE: + case TAB_CLOSE_RIGHT: + case TAB_REOPEN: + case TAB_PREV: + case TAB_NEXT: + case TAB_DUPLICATE: + case ZOOM_IN: + case ZOOM_OUT: + case URLS_PASTE: + case FIND_NEXT: + case FIND_PREV: + case REPEAT_LAST: + return true; } return false; }; diff --git a/src/shared/settings/Blacklist.ts b/src/shared/settings/Blacklist.ts index 6c54d73..278dbd6 100644 --- a/src/shared/settings/Blacklist.ts +++ b/src/shared/settings/Blacklist.ts @@ -1,14 +1,16 @@ -import Key from './Key'; +import Key from "./Key"; -export type BlacklistItemJSON = string | { - url: string, - keys: string[], -}; +export type BlacklistItemJSON = + | string + | { + url: string; + keys: string[]; + }; export type BlacklistJSON = BlacklistItemJSON[]; const regexFromWildcard = (pattern: string): RegExp => { - const regexStr = '^' + pattern.replace(/\*/g, '.*') + '$'; + const regexStr = "^" + pattern.replace(/\*/g, ".*") + "$"; return new RegExp(regexStr); }; @@ -23,11 +25,7 @@ export class BlacklistItem { private readonly keyEntities: Key[]; - constructor( - pattern: string, - partial: boolean, - keys: string[] - ) { + constructor(pattern: string, partial: boolean, keys: string[]) { this.pattern = pattern; this.regex = regexFromWildcard(pattern); this.partial = partial; @@ -36,7 +34,7 @@ export class BlacklistItem { } static fromJSON(json: BlacklistItemJSON): BlacklistItem { - return typeof json === 'string' + return typeof json === "string" ? new BlacklistItem(json, false, []) : new BlacklistItem(json.url, true, json.keys); } @@ -49,7 +47,7 @@ export class BlacklistItem { } matches(url: URL): boolean { - return this.pattern.includes('/') + return this.pattern.includes("/") ? this.regex.test(url.host + url.pathname) : this.regex.test(url.host); } @@ -58,30 +56,27 @@ export class BlacklistItem { if (!this.matches(url) || !this.partial) { return false; } - return this.keyEntities.some(k => k.equals(key)); + return this.keyEntities.some((k) => k.equals(key)); } } export default class Blacklist { - constructor( - public readonly items: BlacklistItem[], - ) { - } + constructor(public readonly items: BlacklistItem[]) {} static fromJSON(json: BlacklistJSON): Blacklist { - const items = json.map(o => BlacklistItem.fromJSON(o)); + const items = json.map((o) => BlacklistItem.fromJSON(o)); return new Blacklist(items); } toJSON(): BlacklistJSON { - return this.items.map(item => item.toJSON()); + return this.items.map((item) => item.toJSON()); } includesEntireBlacklist(url: URL): boolean { - return this.items.some(item => !item.partial && item.matches(url)); + return this.items.some((item) => !item.partial && item.matches(url)); } includeKey(url: URL, key: Key) { - return this.items.some(item => item.includeKey(url, key)); + return this.items.some((item) => item.includeKey(url, key)); } } diff --git a/src/shared/settings/Key.ts b/src/shared/settings/Key.ts index 1464e57..2f47aff 100644 --- a/src/shared/settings/Key.ts +++ b/src/shared/settings/Key.ts @@ -1,4 +1,4 @@ -const digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; +const digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; export default class Key { public readonly key: string; @@ -32,10 +32,10 @@ export default class Key { } static fromMapKey(str: string): Key { - if (str.startsWith('<') && str.endsWith('>')) { + if (str.startsWith("<") && str.endsWith(">")) { const inner = str.slice(1, -1); - const shift = inner.includes('S-'); - let base = inner.slice(inner.lastIndexOf('-') + 1); + const shift = inner.includes("S-"); + let base = inner.slice(inner.lastIndexOf("-") + 1); if (shift && base.length === 1) { base = base.toUpperCase(); } else if (!shift && base.length === 1) { @@ -44,9 +44,9 @@ export default class Key { return new Key({ key: base, shift: shift, - ctrl: inner.includes('C-'), - alt: inner.includes('A-'), - meta: inner.includes('M-'), + ctrl: inner.includes("C-"), + alt: inner.includes("A-"), + meta: inner.includes("M-"), }); } @@ -64,10 +64,12 @@ export default class Key { } equals(key: Key) { - return this.key === key.key && + return ( + this.key === key.key && this.ctrl === key.ctrl && this.meta === key.meta && this.alt === key.alt && - this.shift === key.shift; + this.shift === key.shift + ); } } diff --git a/src/shared/settings/Keymaps.ts b/src/shared/settings/Keymaps.ts index 3880654..718427e 100644 --- a/src/shared/settings/Keymaps.ts +++ b/src/shared/settings/Keymaps.ts @@ -1,18 +1,17 @@ -import * as operations from '../operations'; +import * as operations from "../operations"; -type OperationJson = { - type: string -} | { - type: string; - [prop: string]: string | number | boolean; -}; +type OperationJson = + | { + type: string; + } + | { + type: string; + [prop: string]: string | number | boolean; + }; export type KeymapsJSON = { [key: string]: OperationJson }; export default class Keymaps { - constructor( - private readonly data: { [key: string]: operations.Operation }, - ) { - } + constructor(private readonly data: { [key: string]: operations.Operation }) {} static fromJSON(json: KeymapsJSON): Keymaps { const entries: { [key: string]: operations.Operation } = {}; diff --git a/src/shared/settings/Properties.ts b/src/shared/settings/Properties.ts index 27fb62e..cf10d61 100644 --- a/src/shared/settings/Properties.ts +++ b/src/shared/settings/Properties.ts @@ -1,4 +1,3 @@ - export type PropertiesJSON = { hintchars?: string; smoothscroll?: boolean; @@ -11,38 +10,40 @@ export type PropertyTypes = { complete: string; }; -type PropertyName = 'hintchars' | 'smoothscroll' | 'complete'; +type PropertyName = "hintchars" | "smoothscroll" | "complete"; type PropertyDef = { name: PropertyName; description: string; defaultValue: string | number | boolean; - type: 'string' | 'number' | 'boolean'; + type: "string" | "number" | "boolean"; }; const defs: PropertyDef[] = [ { - name: 'hintchars', - description: 'hint characters on follow mode', - defaultValue: 'abcdefghijklmnopqrstuvwxyz', - type: 'string', - }, { - name: 'smoothscroll', - description: 'smooth scroll', + name: "hintchars", + description: "hint characters on follow mode", + defaultValue: "abcdefghijklmnopqrstuvwxyz", + type: "string", + }, + { + name: "smoothscroll", + description: "smooth scroll", defaultValue: false, - type: 'boolean', - }, { - name: 'complete', - description: 'which are completed at the open page', - defaultValue: 'sbh', - type: 'string', - } + type: "boolean", + }, + { + name: "complete", + description: "which are completed at the open page", + defaultValue: "sbh", + type: "string", + }, ]; const defaultValues = { - hintchars: 'abcdefghijklmnopqrstuvwxyz', + hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: 'sbh', + complete: "sbh", }; export default class Properties { @@ -72,14 +73,14 @@ export default class Properties { static types(): PropertyTypes { return { - hintchars: 'string', - smoothscroll: 'boolean', - complete: 'string', + hintchars: "string", + smoothscroll: "boolean", + complete: "string", }; } static def(name: string): PropertyDef | undefined { - return defs.find(p => p.name === name); + return defs.find((p) => p.name === name); } static defs(): PropertyDef[] { diff --git a/src/shared/settings/Search.ts b/src/shared/settings/Search.ts index 7de03de..b25aa78 100644 --- a/src/shared/settings/Search.ts +++ b/src/shared/settings/Search.ts @@ -6,16 +6,12 @@ export type SearchJSON = { }; export default class Search { - constructor( - public defaultEngine: string, - public engines: Entries, - ) { - } + constructor(public defaultEngine: string, public engines: Entries) {} static fromJSON(json: SearchJSON): Search { for (const [name, url] of Object.entries(json.engines)) { - if (!(/^[a-zA-Z0-9]+$/).test(name)) { - throw new TypeError('Search engine\'s name must be [a-zA-Z0-9]+'); + if (!/^[a-zA-Z0-9]+$/.test(name)) { + throw new TypeError("Search engine's name must be [a-zA-Z0-9]+"); } const matches = url.match(/{}/g); if (matches === null) { diff --git a/src/shared/settings/Settings.ts b/src/shared/settings/Settings.ts index add5389..1bb9249 100644 --- a/src/shared/settings/Settings.ts +++ b/src/shared/settings/Settings.ts @@ -1,16 +1,16 @@ -import Ajv from 'ajv'; +import Ajv from "ajv"; -import Keymaps, { KeymapsJSON } from './Keymaps'; -import Search, { SearchJSON } from './Search'; -import Properties, { PropertiesJSON } from './Properties'; -import Blacklist, { BlacklistJSON } from './Blacklist'; -import validate from './validate'; +import Keymaps, { KeymapsJSON } from "./Keymaps"; +import Search, { SearchJSON } from "./Search"; +import Properties, { PropertiesJSON } from "./Properties"; +import Blacklist, { BlacklistJSON } from "./Blacklist"; +import validate from "./validate"; export type SettingsJSON = { - keymaps?: KeymapsJSON, - search?: SearchJSON, - properties?: PropertiesJSON, - blacklist?: BlacklistJSON, + keymaps?: KeymapsJSON; + search?: SearchJSON; + properties?: PropertiesJSON; + blacklist?: BlacklistJSON; }; export default class Settings { @@ -42,11 +42,11 @@ export default class Settings { static fromJSON(json: unknown): Settings { const valid = validate(json); if (!valid) { - const message = (validate as any).errors!! - .map((err: Ajv.ErrorObject) => { + const message = (validate as any) + .errors!!.map((err: Ajv.ErrorObject) => { return `'${err.dataPath}' ${err.message}`; }) - .join('; '); + .join("; "); throw new TypeError(message); } @@ -162,5 +162,6 @@ export const DefaultSettingJSONText = `{ ] }`; -export const DefaultSetting: Settings = - Settings.fromJSON(JSON.parse(DefaultSettingJSONText)); +export const DefaultSetting: Settings = Settings.fromJSON( + JSON.parse(DefaultSettingJSONText) +); diff --git a/src/shared/urls.ts b/src/shared/urls.ts index bac929e..2bfa44b 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -1,28 +1,28 @@ -import Search from './settings/Search'; +import Search from "./settings/Search"; const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 - return str.replace(/^\s+/, ''); + return str.replace(/^\s+/, ""); }; -const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ftp:', 'mailto:', 'about:']; +const SUPPORTED_PROTOCOLS = ["http:", "https:", "ftp:", "mailto:", "about:"]; const isLocalhost = (url: string): boolean => { - if (url === 'localhost') { + if (url === "localhost") { return true; } - const [host, port] = url.split(':', 2); - return host === 'localhost' && !isNaN(Number(port)); + const [host, port] = url.split(":", 2); + return host === "localhost" && !isNaN(Number(port)); }; const isMissingHttp = (keywords: string): boolean => { - if (keywords.includes('.') && !keywords.includes(' ')) { + if (keywords.includes(".") && !keywords.includes(" ")) { return true; } try { - const u = new URL('http://' + keywords); + const u = new URL("http://" + keywords); return isLocalhost(u.host); } catch (e) { // fallthrough @@ -41,18 +41,18 @@ const searchUrl = (keywords: string, search: Search): string => { } if (isMissingHttp(keywords)) { - return 'http://' + keywords; + return "http://" + keywords; } let template = search.engines[search.defaultEngine]; let query = keywords; - const first = trimStart(keywords).split(' ')[0]; + const first = trimStart(keywords).split(" ")[0]; if (Object.keys(search.engines).includes(first)) { template = search.engines[first]; query = trimStart(trimStart(keywords).slice(first.length)); } - return template.replace('{}', encodeURIComponent(query)); + return template.replace("{}", encodeURIComponent(query)); }; const normalizeUrl = (url: string): string => { @@ -64,7 +64,7 @@ const normalizeUrl = (url: string): string => { } catch (e) { // fallthrough } - return 'http://' + url; + return "http://" + url; }; export { searchUrl, normalizeUrl }; diff --git a/src/shared/utils/dom.ts b/src/shared/utils/dom.ts index a6186cb..0cf2ee8 100644 --- a/src/shared/utils/dom.ts +++ b/src/shared/utils/dom.ts @@ -1,9 +1,9 @@ const isContentEditable = (element: Element): boolean => { - const value = element.getAttribute('contenteditable'); + const value = element.getAttribute("contenteditable"); if (value === null) { return false; } - return value.toLowerCase() === 'true' || value.toLowerCase() === ''; + return value.toLowerCase() === "true" || value.toLowerCase() === ""; }; interface Rect { @@ -14,12 +14,12 @@ interface Rect { } const rectangleCoordsRect = (coords: string): Rect => { - const [left, top, right, bottom] = coords.split(',').map(n => Number(n)); + const [left, top, right, bottom] = coords.split(",").map((n) => Number(n)); return { left, top, right, bottom }; }; const circleCoordsRect = (coords: string): Rect => { - const [x, y, r] = coords.split(',').map(n => Number(n)); + const [x, y, r] = coords.split(",").map((n) => Number(n)); return { left: x - r, top: y - r, @@ -29,7 +29,7 @@ const circleCoordsRect = (coords: string): Rect => { }; const polygonCoordsRect = (coords: string): Rect => { - const params = coords.split(','); + const params = coords.split(","); let minx = Number(params[0]), maxx = Number(params[0]), miny = Number(params[1]), @@ -55,7 +55,7 @@ const polygonCoordsRect = (coords: string): Rect => { }; const viewportRect = (e: Element): Rect => { - if (e.tagName !== 'AREA') { + if (e.tagName !== "AREA") { return e.getBoundingClientRect(); } @@ -63,29 +63,26 @@ const viewportRect = (e: Element): Rect => { const imgElement = document.querySelector( `img[usemap="#${mapElement.name}"]` ) as HTMLImageElement; - const { - left: mapLeft, - top: mapTop - } = imgElement.getBoundingClientRect(); - const coords = e.getAttribute('coords'); + const { left: mapLeft, top: mapTop } = imgElement.getBoundingClientRect(); + const coords = e.getAttribute("coords"); if (!coords) { return e.getBoundingClientRect(); } let rect = { left: 0, top: 0, right: 0, bottom: 0 }; - switch (e.getAttribute('shape')) { - case 'rect': - case 'rectangle': - rect = rectangleCoordsRect(coords); - break; - case 'circ': - case 'circle': - rect = circleCoordsRect(coords); - break; - case 'poly': - case 'polygon': - rect = polygonCoordsRect(coords); - break; + switch (e.getAttribute("shape")) { + case "rect": + case "rectangle": + rect = rectangleCoordsRect(coords); + break; + case "circ": + case "circle": + rect = circleCoordsRect(coords); + break; + case "poly": + case "polygon": + rect = polygonCoordsRect(coords); + break; } return { left: rect.left + mapLeft, @@ -99,7 +96,7 @@ const isVisible = (element: Element): boolean => { const rect = element.getBoundingClientRect(); const style = window.getComputedStyle(element); - if (style.overflow !== 'visible' && (rect.width === 0 || rect.height === 0)) { + if (style.overflow !== "visible" && (rect.width === 0 || rect.height === 0)) { return false; } if (rect.right < 0 && rect.bottom < 0) { @@ -108,13 +105,15 @@ const isVisible = (element: Element): boolean => { if (window.innerWidth < rect.left && window.innerHeight < rect.top) { return false; } - if (element instanceof HTMLInputElement && - element.type.toLowerCase() === 'hidden') { + if ( + element instanceof HTMLInputElement && + element.type.toLowerCase() === "hidden" + ) { return false; } const { display, visibility } = window.getComputedStyle(element); - if (display === 'none' || visibility === 'hidden') { + if (display === "none" || visibility === "hidden") { return false; } return true; diff --git a/test/background/completion/OpenCompletionUseCase.test.ts b/test/background/completion/OpenCompletionUseCase.test.ts index 421ce69..f43e6c1 100644 --- a/test/background/completion/OpenCompletionUseCase.test.ts +++ b/test/background/completion/OpenCompletionUseCase.test.ts @@ -1,42 +1,48 @@ import "reflect-metadata"; import CompletionType from "../../../src/shared/CompletionType"; -import BookmarkRepository, {BookmarkItem} from "../../../src/background/completion/BookmarkRepository"; -import HistoryRepository, {HistoryItem} from "../../../src/background/completion/HistoryRepository"; +import BookmarkRepository, { + BookmarkItem, +} from "../../../src/background/completion/BookmarkRepository"; +import HistoryRepository, { + HistoryItem, +} from "../../../src/background/completion/HistoryRepository"; import OpenCompletionUseCase from "../../../src/background/completion/OpenCompletionUseCase"; import CachedSettingRepository from "../../../src/background/repositories/CachedSettingRepository"; -import Settings, {DefaultSetting} from "../../../src/shared/settings/Settings"; -import { expect } from 'chai'; -import sinon from 'sinon'; +import Settings, { + DefaultSetting, +} from "../../../src/shared/settings/Settings"; +import { expect } from "chai"; +import sinon from "sinon"; import Properties from "../../../src/shared/settings/Properties"; import Search from "../../../src/shared/settings/Search"; class MockBookmarkRepository implements BookmarkRepository { queryBookmarks(_query: string): Promise<BookmarkItem[]> { - throw new Error("not implemented") + throw new Error("not implemented"); } } class MockHistoryRepository implements HistoryRepository { queryHistories(_keywords: string): Promise<HistoryItem[]> { - throw new Error("not implemented") + throw new Error("not implemented"); } } class MockSettingRepository implements CachedSettingRepository { get(): Promise<Settings> { - throw new Error("not implemented") + throw new Error("not implemented"); } setProperty(_name: string, _value: string | number | boolean): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } update(_value: Settings): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } } -describe('OpenCompletionUseCase', () => { +describe("OpenCompletionUseCase", () => { let bookmarkRepository: MockBookmarkRepository; let historyRepository: MockHistoryRepository; let settingRepository: MockSettingRepository; @@ -46,63 +52,80 @@ describe('OpenCompletionUseCase', () => { bookmarkRepository = new MockBookmarkRepository(); historyRepository = new MockHistoryRepository(); settingRepository = new MockSettingRepository(); - sut = new OpenCompletionUseCase(bookmarkRepository, historyRepository, settingRepository) + sut = new OpenCompletionUseCase( + bookmarkRepository, + historyRepository, + settingRepository + ); }); - describe('#getCompletionTypes', () => { + describe("#getCompletionTypes", () => { it("returns completion types from the property", async () => { - sinon.stub(settingRepository, 'get').returns(Promise.resolve(new Settings({ - keymaps: DefaultSetting.keymaps, - search: DefaultSetting.search, - properties: new Properties({ complete: "shb" }), - blacklist: DefaultSetting.blacklist, - }))); + sinon.stub(settingRepository, "get").returns( + Promise.resolve( + new Settings({ + keymaps: DefaultSetting.keymaps, + search: DefaultSetting.search, + properties: new Properties({ complete: "shb" }), + blacklist: DefaultSetting.blacklist, + }) + ) + ); const items = await sut.getCompletionTypes(); expect(items).to.deep.equal([ CompletionType.SearchEngines, CompletionType.History, - CompletionType.Bookmarks + CompletionType.Bookmarks, ]); }); }); - describe('#requestSearchEngines', () => { + describe("#requestSearchEngines", () => { it("returns search engines matches by the query", async () => { - sinon.stub(settingRepository, 'get').returns(Promise.resolve(new Settings({ - keymaps: DefaultSetting.keymaps, - search: new Search("google", { - "google": "https://google.com/search?q={}", - "yahoo": "https://search.yahoo.com/search?q={}", - "bing": "https://bing.com/search?q={}", - "google_ja": "https://google.co.jp/search?q={}", - }), - properties: DefaultSetting.properties, - blacklist: DefaultSetting.blacklist, - }))); + sinon.stub(settingRepository, "get").returns( + Promise.resolve( + new Settings({ + keymaps: DefaultSetting.keymaps, + search: new Search("google", { + google: "https://google.com/search?q={}", + yahoo: "https://search.yahoo.com/search?q={}", + bing: "https://bing.com/search?q={}", + googleja: "https://google.co.jp/search?q={}", + }), + properties: DefaultSetting.properties, + blacklist: DefaultSetting.blacklist, + }) + ) + ); expect(await sut.requestSearchEngines("")).to.deep.equal([ "google", "yahoo", "bing", - "google_ja", + "googleja", ]); expect(await sut.requestSearchEngines("go")).to.deep.equal([ "google", - "google_ja", + "googleja", ]); expect(await sut.requestSearchEngines("x")).to.be.empty; - }) + }); }); - describe('#requestBookmarks', () => { - it("returns bookmarks from the repository", async() => { - sinon.stub(bookmarkRepository, 'queryBookmarks') - .withArgs("site").returns(Promise.resolve([ - { title: "site1", url: "https://site1.example.com" }, - { title: "site2", url: "https://site2.example.com/" }, - ])) - .withArgs("xyz").returns(Promise.resolve([])); + describe("#requestBookmarks", () => { + it("returns bookmarks from the repository", async () => { + sinon + .stub(bookmarkRepository, "queryBookmarks") + .withArgs("site") + .returns( + Promise.resolve([ + { title: "site1", url: "https://site1.example.com" }, + { title: "site2", url: "https://site2.example.com/" }, + ]) + ) + .withArgs("xyz") + .returns(Promise.resolve([])); expect(await sut.requestBookmarks("site")).to.deep.equal([ { title: "site1", url: "https://site1.example.com" }, @@ -112,14 +135,19 @@ describe('OpenCompletionUseCase', () => { }); }); - describe('#requestHistory', () => { - it("returns histories from the repository", async() => { - sinon.stub(historyRepository, 'queryHistories') - .withArgs("site").returns(Promise.resolve([ - { title: "site1", url: "https://site1.example.com" }, - { title: "site2", url: "https://site2.example.com/" }, - ])) - .withArgs("xyz").returns(Promise.resolve([])); + describe("#requestHistory", () => { + it("returns histories from the repository", async () => { + sinon + .stub(historyRepository, "queryHistories") + .withArgs("site") + .returns( + Promise.resolve([ + { title: "site1", url: "https://site1.example.com" }, + { title: "site2", url: "https://site2.example.com/" }, + ]) + ) + .withArgs("xyz") + .returns(Promise.resolve([])); expect(await sut.requestHistory("site")).to.deep.equal([ { title: "site1", url: "https://site1.example.com" }, @@ -128,4 +156,4 @@ describe('OpenCompletionUseCase', () => { expect(await sut.requestHistory("xyz")).to.be.empty; }); }); -});
\ No newline at end of file +}); diff --git a/test/background/completion/PropertyCompletionUseCase.test.ts b/test/background/completion/PropertyCompletionUseCase.test.ts index 57f5bff..dfc989f 100644 --- a/test/background/completion/PropertyCompletionUseCase.test.ts +++ b/test/background/completion/PropertyCompletionUseCase.test.ts @@ -1,15 +1,18 @@ -import 'reflect-metadata'; +import "reflect-metadata"; import PropertyCompletionUseCase from "../../../src/background/completion/PropertyCompletionUseCase"; -import { expect } from 'chai'; +import { expect } from "chai"; -describe('PropertyCompletionUseCase', () => { - describe('getProperties', () => { - it('returns property types', async () => { +describe("PropertyCompletionUseCase", () => { + describe("getProperties", () => { + it("returns property types", async () => { const sut = new PropertyCompletionUseCase(); const properties = await sut.getProperties(); - expect(properties).to.deep.contain({ name: 'smoothscroll', type: 'boolean' }); - expect(properties).to.deep.contain({ name: 'complete', type: 'string' }); - }) + expect(properties).to.deep.contain({ + name: "smoothscroll", + type: "boolean", + }); + expect(properties).to.deep.contain({ name: "complete", type: "string" }); + }); }); -});
\ No newline at end of file +}); diff --git a/test/background/completion/TabCompletionUseCase.test.ts b/test/background/completion/TabCompletionUseCase.test.ts index b9dc60b..d8aa385 100644 --- a/test/background/completion/TabCompletionUseCase.test.ts +++ b/test/background/completion/TabCompletionUseCase.test.ts @@ -1,85 +1,90 @@ -import "reflect-metadata" +import "reflect-metadata"; import TabRepositoryImpl from "../../../src/background/completion/impl/TabRepositoryImpl"; -import {Tab} from "../../../src/background/completion/TabRepository"; +import { Tab } from "../../../src/background/completion/TabRepository"; import TabPresenter from "../../../src/background/presenters/TabPresenter"; import TabCompletionUseCase from "../../../src/background/completion/TabCompletionUseCase"; -import sinon from 'sinon'; -import { expect } from 'chai'; +import sinon from "sinon"; +import { expect } from "chai"; import TabFlag from "../../../src/shared/TabFlag"; class MockTabRepository implements TabRepositoryImpl { async queryTabs(_query: string, _excludePinned: boolean): Promise<Tab[]> { - throw new Error("not implemented") + throw new Error("not implemented"); } async getAllTabs(_excludePinned: boolean): Promise<Tab[]> { - throw new Error("not implemented") + throw new Error("not implemented"); } } class MockTabPresenter implements TabPresenter { create(_url: string, _opts?: object): Promise<browser.tabs.Tab> { - throw new Error("not implemented") + throw new Error("not implemented"); } duplicate(_id: number): Promise<browser.tabs.Tab> { - throw new Error("not implemented") + throw new Error("not implemented"); } getAll(): Promise<browser.tabs.Tab[]> { - throw new Error("not implemented") + throw new Error("not implemented"); } - getByKeyword(_keyword: string, _excludePinned: boolean): Promise<browser.tabs.Tab[]> { - throw new Error("not implemented") + getByKeyword( + _keyword: string, + _excludePinned: boolean + ): Promise<browser.tabs.Tab[]> { + throw new Error("not implemented"); } getCurrent(): Promise<browser.tabs.Tab> { - throw new Error("not implemented") + throw new Error("not implemented"); } getLastSelectedId(): Promise<number | undefined> { - throw new Error("not implemented") + throw new Error("not implemented"); } getZoom(_tabId: number): Promise<number> { - throw new Error("not implemented") + throw new Error("not implemented"); } - onSelected(_listener: (arg: { tabId: number; windowId: number }) => void): void { - throw new Error("not implemented") + onSelected( + _listener: (arg: { tabId: number; windowId: number }) => void + ): void { + throw new Error("not implemented"); } open(_url: string, _tabId?: number): Promise<browser.tabs.Tab> { - throw new Error("not implemented") + throw new Error("not implemented"); } reload(_tabId: number, _cache: boolean): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } remove(_ids: number[]): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } reopen(): Promise<any> { - throw new Error("not implemented") + throw new Error("not implemented"); } select(_tabId: number): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } setPinned(_tabId: number, _pinned: boolean): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } setZoom(_tabId: number, _factor: number): Promise<void> { - throw new Error("not implemented") + throw new Error("not implemented"); } } -describe('TabCompletionUseCase', () => { +describe("TabCompletionUseCase", () => { let tabRepository: MockTabRepository; let tabPresenter: TabPresenter; let sut: TabCompletionUseCase; @@ -89,56 +94,169 @@ describe('TabCompletionUseCase', () => { tabPresenter = new MockTabPresenter(); sut = new TabCompletionUseCase(tabRepository, tabPresenter); - sinon.stub(tabPresenter, 'getLastSelectedId').returns(Promise.resolve(12)); - sinon.stub(tabRepository, 'getAllTabs').returns(Promise.resolve([ - { id: 10, index: 0, title: 'Google', url: 'https://google.com/', faviconUrl: 'https://google.com/favicon.ico', active: false }, - { id: 11, index: 1, title: 'Yahoo', url: 'https://yahoo.com/', faviconUrl: 'https://yahoo.com/favicon.ico', active: true }, - { id: 12, index: 2, title: 'Bing', url: 'https://bing.com/', active: false }, - ])); + sinon.stub(tabPresenter, "getLastSelectedId").returns(Promise.resolve(12)); + sinon.stub(tabRepository, "getAllTabs").returns( + Promise.resolve([ + { + id: 10, + index: 0, + title: "Google", + url: "https://google.com/", + faviconUrl: "https://google.com/favicon.ico", + active: false, + }, + { + id: 11, + index: 1, + title: "Yahoo", + url: "https://yahoo.com/", + faviconUrl: "https://yahoo.com/favicon.ico", + active: true, + }, + { + id: 12, + index: 2, + title: "Bing", + url: "https://bing.com/", + active: false, + }, + ]) + ); }); - describe('#queryTabs', () => { + describe("#queryTabs", () => { it("returns tab items", async () => { - sinon.stub(tabRepository, 'queryTabs').withArgs('', false).returns(Promise.resolve([ - { id: 10, index: 0, title: 'Google', url: 'https://google.com/', faviconUrl: 'https://google.com/favicon.ico', active: false }, - { id: 11, index: 1, title: 'Yahoo', url: 'https://yahoo.com/', faviconUrl: 'https://yahoo.com/favicon.ico', active: true }, - { id: 12, index: 2, title: 'Bing', url: 'https://bing.com/', active: false }, - ])).withArgs('oo', false).returns(Promise.resolve([ - { id: 10, index: 0, title: 'Google', url: 'https://google.com/', faviconUrl: 'https://google.com/favicon.ico', active: false }, - { id: 11, index: 1, title: 'Yahoo', url: 'https://yahoo.com/', faviconUrl: 'https://yahoo.com/favicon.ico', active: true }, - ])); - - expect(await sut.queryTabs('', false)).to.deep.equal([ - { index: 1, title: 'Google', url: 'https://google.com/', faviconUrl: 'https://google.com/favicon.ico', flag: TabFlag.None }, - { index: 2, title: 'Yahoo', url: 'https://yahoo.com/', faviconUrl: 'https://yahoo.com/favicon.ico', flag: TabFlag.CurrentTab }, - { index: 3, title: 'Bing', url: 'https://bing.com/', faviconUrl: undefined, flag: TabFlag.LastTab }, + sinon + .stub(tabRepository, "queryTabs") + .withArgs("", false) + .returns( + Promise.resolve([ + { + id: 10, + index: 0, + title: "Google", + url: "https://google.com/", + faviconUrl: "https://google.com/favicon.ico", + active: false, + }, + { + id: 11, + index: 1, + title: "Yahoo", + url: "https://yahoo.com/", + faviconUrl: "https://yahoo.com/favicon.ico", + active: true, + }, + { + id: 12, + index: 2, + title: "Bing", + url: "https://bing.com/", + active: false, + }, + ]) + ) + .withArgs("oo", false) + .returns( + Promise.resolve([ + { + id: 10, + index: 0, + title: "Google", + url: "https://google.com/", + faviconUrl: "https://google.com/favicon.ico", + active: false, + }, + { + id: 11, + index: 1, + title: "Yahoo", + url: "https://yahoo.com/", + faviconUrl: "https://yahoo.com/favicon.ico", + active: true, + }, + ]) + ); + + expect(await sut.queryTabs("", false)).to.deep.equal([ + { + index: 1, + title: "Google", + url: "https://google.com/", + faviconUrl: "https://google.com/favicon.ico", + flag: TabFlag.None, + }, + { + index: 2, + title: "Yahoo", + url: "https://yahoo.com/", + faviconUrl: "https://yahoo.com/favicon.ico", + flag: TabFlag.CurrentTab, + }, + { + index: 3, + title: "Bing", + url: "https://bing.com/", + faviconUrl: undefined, + flag: TabFlag.LastTab, + }, ]); - expect(await sut.queryTabs('oo', false)).to.deep.equal([ - { index: 1, title: 'Google', url: 'https://google.com/', faviconUrl: 'https://google.com/favicon.ico', flag: TabFlag.None }, - { index: 2, title: 'Yahoo', url: 'https://yahoo.com/', faviconUrl: 'https://yahoo.com/favicon.ico', flag: TabFlag.CurrentTab }, + expect(await sut.queryTabs("oo", false)).to.deep.equal([ + { + index: 1, + title: "Google", + url: "https://google.com/", + faviconUrl: "https://google.com/favicon.ico", + flag: TabFlag.None, + }, + { + index: 2, + title: "Yahoo", + url: "https://yahoo.com/", + faviconUrl: "https://yahoo.com/favicon.ico", + flag: TabFlag.CurrentTab, + }, ]); }); it("returns a tab by the index", async () => { - expect(await sut.queryTabs('1', false)).to.deep.equal([ - { index: 1, title: 'Google', url: 'https://google.com/', faviconUrl: 'https://google.com/favicon.ico', flag: TabFlag.None }, + expect(await sut.queryTabs("1", false)).to.deep.equal([ + { + index: 1, + title: "Google", + url: "https://google.com/", + faviconUrl: "https://google.com/favicon.ico", + flag: TabFlag.None, + }, ]); - expect(await sut.queryTabs('10', false)).to.be.empty; - expect(await sut.queryTabs('-1', false)).to.be.empty; + expect(await sut.queryTabs("10", false)).to.be.empty; + expect(await sut.queryTabs("-1", false)).to.be.empty; }); it("returns the current tab by % flag", async () => { - expect(await sut.queryTabs('%', false)).to.deep.equal([ - { index: 2, title: 'Yahoo', url: 'https://yahoo.com/', faviconUrl: 'https://yahoo.com/favicon.ico', flag: TabFlag.CurrentTab }, + expect(await sut.queryTabs("%", false)).to.deep.equal([ + { + index: 2, + title: "Yahoo", + url: "https://yahoo.com/", + faviconUrl: "https://yahoo.com/favicon.ico", + flag: TabFlag.CurrentTab, + }, ]); }); it("returns the current tab by # flag", async () => { - expect(await sut.queryTabs('#', false)).to.deep.equal([ - { index: 3, title: 'Bing', url: 'https://bing.com/', faviconUrl: undefined, flag: TabFlag.LastTab }, + expect(await sut.queryTabs("#", false)).to.deep.equal([ + { + index: 3, + title: "Bing", + url: "https://bing.com/", + faviconUrl: undefined, + flag: TabFlag.LastTab, + }, ]); - }) + }); }); -});
\ No newline at end of file +}); diff --git a/test/background/completion/impl/PrefetchAndCache.test.ts b/test/background/completion/impl/PrefetchAndCache.test.ts index 23e3879..b24dfa9 100644 --- a/test/background/completion/impl/PrefetchAndCache.test.ts +++ b/test/background/completion/impl/PrefetchAndCache.test.ts @@ -1,39 +1,39 @@ -import PrefetchAndCache, {shortKey} from "../../../../src/background/completion/impl/PrefetchAndCache"; -import { expect } from 'chai'; +import PrefetchAndCache, { + shortKey, +} from "../../../../src/background/completion/impl/PrefetchAndCache"; +import { expect } from "chai"; class MockRepository { public history: string[] = []; - constructor( - private items: string[], - ) { - } + constructor(private items: string[]) {} get(query: string): Promise<string[]> { this.history.push(query); if (query.length === 0) { return Promise.resolve(this.items); } else { - return Promise.resolve(this.items.filter(item => item.includes(query))); + return Promise.resolve(this.items.filter((item) => item.includes(query))); } } } -const filter = (items: string[], query: string) => query.length === 0 ? items : items.filter(item => item.includes(query)); +const filter = (items: string[], query: string) => + query.length === 0 ? items : items.filter((item) => item.includes(query)); -describe('shortKey', () => { - it('returns query excluding the last word', () => { - const query = "hello\t world good bye"; - const shorten = shortKey(query); - expect(shorten).to.equal("hello world good") +describe("shortKey", () => { + it("returns query excluding the last word", () => { + const query = "hello\t world good bye"; + const shorten = shortKey(query); + expect(shorten).to.equal("hello world good"); }); - it('returns half-length of the query', () => { + it("returns half-length of the query", () => { const query = "the-query-with-super-long-word"; const shorten = shortKey(query); - expect(shorten).to.equal("the-query-with-") + expect(shorten).to.equal("the-query-with-"); }); - it('returns shorten URL', () => { + it("returns shorten URL", () => { let query = "https://example.com/path/to/resource?q=hello"; let shorten = shortKey(query); expect(shorten).to.equal("https://example.com/path/to/"); @@ -45,20 +45,39 @@ describe('shortKey', () => { query = "https://www.google.c"; shorten = shortKey(query); expect(shorten).to.equal("https://ww"); - }) + }); }); -describe('PrefetchAndCache', () => { - describe('get', () => { - it('returns cached request', async() => { - const repo = new MockRepository(["apple", "apple pie", "apple juice", "banana", "banana pudding", "cherry"]); +describe("PrefetchAndCache", () => { + describe("get", () => { + it("returns cached request", async () => { + const repo = new MockRepository([ + "apple", + "apple pie", + "apple juice", + "banana", + "banana pudding", + "cherry", + ]); const sut = new PrefetchAndCache(repo.get.bind(repo), filter); expect(await sut.get("apple pie")).deep.equal(["apple pie"]); - expect(await sut.get("apple ")).deep.equal(["apple", "apple pie", "apple juice"]); - expect(await sut.get("apple")).deep.equal(["apple", "apple pie", "apple juice"]); - expect(await sut.get("appl")).deep.equal(["apple", "apple pie", "apple juice"]); - expect(repo.history).to.deep.equal(["apple", 'ap']); + expect(await sut.get("apple ")).deep.equal([ + "apple", + "apple pie", + "apple juice", + ]); + expect(await sut.get("apple")).deep.equal([ + "apple", + "apple pie", + "apple juice", + ]); + expect(await sut.get("appl")).deep.equal([ + "apple", + "apple pie", + "apple juice", + ]); + expect(repo.history).to.deep.equal(["apple", "ap"]); expect(await sut.get("banana")).deep.equal(["banana", "banana pudding"]); expect(repo.history).to.deep.equal(["apple", "ap", "ban"]); @@ -68,7 +87,14 @@ describe('PrefetchAndCache', () => { expect(repo.history).to.deep.equal(["apple", "ap", "ban", "banana", "b"]); expect(await sut.get("")).to.have.lengthOf(6); - expect(repo.history).to.deep.equal(["apple", "ap", "ban", "banana", "b", ""]); + expect(repo.history).to.deep.equal([ + "apple", + "ap", + "ban", + "banana", + "b", + "", + ]); }); }); -});
\ No newline at end of file +}); diff --git a/test/background/completion/impl/filters.test.ts b/test/background/completion/impl/filters.test.ts index a181f60..70c2663 100644 --- a/test/background/completion/impl/filters.test.ts +++ b/test/background/completion/impl/filters.test.ts @@ -1,87 +1,89 @@ -import * as filters from '../../../../src/background/completion/impl/filters' -import { expect } from 'chai'; +import * as filters from "../../../../src/background/completion/impl/filters"; +import { expect } from "chai"; -describe('background/usecases/filters', () => { - describe('filterHttp', () => { - it('filters http URLs duplicates to https hosts', () => { +describe("background/usecases/filters", () => { + describe("filterHttp", () => { + it("filters http URLs duplicates to https hosts", () => { const pages = [ - { id: '0', url: 'http://i-beam.org/foo' }, - { id: '1', url: 'https://i-beam.org/bar' }, - { id: '2', url: 'http://i-beam.net/hoge' }, - { id: '3', url: 'http://i-beam.net/fuga' }, + { id: "0", url: "http://i-beam.org/foo" }, + { id: "1", url: "https://i-beam.org/bar" }, + { id: "2", url: "http://i-beam.net/hoge" }, + { id: "3", url: "http://i-beam.net/fuga" }, ]; const filtered = filters.filterHttp(pages); - const urls = filtered.map(x => x.url); + const urls = filtered.map((x) => x.url); expect(urls).to.deep.equal([ - 'https://i-beam.org/bar', 'http://i-beam.net/hoge', 'http://i-beam.net/fuga' + "https://i-beam.org/bar", + "http://i-beam.net/hoge", + "http://i-beam.net/fuga", ]); - }) + }); }); - describe('filterBlankTitle', () => { - it('filters blank titles', () => { + describe("filterBlankTitle", () => { + it("filters blank titles", () => { const pages = [ - { id: '0', title: 'hello' }, - { id: '1', title: '' }, - { id: '2' }, + { id: "0", title: "hello" }, + { id: "1", title: "" }, + { id: "2" }, ]; const filtered = filters.filterBlankTitle(pages); - expect(filtered).to.deep.equal([{ id: '0', title: 'hello' }]); + expect(filtered).to.deep.equal([{ id: "0", title: "hello" }]); }); }); - describe('filterByTailingSlash', () => { - it('filters duplicated pathname on tailing slash', () => { + describe("filterByTailingSlash", () => { + it("filters duplicated pathname on tailing slash", () => { const pages = [ - { id: '0', url: 'http://i-beam.org/content' }, - { id: '1', url: 'http://i-beam.org/content/' }, - { id: '2', url: 'http://i-beam.org/search' }, - { id: '3', url: 'http://i-beam.org/search?q=apple_banana_cherry' }, + { id: "0", url: "http://i-beam.org/content" }, + { id: "1", url: "http://i-beam.org/content/" }, + { id: "2", url: "http://i-beam.org/search" }, + { id: "3", url: "http://i-beam.org/search?q=apple_banana_cherry" }, ]; const filtered = filters.filterByTailingSlash(pages); - const urls = filtered.map(x => x.url); + const urls = filtered.map((x) => x.url); expect(urls).to.deep.equal([ - 'http://i-beam.org/content', - 'http://i-beam.org/search', - 'http://i-beam.org/search?q=apple_banana_cherry', + "http://i-beam.org/content", + "http://i-beam.org/search", + "http://i-beam.org/search?q=apple_banana_cherry", ]); }); - }) + }); - describe('filterByPathname', () => { - it('filters by length of pathname', () => { + describe("filterByPathname", () => { + it("filters by length of pathname", () => { const pages = [ - { id: '0', url: 'http://i-beam.org/search?q=apple' }, - { id: '1', url: 'http://i-beam.org/search?q=apple_banana' }, - { id: '2', url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - { id: '3', url: 'http://i-beam.net/search?q=apple' }, - { id: '4', url: 'http://i-beam.net/search?q=apple_banana' }, - { id: '5', url: 'http://i-beam.net/search?q=apple_banana_cherry' }, + { id: "0", url: "http://i-beam.org/search?q=apple" }, + { id: "1", url: "http://i-beam.org/search?q=apple_banana" }, + { id: "2", url: "http://i-beam.org/search?q=apple_banana_cherry" }, + { id: "3", url: "http://i-beam.net/search?q=apple" }, + { id: "4", url: "http://i-beam.net/search?q=apple_banana" }, + { id: "5", url: "http://i-beam.net/search?q=apple_banana_cherry" }, ]; const filtered = filters.filterByPathname(pages); expect(filtered).to.deep.equal([ - { id: '0', url: 'http://i-beam.org/search?q=apple' }, - { id: '3', url: 'http://i-beam.net/search?q=apple' }, + { id: "0", url: "http://i-beam.org/search?q=apple" }, + { id: "3", url: "http://i-beam.net/search?q=apple" }, ]); }); }); - describe('filterByOrigin', () => { - it('filters by length of pathname', () => { + describe("filterByOrigin", () => { + it("filters by length of pathname", () => { const pages = [ - { id: '0', url: 'http://i-beam.org/search?q=apple' }, - { id: '1', url: 'http://i-beam.org/search?q=apple_banana' }, - { id: '2', url: 'http://i-beam.org/search?q=apple_banana_cherry' }, - { id: '3', url: 'http://i-beam.org/request?q=apple' }, - { id: '4', url: 'http://i-beam.org/request?q=apple_banana' }, - { id: '5', url: 'http://i-beam.org/request?q=apple_banana_cherry' }, + { id: "0", url: "http://i-beam.org/search?q=apple" }, + { id: "1", url: "http://i-beam.org/search?q=apple_banana" }, + { id: "2", url: "http://i-beam.org/search?q=apple_banana_cherry" }, + { id: "3", url: "http://i-beam.org/request?q=apple" }, + { id: "4", url: "http://i-beam.org/request?q=apple_banana" }, + { id: "5", url: "http://i-beam.org/request?q=apple_banana_cherry" }, ]; const filtered = filters.filterByOrigin(pages); expect(filtered).to.deep.equal([ - { id: '0', url: 'http://i-beam.org/search?q=apple' }, + { id: "0", url: "http://i-beam.org/search?q=apple" }, ]); }); }); diff --git a/test/background/infrastructures/MemoryStorage.test.ts b/test/background/infrastructures/MemoryStorage.test.ts index ccdf9f0..1c67b18 100644 --- a/test/background/infrastructures/MemoryStorage.test.ts +++ b/test/background/infrastructures/MemoryStorage.test.ts @@ -1,44 +1,45 @@ -import MemoryStorage from 'background/infrastructures/MemoryStorage'; +import MemoryStorage from "../../../src/background/infrastructures/MemoryStorage"; +import { expect } from "chai"; describe("background/infrastructures/memory-storage", () => { - it('stores values', () => { + it("stores values", () => { const cache = new MemoryStorage(); - cache.set('number', 123); - expect(cache.get('number')).to.equal(123); + cache.set("number", 123); + expect(cache.get("number")).to.equal(123); - cache.set('string', '123'); - expect(cache.get('string')).to.equal('123'); + cache.set("string", "123"); + expect(cache.get("string")).to.equal("123"); - cache.set('object', { hello: '123' }); - expect(cache.get('object')).to.deep.equal({ hello: '123' }); + cache.set("object", { hello: "123" }); + expect(cache.get("object")).to.deep.equal({ hello: "123" }); }); - it('returns undefined if no keys', () => { + it("returns undefined if no keys", () => { const cache = new MemoryStorage(); - expect(cache.get('no-keys')).to.be.undefined; - }) + expect(cache.get("no-keys")).to.be.undefined; + }); - it('stored on shared memory', () => { + it("stored on shared memory", () => { let cache = new MemoryStorage(); - cache.set('red', 'apple'); + cache.set("red", "apple"); cache = new MemoryStorage(); - const got = cache.get('red'); - expect(got).to.equal('apple'); + const got = cache.get("red"); + expect(got).to.equal("apple"); }); - it('stored cloned objects', () => { + it("stored cloned objects", () => { const cache = new MemoryStorage(); - const recipe = { sugar: '300g' }; - cache.set('recipe', recipe); + const recipe = { sugar: "300g", salt: "10g" }; + cache.set("recipe", recipe); - recipe.salt = '20g' - const got = cache.get('recipe', recipe); - expect(got).to.deep.equal({ sugar: '300g' }); + recipe.salt = "20g"; + const got = cache.get("recipe"); + expect(got).to.deep.equal({ sugar: "300g", salt: "10g" }); }); - it('throws an error with unserializable objects', () => { + it("throws an error with unserializable objects", () => { const cache = new MemoryStorage(); - expect(() => cache.set('fn', setTimeout)).to.throw(); - }) + expect(() => cache.set("fn", setTimeout)).to.throw(); + }); }); diff --git a/test/background/repositories/Mark.test.ts b/test/background/repositories/Mark.test.ts index ed1a68e..5cee5b6 100644 --- a/test/background/repositories/Mark.test.ts +++ b/test/background/repositories/Mark.test.ts @@ -1,24 +1,25 @@ -import MarkRepository from 'background/repositories/MarkRepository'; +import MarkRepository from "../../../src/background/repositories/MarkRepository"; +import { expect } from "chai"; -describe('background/repositories/mark', () => { +describe("background/repositories/mark", () => { let repository: MarkRepository; beforeEach(() => { repository = new MarkRepository(); }); - it('get and set', async() => { - const mark = { tabId: 1, url: 'http://example.com', x: 10, y: 30 }; + it("get and set", async () => { + const mark = { tabId: 1, url: "http://example.com", x: 10, y: 30 }; - repository.setMark('A', mark); + await repository.setMark("A", mark); - let got = await repository.getMark('A'); + let got = (await repository.getMark("A"))!!; expect(got.tabId).to.equal(1); - expect(got.url).to.equal('http://example.com'); + expect(got.url).to.equal("http://example.com"); expect(got.x).to.equal(10); expect(got.y).to.equal(30); - got = await repository.getMark('B'); + got = (await repository.getMark("B"))!!; expect(got).to.be.undefined; }); }); diff --git a/test/background/usecases/NavigateUseCase.test.ts b/test/background/usecases/NavigateUseCase.test.ts index 7ad0e4f..7263627 100644 --- a/test/background/usecases/NavigateUseCase.test.ts +++ b/test/background/usecases/NavigateUseCase.test.ts @@ -1,8 +1,8 @@ import "reflect-metadata"; -import TabPresenter from '../../../src/background/presenters/TabPresenter'; -import NavigateUseCase from '../../../src/background/usecases/NavigateUseCase'; -import NavigateClient from '../../../src/background/clients/NavigateClient'; -import * as sinon from 'sinon'; +import TabPresenter from "../../../src/background/presenters/TabPresenter"; +import NavigateUseCase from "../../../src/background/usecases/NavigateUseCase"; +import NavigateClient from "../../../src/background/clients/NavigateClient"; +import * as sinon from "sinon"; class MockTabPresenter implements TabPresenter { create(_url: string, _opts?: object): Promise<browser.tabs.Tab> { @@ -17,7 +17,10 @@ class MockTabPresenter implements TabPresenter { throw new Error("not implemented"); } - getByKeyword(_keyword: string, _excludePinned: boolean): Promise<browser.tabs.Tab[]> { + getByKeyword( + _keyword: string, + _excludePinned: boolean + ): Promise<browser.tabs.Tab[]> { throw new Error("not implemented"); } @@ -33,7 +36,9 @@ class MockTabPresenter implements TabPresenter { throw new Error("not implemented"); } - onSelected(_listener: (arg: { tabId: number; windowId: number }) => void): void { + onSelected( + _listener: (arg: { tabId: number; windowId: number }) => void + ): void { throw new Error("not implemented"); } @@ -66,7 +71,7 @@ class MockTabPresenter implements TabPresenter { } } -describe('NavigateUseCase', () => { +describe("NavigateUseCase", () => { let sut: NavigateUseCase; let tabPresenter: TabPresenter; let navigateClient: NavigateClient; @@ -80,7 +85,7 @@ describe('NavigateUseCase', () => { const newTab = (url: string): browser.tabs.Tab => { return { index: 0, - title: 'dummy title', + title: "dummy title", url: url, active: true, hidden: false, @@ -91,53 +96,67 @@ describe('NavigateUseCase', () => { lastAccessed: 1585446733000, pinned: false, selected: false, - windowId: 0 + windowId: 0, }; }; - describe('#openParent()', async () => { - it('opens parent directory of file', async() => { - sinon.stub(tabPresenter, 'getCurrent') - .returns(Promise.resolve(newTab('https://google.com/fruits/yellow/banana'))); + describe("#openParent()", async () => { + it("opens parent directory of file", async () => { + sinon + .stub(tabPresenter, "getCurrent") + .returns( + Promise.resolve(newTab("https://google.com/fruits/yellow/banana")) + ); - const mock = sinon.mock(tabPresenter) - .expects('open').withArgs('https://google.com/fruits/yellow/'); + const mock = sinon + .mock(tabPresenter) + .expects("open") + .withArgs("https://google.com/fruits/yellow/"); await sut.openParent(); mock.verify(); }); - it('opens parent directory of directory', async() => { - sinon.stub(tabPresenter, 'getCurrent') - .returns(Promise.resolve(newTab('https://google.com/fruits/yellow/'))); + it("opens parent directory of directory", async () => { + sinon + .stub(tabPresenter, "getCurrent") + .returns(Promise.resolve(newTab("https://google.com/fruits/yellow/"))); - const mock = sinon.mock(tabPresenter) - .expects('open').withArgs('https://google.com/fruits/'); + const mock = sinon + .mock(tabPresenter) + .expects("open") + .withArgs("https://google.com/fruits/"); await sut.openParent(); mock.verify(); }); - it('removes hash', async() => { - sinon.stub(tabPresenter, 'getCurrent') - .returns(Promise.resolve(newTab('https://google.com/#top'))); + it("removes hash", async () => { + sinon + .stub(tabPresenter, "getCurrent") + .returns(Promise.resolve(newTab("https://google.com/#top"))); - const mock = sinon.mock(tabPresenter) - .expects('open').withArgs('https://google.com/'); + const mock = sinon + .mock(tabPresenter) + .expects("open") + .withArgs("https://google.com/"); await sut.openParent(); mock.verify(); }); - it('removes search query', async() => { - sinon.stub(tabPresenter, 'getCurrent') - .returns(Promise.resolve(newTab('https://google.com/search?q=apple'))); + it("removes search query", async () => { + sinon + .stub(tabPresenter, "getCurrent") + .returns(Promise.resolve(newTab("https://google.com/search?q=apple"))); - const mock = sinon.mock(tabPresenter) - .expects('open').withArgs('https://google.com/search'); + const mock = sinon + .mock(tabPresenter) + .expects("open") + .withArgs("https://google.com/search"); await sut.openParent(); @@ -145,13 +164,16 @@ describe('NavigateUseCase', () => { }); }); - describe('#openRoot()', () => { - it('opens root direectory', async() => { - sinon.stub(tabPresenter, 'getCurrent') - .returns(Promise.resolve(newTab('https://google.com/seach?q=apple'))); + describe("#openRoot()", () => { + it("opens root direectory", async () => { + sinon + .stub(tabPresenter, "getCurrent") + .returns(Promise.resolve(newTab("https://google.com/seach?q=apple"))); - const mock = sinon.mock(tabPresenter) - .expects('open').withArgs('https://google.com'); + const mock = sinon + .mock(tabPresenter) + .expects("open") + .withArgs("https://google.com"); await sut.openRoot(); diff --git a/test/background/usecases/SettingUseCase.test.ts b/test/background/usecases/SettingUseCase.test.ts index bfa599c..c604e91 100644 --- a/test/background/usecases/SettingUseCase.test.ts +++ b/test/background/usecases/SettingUseCase.test.ts @@ -1,21 +1,22 @@ import "reflect-metadata"; import SettingUseCase from "../../../src/background/usecases/SettingUseCase"; import SettingRepository from "../../../src/background/repositories/SettingRepository"; -import SettingData, {JSONTextSettings} from "../../../src/shared/SettingData"; +import SettingData, { JSONTextSettings } from "../../../src/shared/SettingData"; import CachedSettingRepository from "../../../src/background/repositories/CachedSettingRepository"; -import Settings, {DefaultSetting} from "../../../src/shared/settings/Settings"; +import Settings, { + DefaultSetting, +} from "../../../src/shared/settings/Settings"; import Notifier from "../../../src/background/presenters/Notifier"; -import {expect} from "chai"; +import { expect } from "chai"; import Properties from "../../../src/shared/settings/Properties"; -import sinon from 'sinon'; +import sinon from "sinon"; class MockSettingRepository implements SettingRepository { load(): Promise<SettingData | null> { throw new Error("not implemented"); } - onChange(_: () => void): void { - } + onChange(_: () => void): void {} } class MockCachedSettingRepository implements CachedSettingRepository { @@ -46,12 +47,12 @@ class NopNotifier implements Notifier { } } -describe('SettingUseCase', () => { - let localSettingRepository : SettingRepository; - let syncSettingRepository : SettingRepository; - let cachedSettingRepository : CachedSettingRepository; +describe("SettingUseCase", () => { + let localSettingRepository: SettingRepository; + let syncSettingRepository: SettingRepository; + let cachedSettingRepository: CachedSettingRepository; let notifier: Notifier; - let sut : SettingUseCase; + let sut: SettingUseCase; beforeEach(() => { localSettingRepository = new MockSettingRepository(); @@ -66,34 +67,34 @@ describe('SettingUseCase', () => { ); }); - describe('getCached', () => { + describe("getCached", () => { it("returns cached settings", async () => { const settings = new Settings({ keymaps: DefaultSetting.keymaps, search: DefaultSetting.search, blacklist: DefaultSetting.blacklist, properties: new Properties({ - hintchars: "abcd1234" + hintchars: "abcd1234", }), }); - sinon.stub(cachedSettingRepository, "get") + sinon + .stub(cachedSettingRepository, "get") .returns(Promise.resolve(settings)); const got = await sut.getCached(); expect(got.properties.hintchars).to.equal("abcd1234"); - }); }); describe("reload", () => { context("when sync is not set", () => { - it("loads settings from local storage", async() => { + it("loads settings from local storage", async () => { const settings = new Settings({ keymaps: DefaultSetting.keymaps, search: DefaultSetting.search, blacklist: DefaultSetting.blacklist, properties: new Properties({ - hintchars: "abcd1234" + hintchars: "abcd1234", }), }); const settingData = SettingData.fromJSON({ @@ -101,9 +102,11 @@ describe('SettingUseCase', () => { json: JSONTextSettings.fromSettings(settings).toJSONText(), }); - sinon.stub(syncSettingRepository, "load") + sinon + .stub(syncSettingRepository, "load") .returns(Promise.resolve(null)); - sinon.stub(localSettingRepository, "load") + sinon + .stub(localSettingRepository, "load") .returns(Promise.resolve(settingData)); await sut.reload(); @@ -114,13 +117,13 @@ describe('SettingUseCase', () => { }); context("when local is not set", () => { - it("loads settings from sync storage", async() => { + it("loads settings from sync storage", async () => { const settings = new Settings({ keymaps: DefaultSetting.keymaps, search: DefaultSetting.search, blacklist: DefaultSetting.blacklist, properties: new Properties({ - hintchars: "aaaa1111" + hintchars: "aaaa1111", }), }); const settingData = SettingData.fromJSON({ @@ -128,9 +131,11 @@ describe('SettingUseCase', () => { json: JSONTextSettings.fromSettings(settings).toJSONText(), }); - sinon.stub(syncSettingRepository, "load") + sinon + .stub(syncSettingRepository, "load") .returns(Promise.resolve(settingData)); - sinon.stub(localSettingRepository, "load") + sinon + .stub(localSettingRepository, "load") .returns(Promise.resolve(null)); await sut.reload(); @@ -141,21 +146,23 @@ describe('SettingUseCase', () => { }); context("neither local nor sync not set", () => { - it("loads default settings", async() => { - it("loads settings from sync storage", async() => { - sinon.stub(syncSettingRepository, "load") + it("loads default settings", async () => { + it("loads settings from sync storage", async () => { + sinon + .stub(syncSettingRepository, "load") .returns(Promise.resolve(null)); - sinon.stub(localSettingRepository, "load") + sinon + .stub(localSettingRepository, "load") .returns(Promise.resolve(null)); await sut.reload(); const current = await cachedSettingRepository.get(); - expect(current.properties.hintchars).to.equal(DefaultSetting.properties.hintchars); + expect(current.properties.hintchars).to.equal( + DefaultSetting.properties.hintchars + ); }); - - }) - }) - }) + }); + }); + }); }); - diff --git a/test/background/usecases/parsers.test.ts b/test/background/usecases/parsers.test.ts index d08de0d..019b56e 100644 --- a/test/background/usecases/parsers.test.ts +++ b/test/background/usecases/parsers.test.ts @@ -1,34 +1,44 @@ -import * as parsers from 'background/usecases/parsers'; +import * as parsers from "../../../src/background/usecases/parsers"; +import { expect } from "chai"; describe("shared/commands/parsers", () => { describe("#parsers.parseSetOption", () => { - it('parse set string', () => { - const [key, value] = parsers.parseSetOption('hintchars=abcdefgh'); - expect(key).to.equal('hintchars'); - expect(value).to.equal('abcdefgh'); + it("parse set string", () => { + const [key, value] = parsers.parseSetOption("hintchars=abcdefgh"); + expect(key).to.equal("hintchars"); + expect(value).to.equal("abcdefgh"); }); - it('parse set empty string', () => { - const [key, value] = parsers.parseSetOption('hintchars='); - expect(key).to.equal('hintchars'); - expect(value).to.equal(''); + it("parse set empty string", () => { + const [key, value] = parsers.parseSetOption("hintchars="); + expect(key).to.equal("hintchars"); + expect(value).to.equal(""); }); - it('parse set boolean', () => { - let [key, value] = parsers.parseSetOption('smoothscroll'); - expect(key).to.equal('smoothscroll'); + it("parse set boolean", () => { + let [key, value] = parsers.parseSetOption("smoothscroll"); + expect(key).to.equal("smoothscroll"); expect(value).to.be.true; - [key, value] = parsers.parseSetOption('nosmoothscroll'); - expect(key).to.equal('smoothscroll'); + [key, value] = parsers.parseSetOption("nosmoothscroll"); + expect(key).to.equal("smoothscroll"); expect(value).to.be.false; }); - it('throws error on unknown property', () => { - expect(() => parsers.parseSetOption('encoding=utf-8')).to.throw(Error, 'Unknown'); - expect(() => parsers.parseSetOption('paste')).to.throw(Error, 'Unknown'); - expect(() => parsers.parseSetOption('nopaste')).to.throw(Error, 'Unknown'); - expect(() => parsers.parseSetOption('smoothscroll=yes')).to.throw(Error, 'Invalid argument'); + it("throws error on unknown property", () => { + expect(() => parsers.parseSetOption("encoding=utf-8")).to.throw( + Error, + "Unknown" + ); + expect(() => parsers.parseSetOption("paste")).to.throw(Error, "Unknown"); + expect(() => parsers.parseSetOption("nopaste")).to.throw( + Error, + "Unknown" + ); + expect(() => parsers.parseSetOption("smoothscroll=yes")).to.throw( + Error, + "Invalid argument" + ); }); }); }); diff --git a/test/console/actions/console.test.ts b/test/console/actions/console.test.ts index e6567b2..3169c4b 100644 --- a/test/console/actions/console.test.ts +++ b/test/console/actions/console.test.ts @@ -1,69 +1,77 @@ -import * as actions from '../../../src/console/actions'; -import * as consoleActions from '../../../src/console/actions/console'; -import { expect } from 'chai'; +import * as actions from "../../../src/console/actions"; +import * as consoleActions from "../../../src/console/actions/console"; +import { expect } from "chai"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-ignore +// @ts-ignore +import browserFake from "webextensions-api-fake"; describe("console actions", () => { - describe('hide', () => { - it('create CONSOLE_HIDE action', () => { + beforeEach(() => { + (global as any).browser = browserFake(); + }); + + describe("hide", () => { + it("create CONSOLE_HIDE action", () => { const action = consoleActions.hide(); expect(action.type).to.equal(actions.CONSOLE_HIDE); }); }); describe("showCommand", () => { - it('create CONSOLE_SHOW_COMMAND action', async () => { - const action = await consoleActions.showCommand('hello'); + it("create CONSOLE_SHOW_COMMAND action", async () => { + const action = await consoleActions.showCommand("hello"); expect(action.type).to.equal(actions.CONSOLE_SHOW_COMMAND); - expect(action.text).to.equal('hello'); + expect(action.text).to.equal("hello"); }); }); describe("showFind", () => { - it('create CONSOLE_SHOW_FIND action', () => { + it("create CONSOLE_SHOW_FIND action", () => { const action = consoleActions.showFind(); expect(action.type).to.equal(actions.CONSOLE_SHOW_FIND); }); }); describe("showError", () => { - it('create CONSOLE_SHOW_ERROR action', () => { - const action = consoleActions.showError('an error'); + it("create CONSOLE_SHOW_ERROR action", () => { + const action = consoleActions.showError("an error"); expect(action.type).to.equal(actions.CONSOLE_SHOW_ERROR); - expect(action.text).to.equal('an error'); + expect(action.text).to.equal("an error"); }); }); describe("showInfo", () => { - it('create CONSOLE_SHOW_INFO action', () => { - const action = consoleActions.showInfo('an info'); + it("create CONSOLE_SHOW_INFO action", () => { + const action = consoleActions.showInfo("an info"); expect(action.type).to.equal(actions.CONSOLE_SHOW_INFO); - expect(action.text).to.equal('an info'); + expect(action.text).to.equal("an info"); }); }); describe("hideCommand", () => { - it('create CONSOLE_HIDE_COMMAND action', () => { + it("create CONSOLE_HIDE_COMMAND action", () => { const action = consoleActions.hideCommand(); expect(action.type).to.equal(actions.CONSOLE_HIDE_COMMAND); }); }); - describe('setConsoleText', () => { - it('create CONSOLE_SET_CONSOLE_TEXT action', () => { - const action = consoleActions.setConsoleText('hello world'); + describe("setConsoleText", () => { + it("create CONSOLE_SET_CONSOLE_TEXT action", () => { + const action = consoleActions.setConsoleText("hello world"); expect(action.type).to.equal(actions.CONSOLE_SET_CONSOLE_TEXT); - expect(action.consoleText).to.equal('hello world'); + expect(action.consoleText).to.equal("hello world"); }); }); describe("completionPrev", () => { - it('create CONSOLE_COMPLETION_PREV action', () => { + it("create CONSOLE_COMPLETION_PREV action", () => { const action = consoleActions.completionPrev(); expect(action.type).to.equal(actions.CONSOLE_COMPLETION_PREV); }); }); describe("completionNext", () => { - it('create CONSOLE_COMPLETION_NEXT action', () => { + it("create CONSOLE_COMPLETION_NEXT action", () => { const action = consoleActions.completionNext(); expect(action.type).to.equal(actions.CONSOLE_COMPLETION_NEXT); }); diff --git a/test/console/commandline/CommandLineParser.test.ts b/test/console/commandline/CommandLineParser.test.ts index 6aec682..7cba04c 100644 --- a/test/console/commandline/CommandLineParser.test.ts +++ b/test/console/commandline/CommandLineParser.test.ts @@ -1,4 +1,6 @@ -import CommandLineParser, {InputPhase} from "../../../src/console/commandline/CommandLineParser"; +import CommandLineParser, { + InputPhase, +} from "../../../src/console/commandline/CommandLineParser"; import { Command } from "../../../src/shared/Command"; import { expect } from "chai"; @@ -9,7 +11,7 @@ describe("CommandLineParser", () => { expect(sut.inputPhase("")).to.equal(InputPhase.OnCommand); expect(sut.inputPhase("op")).to.equal(InputPhase.OnCommand); expect(sut.inputPhase("open ")).to.equal(InputPhase.OnArgs); - expect(sut.inputPhase("open apple")).to.equal(InputPhase.OnArgs) + expect(sut.inputPhase("open apple")).to.equal(InputPhase.OnArgs); }); }); describe("#parse", () => { @@ -24,6 +26,6 @@ describe("CommandLineParser", () => { command: Command.QuitAll, args: "", }); - }) - }) + }); + }); }); diff --git a/test/console/commandline/CommandParser.test.ts b/test/console/commandline/CommandParser.test.ts index 4ad78fd..f72afd6 100644 --- a/test/console/commandline/CommandParser.test.ts +++ b/test/console/commandline/CommandParser.test.ts @@ -1,6 +1,8 @@ -import CommandParser, { UnknownCommandError } from "../../../src/console/commandline/CommandParser"; +import CommandParser, { + UnknownCommandError, +} from "../../../src/console/commandline/CommandParser"; import { Command } from "../../../src/shared/Command"; -import { expect } from "chai" +import { expect } from "chai"; describe("CommandParser", () => { describe("#parse", () => { @@ -10,6 +12,6 @@ describe("CommandParser", () => { expect(sut.parse("w")).to.equal(Command.WindowOpen); expect(sut.parse("bdelete!")).to.equal(Command.BufferDeleteForce); expect(() => sut.parse("harakiri")).to.throw(UnknownCommandError); - }) - }) + }); + }); }); diff --git a/test/console/components/console/Completion.test.tsx b/test/console/components/console/Completion.test.tsx index e411c4a..921720b 100644 --- a/test/console/components/console/Completion.test.tsx +++ b/test/console/components/console/Completion.test.tsx @@ -1,166 +1,165 @@ -import React from 'react'; -import Completion from 'console/components/console/Completion' -import ReactTestRenderer from 'react-test-renderer'; +import React from "react"; +import Completion from "../../../../src/console/components/console/Completion"; +import ReactTestRenderer, { ReactTestInstance } from "react-test-renderer"; +import { expect } from "chai"; +import CompletionTitle from "../../../../src/console/components/console/CompletionTitle"; +import CompletionItem from "../../../../src/console/components/console/CompletionItem"; describe("console/components/console/completion", () => { - const completions = [{ - name: "Fruit", - items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], - }, { - name: "Element", - items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], - }]; - - it('renders Completion component', () => { - const root = ReactTestRenderer.create(<Completion - completions={completions} - size={30} - />).root; - - expect(root.children).to.have.lengthOf(1); - - const children = root.children[0].children; + const completions = [ + { + name: "Fruit", + items: [ + { caption: "apple" }, + { caption: "banana" }, + { caption: "cherry" }, + ], + }, + { + name: "Element", + items: [ + { caption: "argon" }, + { caption: "boron" }, + { caption: "carbon" }, + ], + }, + ]; + + it("renders Completion component", () => { + const root = ReactTestRenderer.create( + <Completion completions={completions} size={30} select={-1} /> + ).root; + + // const children = root.findByType('ul').children as Array<ReactTestInstance>; + const children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children).to.have.lengthOf(8); - expect(children[0].props.title).to.equal('Fruit'); - expect(children[1].props.caption).to.equal('apple'); - expect(children[2].props.caption).to.equal('banana'); - expect(children[3].props.caption).to.equal('cherry'); - expect(children[4].props.title).to.equal('Element'); - expect(children[5].props.caption).to.equal('argon'); - expect(children[6].props.caption).to.equal('boron'); - expect(children[7].props.caption).to.equal('carbon'); + expect(children.map((e) => e.type)).to.deep.equal([ + CompletionTitle, + CompletionItem, + CompletionItem, + CompletionItem, + CompletionTitle, + CompletionItem, + CompletionItem, + CompletionItem, + ]); + expect(children[0].props.title).to.equal("Fruit"); + expect(children[1].props.caption).to.equal("apple"); + expect(children[2].props.caption).to.equal("banana"); + expect(children[3].props.caption).to.equal("cherry"); + expect(children[4].props.title).to.equal("Element"); + expect(children[5].props.caption).to.equal("argon"); + expect(children[6].props.caption).to.equal("boron"); + expect(children[7].props.caption).to.equal("carbon"); }); - it('highlight current item', () => { - const root = ReactTestRenderer.create(<Completion - completions={completions} - size={30} - select={3} - />).root; + it("highlight current item", () => { + const root = ReactTestRenderer.create( + <Completion completions={completions} size={30} select={3} /> + ).root; - const children = root.children[0].children; + const children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children[5].props.highlight).to.be.true; }); - it('does not highlight any items', () => { - const root = ReactTestRenderer.create(<Completion - completions={completions} - size={30} - select={-1} - />).root; - - const children = root.children[0].children; - for (const li of children[0].children) { - expect(li.props.highlight).not.to.be.ok; - } + it("does not highlight any items", () => { + const root = ReactTestRenderer.create( + <Completion completions={completions} size={30} select={-1} /> + ).root; + + const children = root.findByType("ul").findAllByType(CompletionItem); + expect(children.every((e) => e.props.highlight === false)).to.be.true; }); - it('limits completion items', () => { - let root = ReactTestRenderer.create(<Completion - completions={completions} - size={3} - select={-1} - />).root; + it("limits completion items", () => { + let root = ReactTestRenderer.create( + <Completion completions={completions} size={3} select={-1} /> + ).root; - let children = root.children[0].children; + let children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children).to.have.lengthOf(3); - expect(children[0].props.title).to.equal('Fruit'); - expect(children[1].props.caption).to.equal('apple'); - expect(children[2].props.caption).to.equal('banana'); + expect(children[0].props.title).to.equal("Fruit"); + expect(children[1].props.caption).to.equal("apple"); + expect(children[2].props.caption).to.equal("banana"); - root = ReactTestRenderer.create(<Completion - completions={completions} - size={3} select={0} - />).root; + root = ReactTestRenderer.create( + <Completion completions={completions} size={3} select={0} /> + ).root; - children = root.children[0].children; + children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children[1].props.highlight).to.be.true; - }) - - it('scrolls up to down with select', () => { - const component = ReactTestRenderer.create(<Completion - completions={completions} - size={3} - select={1} - />); + }); + + it("scrolls up to down with select", () => { + const component = ReactTestRenderer.create( + <Completion completions={completions} size={3} select={1} /> + ); const root = component.root; - let children = root.children[0].children; + let children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children).to.have.lengthOf(3); - expect(children[0].props.title).to.equal('Fruit'); - expect(children[1].props.caption).to.equal('apple'); - expect(children[2].props.caption).to.equal('banana'); + expect(children[0].props.title).to.equal("Fruit"); + expect(children[1].props.caption).to.equal("apple"); + expect(children[2].props.caption).to.equal("banana"); - component.update(<Completion - completions={completions} - size={3} - select={2} - />); + component.update( + <Completion completions={completions} size={3} select={2} /> + ); - children = root.children[0].children; + children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children).to.have.lengthOf(3); - expect(children[0].props.caption).to.equal('apple'); - expect(children[1].props.caption).to.equal('banana'); - expect(children[2].props.caption).to.equal('cherry'); + expect(children[0].props.caption).to.equal("apple"); + expect(children[1].props.caption).to.equal("banana"); + expect(children[2].props.caption).to.equal("cherry"); expect(children[2].props.highlight).to.be.true; - component.update(<Completion - completions={completions} - size={3} - select={3} - />); + component.update( + <Completion completions={completions} size={3} select={3} /> + ); - children = root.children[0].children; + children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children).to.have.lengthOf(3); - expect(children[0].props.caption).to.equal('cherry'); - expect(children[1].props.title).to.equal('Element'); - expect(children[2].props.caption).to.equal('argon'); + expect(children[0].props.caption).to.equal("cherry"); + expect(children[1].props.title).to.equal("Element"); + expect(children[2].props.caption).to.equal("argon"); expect(children[2].props.highlight).to.be.true; }); - it('scrolls down to up with select', () => { - const component = ReactTestRenderer.create(<Completion - completions={completions} - size={3} - select={5} - />); + it("scrolls down to up with select", () => { + const component = ReactTestRenderer.create( + <Completion completions={completions} size={3} select={5} /> + ); const root = component.root; - let children = root.children[0].children; + let children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children).to.have.lengthOf(3); - expect(children[0].props.caption).to.equal('argon'); - expect(children[1].props.caption).to.equal('boron'); - expect(children[2].props.caption).to.equal('carbon'); + expect(children[0].props.caption).to.equal("argon"); + expect(children[1].props.caption).to.equal("boron"); + expect(children[2].props.caption).to.equal("carbon"); - component.update(<Completion - completions={completions} - size={3} - select={4} - />); + component.update( + <Completion completions={completions} size={3} select={4} /> + ); - children = root.children[0].children; + children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children[1].props.highlight).to.be.true; - component.update(<Completion - completions={completions} - size={3} - select={3} - />); + component.update( + <Completion completions={completions} size={3} select={3} /> + ); - children = root.children[0].children; + children = root.findByType("ul").children as Array<ReactTestInstance>; expect(children[0].props.highlight).to.be.true; - component.update(<Completion - completions={completions} - size={3} - select={2} - />); + component.update( + <Completion completions={completions} size={3} select={2} /> + ); - children = root.children[0].children; - expect(children[0].props.caption).to.equal('cherry'); - expect(children[1].props.title).to.equal('Element'); - expect(children[2].props.caption).to.equal('argon'); + children = root.findByType("ul").children as Array<ReactTestInstance>; + expect(children[0].props.caption).to.equal("cherry"); + expect(children[1].props.title).to.equal("Element"); + expect(children[2].props.caption).to.equal("argon"); expect(children[0].props.highlight).to.be.true; }); }); diff --git a/test/console/reducers/console.test.ts b/test/console/reducers/console.test.ts index 038e712..64e8eb3 100644 --- a/test/console/reducers/console.test.ts +++ b/test/console/reducers/console.test.ts @@ -1,131 +1,164 @@ -import * as actions from 'console/actions'; -import reducer from 'console/reducers'; +import * as actions from "../../../src/console/actions"; +import reducer, { State } from "../../../src/console/reducers"; +import { expect } from "chai"; +import CompletionType from "../../../src/shared/CompletionType"; +import { ConsoleAction } from "../../../src/console/actions"; describe("console reducer", () => { - it('return the initial state', () => { - const state = reducer(undefined, {}); - expect(state).to.have.property('mode', ''); - expect(state).to.have.property('messageText', ''); - expect(state).to.have.property('consoleText', ''); - expect(state).to.have.deep.property('completions', []); - expect(state).to.have.property('select', -1); + it("return the initial state", () => { + const state = reducer(undefined, {} as any); + expect(state).to.have.property("mode", ""); + expect(state).to.have.property("messageText", ""); + expect(state).to.have.property("consoleText", ""); + expect(state).to.have.deep.property("completions", []); + expect(state).to.have.property("select", -1); }); - it('return next state for CONSOLE_HIDE', () => { - const action = { type: actions.CONSOLE_HIDE }; - const state = reducer({ mode: 'error' }, action); - expect(state).to.have.property('mode', ''); - }) - - it('return next state for CONSOLE_SHOW_COMMAND', () => { - const action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' }; - const state = reducer({}, action); - expect(state).to.have.property('mode', 'command'); - expect(state).to.have.property('consoleText', 'open '); + it("return next state for CONSOLE_HIDE", () => { + const initialState = reducer(undefined, {} as any); + const action: actions.ConsoleAction = { type: actions.CONSOLE_HIDE }; + const state = reducer({ ...initialState, mode: "error" }, action); + expect(state).to.have.property("mode", ""); }); - it('return next state for CONSOLE_SHOW_INFO', () => { - const action = { type: actions.CONSOLE_SHOW_INFO, text: 'an info' }; - const state = reducer({}, action); - expect(state).to.have.property('mode', 'info'); - expect(state).to.have.property('messageText', 'an info'); + it("return next state for CONSOLE_SHOW_COMMAND", () => { + const action: actions.ConsoleAction = { + type: actions.CONSOLE_SHOW_COMMAND, + completionTypes: [CompletionType.SearchEngines, CompletionType.History], + text: "open ", + }; + const state = reducer(undefined, action); + expect(state).to.have.property("mode", "command"); + expect(state).to.have.property("consoleText", "open "); }); - it('return next state for CONSOLE_SHOW_ERROR', () => { - const action = { type: actions.CONSOLE_SHOW_ERROR, text: 'an error' }; - const state = reducer({}, action); - expect(state).to.have.property('mode', 'error'); - expect(state).to.have.property('messageText', 'an error'); + it("return next state for CONSOLE_SHOW_INFO", () => { + const action: actions.ConsoleAction = { + type: actions.CONSOLE_SHOW_INFO, + text: "an info", + }; + const state = reducer(undefined, action); + expect(state).to.have.property("mode", "info"); + expect(state).to.have.property("messageText", "an info"); + }); + + it("return next state for CONSOLE_SHOW_ERROR", () => { + const action: actions.ConsoleAction = { + type: actions.CONSOLE_SHOW_ERROR, + text: "an error", + }; + const state = reducer(undefined, action); + expect(state).to.have.property("mode", "error"); + expect(state).to.have.property("messageText", "an error"); }); - it('return next state for CONSOLE_HIDE_COMMAND', () => { - const action = { type: actions.CONSOLE_HIDE_COMMAND }; - let state = reducer({ mode: 'command' }, action); - expect(state).to.have.property('mode', ''); + it("return next state for CONSOLE_HIDE_COMMAND", () => { + const initialState = reducer(undefined, {} as any); + const action: actions.ConsoleAction = { + type: actions.CONSOLE_HIDE_COMMAND, + }; + let state = reducer({ ...initialState, mode: "command" }, action); + expect(state).to.have.property("mode", ""); - state = reducer({ mode: 'error' }, action); - expect(state).to.have.property('mode', 'error'); + state = reducer({ ...initialState, mode: "error" }, action); + expect(state).to.have.property("mode", "error"); }); - it('return next state for CONSOLE_SET_CONSOLE_TEXT', () => { - const action = { + it("return next state for CONSOLE_SET_CONSOLE_TEXT", () => { + const action: actions.ConsoleAction = { type: actions.CONSOLE_SET_CONSOLE_TEXT, - consoleText: 'hello world' - } - const state = reducer({}, action) + consoleText: "hello world", + }; + const state = reducer(undefined, action); - expect(state).to.have.property('consoleText', 'hello world'); + expect(state).to.have.property("consoleText", "hello world"); }); - it ('return next state for CONSOLE_SET_COMPLETIONS', () => { - let state = { + it("return next state for CONSOLE_SET_COMPLETIONS", () => { + const initialState = reducer(undefined, {} as any); + let state: State = { + ...initialState, select: 0, completions: [], - } - const action = { + }; + const action: actions.ConsoleAction = { type: actions.CONSOLE_SET_COMPLETIONS, - completions: [{ - name: 'Apple', - items: [1, 2, 3] - }, { - name: 'Banana', - items: [4, 5, 6] - }] - } + completions: [ + { + name: "Apple", + items: [{}, {}, {}], + }, + { + name: "Banana", + items: [{}, {}, {}], + }, + ], + completionSource: "", + }; state = reducer(state, action); - expect(state).to.have.property('completions', action.completions); - expect(state).to.have.property('select', -1); + expect(state).to.have.property("completions", action.completions); + expect(state).to.have.property("select", -1); }); - it ('return next state for CONSOLE_COMPLETION_NEXT', () => { - const action = { type: actions.CONSOLE_COMPLETION_NEXT }; + it("return next state for CONSOLE_COMPLETION_NEXT", () => { + const initialState = reducer(undefined, {} as any); + const action: ConsoleAction = { type: actions.CONSOLE_COMPLETION_NEXT }; let state = { + ...initialState, select: -1, - completions: [{ - name: 'Apple', - items: [1, 2] - }, { - name: 'Banana', - items: [3] - }] + completions: [ + { + name: "Apple", + items: [{}, {}], + }, + { + name: "Banana", + items: [{}], + }, + ], }; state = reducer(state, action); - expect(state).to.have.property('select', 0); + expect(state).to.have.property("select", 0); state = reducer(state, action); - expect(state).to.have.property('select', 1); + expect(state).to.have.property("select", 1); state = reducer(state, action); - expect(state).to.have.property('select', 2); + expect(state).to.have.property("select", 2); state = reducer(state, action); - expect(state).to.have.property('select', -1); + expect(state).to.have.property("select", -1); }); - it ('return next state for CONSOLE_COMPLETION_PREV', () => { - const action = { type: actions.CONSOLE_COMPLETION_PREV }; + it("return next state for CONSOLE_COMPLETION_PREV", () => { + const initialState = reducer(undefined, {} as any); + const action: ConsoleAction = { type: actions.CONSOLE_COMPLETION_PREV }; let state = { + ...initialState, select: -1, - completions: [{ - name: 'Apple', - items: [1, 2] - }, { - name: 'Banana', - items: [3] - }] + completions: [ + { + name: "Apple", + items: [{}, {}], + }, + { + name: "Banana", + items: [{}], + }, + ], }; state = reducer(state, action); - expect(state).to.have.property('select', 2); + expect(state).to.have.property("select", 2); state = reducer(state, action); - expect(state).to.have.property('select', 1); + expect(state).to.have.property("select", 1); state = reducer(state, action); - expect(state).to.have.property('select', 0); + expect(state).to.have.property("select", 0); state = reducer(state, action); - expect(state).to.have.property('select', -1); + expect(state).to.have.property("select", -1); }); }); diff --git a/test/content/InputDriver.test.ts b/test/content/InputDriver.test.ts index d3a55dd..f464dac 100644 --- a/test/content/InputDriver.test.ts +++ b/test/content/InputDriver.test.ts @@ -1,26 +1,26 @@ -import InputDriver, {keyFromKeyboardEvent} from '../../src/content/InputDriver'; -import { expect } from 'chai'; -import Key from '../../src/shared/settings/Key'; +import InputDriver, { + keyFromKeyboardEvent, +} from "../../src/content/InputDriver"; +import { expect } from "chai"; +import Key from "../../src/shared/settings/Key"; -describe('InputDriver', () => { +describe("InputDriver", () => { let target: HTMLElement; let driver: InputDriver; beforeEach(() => { - target = document.createElement('div'); + target = document.createElement("div"); document.body.appendChild(target); driver = new InputDriver(target); }); afterEach(() => { target.remove(); - target = null; - driver = null; }); - it('register callbacks', (done) => { + it("register callbacks", (done) => { driver.onKey((key: Key): boolean => { - expect(key.key).to.equal('a'); + expect(key.key).to.equal("a"); expect(key.ctrl).to.be.true; expect(key.shift).to.be.false; expect(key.alt).to.be.false; @@ -29,34 +29,37 @@ describe('InputDriver', () => { return true; }); - target.dispatchEvent(new KeyboardEvent('keydown', { - key: 'a', - ctrlKey: true, - shiftKey: false, - altKey: false, - metaKey: false, - })); + target.dispatchEvent( + new KeyboardEvent("keydown", { + key: "a", + ctrlKey: true, + shiftKey: false, + altKey: false, + metaKey: false, + }) + ); }); - it('invoke callback once', () => { - let a = 0, b = 0; + it("invoke callback once", () => { + let a = 0, + b = 0; driver.onKey((key: Key): boolean => { - if (key.key == 'a') { + if (key.key == "a") { ++a; } else { - key.key == 'b' + key.key == "b"; ++b; } return true; }); const events = [ - new KeyboardEvent('keydown', { key: 'a' }), - new KeyboardEvent('keydown', { key: 'b' }), - new KeyboardEvent('keypress', { key: 'a' }), - new KeyboardEvent('keyup', { key: 'a' }), - new KeyboardEvent('keypress', { key: 'b' }), - new KeyboardEvent('keyup', { key: 'b' }), + new KeyboardEvent("keydown", { key: "a" }), + new KeyboardEvent("keydown", { key: "b" }), + new KeyboardEvent("keypress", { key: "a" }), + new KeyboardEvent("keyup", { key: "a" }), + new KeyboardEvent("keypress", { key: "b" }), + new KeyboardEvent("keyup", { key: "b" }), ]; for (const e of events) { target.dispatchEvent(e); @@ -64,10 +67,12 @@ describe('InputDriver', () => { expect(a).to.equal(1); expect(b).to.equal(1); - }) + }); - it('propagates and stop handler chain', () => { - let a = 0, b = 0, c = 0; + it("propagates and stop handler chain", () => { + let a = 0, + b = 0, + c = 0; driver.onKey((_key: Key): boolean => { a++; return false; @@ -81,93 +86,117 @@ describe('InputDriver', () => { return true; }); - target.dispatchEvent(new KeyboardEvent('keydown', { key: 'b' })); + target.dispatchEvent(new KeyboardEvent("keydown", { key: "b" })); expect(a).to.equal(1); expect(b).to.equal(1); expect(c).to.equal(0); - }) + }); - it('does not invoke only meta keys', () => { - driver.onKey((_key: Key): boolean=> { + it("does not invoke only meta keys", () => { + driver.onKey((_key: Key): boolean => { expect.fail(); return false; }); - target.dispatchEvent(new KeyboardEvent('keydown', { key: 'Shift' })); - target.dispatchEvent(new KeyboardEvent('keydown', { key: 'Control' })); - target.dispatchEvent(new KeyboardEvent('keydown', { key: 'Alt' })); - target.dispatchEvent(new KeyboardEvent('keydown', { key: 'OS' })); - }) + target.dispatchEvent(new KeyboardEvent("keydown", { key: "Shift" })); + target.dispatchEvent(new KeyboardEvent("keydown", { key: "Control" })); + target.dispatchEvent(new KeyboardEvent("keydown", { key: "Alt" })); + target.dispatchEvent(new KeyboardEvent("keydown", { key: "OS" })); + }); - it('ignores events from input elements', () => { - ['input', 'textarea', 'select'].forEach((name) => { + it("ignores events from input elements", () => { + ["input", "textarea", "select"].forEach((name) => { const input = window.document.createElement(name); const driver = new InputDriver(input); driver.onKey((_key: Key): boolean => { expect.fail(); return false; }); - input.dispatchEvent(new KeyboardEvent('keydown', { key: 'x' })); + input.dispatchEvent(new KeyboardEvent("keydown", { key: "x" })); }); }); - it('ignores events from contenteditable elements', () => { - const div = window.document.createElement('div'); + it("ignores events from contenteditable elements", () => { + const div = window.document.createElement("div"); const driver = new InputDriver(div); driver.onKey((_key: Key): boolean => { expect.fail(); return false; }); - div.setAttribute('contenteditable', ''); - div.dispatchEvent(new KeyboardEvent('keydown', { key: 'x' })); + div.setAttribute("contenteditable", ""); + div.dispatchEvent(new KeyboardEvent("keydown", { key: "x" })); - div.setAttribute('contenteditable', 'true'); - div.dispatchEvent(new KeyboardEvent('keydown', { key: 'x' })); + div.setAttribute("contenteditable", "true"); + div.dispatchEvent(new KeyboardEvent("keydown", { key: "x" })); }); }); describe("#keyFromKeyboardEvent", () => { - it('returns from keyboard input Ctrl+X', () => { - const k = keyFromKeyboardEvent(new KeyboardEvent('keydown', { - key: 'x', shiftKey: false, ctrlKey: true, altKey: false, metaKey: true, - })); - expect(k.key).to.equal('x'); + it("returns from keyboard input Ctrl+X", () => { + const k = keyFromKeyboardEvent( + new KeyboardEvent("keydown", { + key: "x", + shiftKey: false, + ctrlKey: true, + altKey: false, + metaKey: true, + }) + ); + expect(k.key).to.equal("x"); expect(k.shift).to.be.false; expect(k.ctrl).to.be.true; expect(k.alt).to.be.false; expect(k.meta).to.be.true; }); - it('returns from keyboard input Shift+Esc', () => { - const k = keyFromKeyboardEvent(new KeyboardEvent('keydown', { - key: 'Escape', shiftKey: true, ctrlKey: false, altKey: false, metaKey: true - })); - expect(k.key).to.equal('Esc'); + it("returns from keyboard input Shift+Esc", () => { + const k = keyFromKeyboardEvent( + new KeyboardEvent("keydown", { + key: "Escape", + shiftKey: true, + ctrlKey: false, + altKey: false, + metaKey: true, + }) + ); + expect(k.key).to.equal("Esc"); expect(k.shift).to.be.true; expect(k.ctrl).to.be.false; expect(k.alt).to.be.false; expect(k.meta).to.be.true; }); - it('returns from keyboard input Ctrl+$', () => { + it("returns from keyboard input Ctrl+$", () => { // $ required shift pressing on most keyboards - const k = keyFromKeyboardEvent(new KeyboardEvent('keydown', { - key: '$', shiftKey: true, ctrlKey: true, altKey: false, metaKey: false - })); - expect(k.key).to.equal('$'); + const k = keyFromKeyboardEvent( + new KeyboardEvent("keydown", { + key: "$", + shiftKey: true, + ctrlKey: true, + altKey: false, + metaKey: false, + }) + ); + expect(k.key).to.equal("$"); expect(k.shift).to.be.false; expect(k.ctrl).to.be.true; expect(k.alt).to.be.false; expect(k.meta).to.be.false; }); - it('returns from keyboard input Crtl+Space', () => { - const k = keyFromKeyboardEvent(new KeyboardEvent('keydown', { - key: ' ', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false - })); - expect(k.key).to.equal('Space'); + it("returns from keyboard input Crtl+Space", () => { + const k = keyFromKeyboardEvent( + new KeyboardEvent("keydown", { + key: " ", + shiftKey: false, + ctrlKey: true, + altKey: false, + metaKey: false, + }) + ); + expect(k.key).to.equal("Space"); expect(k.shift).to.be.false; expect(k.ctrl).to.be.true; expect(k.alt).to.be.false; diff --git a/test/content/domains/KeySequence.test.ts b/test/content/domains/KeySequence.test.ts index 5df5217..1d1debe 100644 --- a/test/content/domains/KeySequence.test.ts +++ b/test/content/domains/KeySequence.test.ts @@ -1,166 +1,179 @@ -import KeySequence from '../../../src/content/domains/KeySequence'; -import { expect } from 'chai' +import KeySequence from "../../../src/content/domains/KeySequence"; +import { expect } from "chai"; import Key from "../../../src/shared/settings/Key"; describe("KeySequence", () => { - describe('#push', () => { - it('append a key to the sequence', () => { + describe("#push", () => { + it("append a key to the sequence", () => { const seq = new KeySequence([]); - seq.push(Key.fromMapKey('g')); - seq.push(Key.fromMapKey('<S-U>')); + seq.push(Key.fromMapKey("g")); + seq.push(Key.fromMapKey("<S-U>")); - expect(seq.keys[0].key).to.equal('g'); - expect(seq.keys[1].key).to.equal('U'); + expect(seq.keys[0].key).to.equal("g"); + expect(seq.keys[1].key).to.equal("U"); expect(seq.keys[1].shift).to.be.true; - }) + }); }); - describe('#startsWith', () => { - it('returns true if the key sequence starts with param', () => { + describe("#startsWith", () => { + it("returns true if the key sequence starts with param", () => { const seq = new KeySequence([ - Key.fromMapKey('g'), - Key.fromMapKey('<S-U>'), + Key.fromMapKey("g"), + Key.fromMapKey("<S-U>"), ]); - expect(seq.startsWith(new KeySequence([ - ]))).to.be.true; - expect(seq.startsWith(new KeySequence([ - Key.fromMapKey('g'), - ]))).to.be.true; - expect(seq.startsWith(new KeySequence([ - Key.fromMapKey('g'), Key.fromMapKey('<S-U>'), - ]))).to.be.true; - expect(seq.startsWith(new KeySequence([ - Key.fromMapKey('g'), Key.fromMapKey('<S-U>'), Key.fromMapKey('x'), - ]))).to.be.false; - expect(seq.startsWith(new KeySequence([ - Key.fromMapKey('h'), - ]))).to.be.false; + expect(seq.startsWith(new KeySequence([]))).to.be.true; + expect(seq.startsWith(new KeySequence([Key.fromMapKey("g")]))).to.be.true; + expect( + seq.startsWith( + new KeySequence([Key.fromMapKey("g"), Key.fromMapKey("<S-U>")]) + ) + ).to.be.true; + expect( + seq.startsWith( + new KeySequence([ + Key.fromMapKey("g"), + Key.fromMapKey("<S-U>"), + Key.fromMapKey("x"), + ]) + ) + ).to.be.false; + expect(seq.startsWith(new KeySequence([Key.fromMapKey("h")]))).to.be + .false; }); - it('returns true if the empty sequence starts with an empty sequence', () => { + it("returns true if the empty sequence starts with an empty sequence", () => { const seq = new KeySequence([]); expect(seq.startsWith(new KeySequence([]))).to.be.true; - expect(seq.startsWith(new KeySequence([ - Key.fromMapKey('h'), - ]))).to.be.false; - }) + expect(seq.startsWith(new KeySequence([Key.fromMapKey("h")]))).to.be + .false; + }); }); - describe('#isDigitOnly', () => { - it('returns true the keys are only digits', () => { - expect(new KeySequence([ - new Key({ key: '4' }), - new Key({ key: '0' }), - ]).isDigitOnly()).to.be.true; - expect(new KeySequence([ - new Key({ key: '4' }), - new Key({ key: '0' }), - new Key({ key: 'z' }), - ]).isDigitOnly()).to.be.false; - }) + describe("#isDigitOnly", () => { + it("returns true the keys are only digits", () => { + expect( + new KeySequence([ + new Key({ key: "4" }), + new Key({ key: "0" }), + ]).isDigitOnly() + ).to.be.true; + expect( + new KeySequence([ + new Key({ key: "4" }), + new Key({ key: "0" }), + new Key({ key: "z" }), + ]).isDigitOnly() + ).to.be.false; + }); }); - describe('#repeatCount', () => { - it('returns repeat count with a numeric prefix', () => { + describe("#repeatCount", () => { + it("returns repeat count with a numeric prefix", () => { let seq = new KeySequence([ - new Key({ key: '1' }), new Key({ key: '0' }) , - new Key({ key: 'g' }), new Key({ key: 'g' }) , + new Key({ key: "1" }), + new Key({ key: "0" }), + new Key({ key: "g" }), + new Key({ key: "g" }), ]); expect(seq.repeatCount()).to.equal(10); seq = new KeySequence([ - new Key({ key: '0' }), new Key({ key: '5' }) , - new Key({ key: 'g' }), new Key({ key: 'g' }) , + new Key({ key: "0" }), + new Key({ key: "5" }), + new Key({ key: "g" }), + new Key({ key: "g" }), ]); expect(seq.repeatCount()).to.equal(5); }); - it('returns 1 if no numeric prefix', () => { - let seq = new KeySequence([ - new Key({ key: 'g' }), new Key({ key: 'g' }) , - ]); + it("returns 1 if no numeric prefix", () => { + let seq = new KeySequence([new Key({ key: "g" }), new Key({ key: "g" })]); expect(seq.repeatCount()).to.equal(1); seq = new KeySequence([]); expect(seq.repeatCount()).to.equal(1); }); - it('returns whole keys if digits only sequence', () => { - let seq = new KeySequence([ - new Key({ key: '1' }), new Key({ key: '0' }) , - ]); + it("returns whole keys if digits only sequence", () => { + let seq = new KeySequence([new Key({ key: "1" }), new Key({ key: "0" })]); expect(seq.repeatCount()).to.equal(10); - seq = new KeySequence([ - new Key({ key: '0' }), new Key({ key: '5' }) , - ]); + seq = new KeySequence([new Key({ key: "0" }), new Key({ key: "5" })]); expect(seq.repeatCount()).to.equal(5); }); }); - describe('#trimNumericPrefix', () => { - it('removes numeric prefix', () => { + describe("#trimNumericPrefix", () => { + it("removes numeric prefix", () => { const seq = new KeySequence([ - new Key({ key: '1' }), new Key({ key: '0' }) , - new Key({ key: 'g' }), new Key({ key: 'g' }) , new Key({ key: '3' }) , + new Key({ key: "1" }), + new Key({ key: "0" }), + new Key({ key: "g" }), + new Key({ key: "g" }), + new Key({ key: "3" }), ]).trimNumericPrefix(); - expect(seq.keys.map(key => key.key)).to.deep.equal(['g', 'g', '3']); + expect(seq.keys.map((key) => key.key)).to.deep.equal(["g", "g", "3"]); }); - it('returns empty if keys contains only digis', () => { + it("returns empty if keys contains only digis", () => { const seq = new KeySequence([ - new Key({ key: '1' }), new Key({ key: '0' }) , + new Key({ key: "1" }), + new Key({ key: "0" }), ]).trimNumericPrefix(); expect(seq.trimNumericPrefix().keys).to.be.empty; }); - it('returns itself if no numeric prefix', () => { + it("returns itself if no numeric prefix", () => { const seq = new KeySequence([ - new Key({ key: 'g' }), new Key({ key: 'g' }) , new Key({ key: '3' }) , + new Key({ key: "g" }), + new Key({ key: "g" }), + new Key({ key: "3" }), ]).trimNumericPrefix(); - expect(seq.keys.map(key => key.key)).to.deep.equal(['g', 'g', '3']); + expect(seq.keys.map((key) => key.key)).to.deep.equal(["g", "g", "3"]); }); }); - describe('#splitNumericPrefix', () => { - it('splits numeric prefix', () => { - expect(KeySequence.fromMapKeys('10gg').splitNumericPrefix()).to.deep.equal([ - KeySequence.fromMapKeys('10'), - KeySequence.fromMapKeys('gg'), - ]); - expect(KeySequence.fromMapKeys('10').splitNumericPrefix()).to.deep.equal([ - KeySequence.fromMapKeys('10'), - new KeySequence([]), - ]); - expect(KeySequence.fromMapKeys('gg').splitNumericPrefix()).to.deep.equal([ - new KeySequence([]), - KeySequence.fromMapKeys('gg'), - ]); - }); + describe("#splitNumericPrefix", () => { + it("splits numeric prefix", () => { + expect( + KeySequence.fromMapKeys("10gg").splitNumericPrefix() + ).to.deep.equal([ + KeySequence.fromMapKeys("10"), + KeySequence.fromMapKeys("gg"), + ]); + expect(KeySequence.fromMapKeys("10").splitNumericPrefix()).to.deep.equal([ + KeySequence.fromMapKeys("10"), + new KeySequence([]), + ]); + expect(KeySequence.fromMapKeys("gg").splitNumericPrefix()).to.deep.equal([ + new KeySequence([]), + KeySequence.fromMapKeys("gg"), + ]); + }); }); - describe('#fromMapKeys', () => { - it('returns mapped keys for Shift+Esc', () => { - const keys = KeySequence.fromMapKeys('<S-Esc>').keys; + describe("#fromMapKeys", () => { + it("returns mapped keys for Shift+Esc", () => { + const keys = KeySequence.fromMapKeys("<S-Esc>").keys; expect(keys).to.have.lengthOf(1); - expect(keys[0].key).to.equal('Esc'); + expect(keys[0].key).to.equal("Esc"); expect(keys[0].shift).to.be.true; }); - it('returns mapped keys for a<C-B><A-C>d<M-e>', () => { - const keys = KeySequence.fromMapKeys('a<C-B><A-C>d<M-e>').keys; + it("returns mapped keys for a<C-B><A-C>d<M-e>", () => { + const keys = KeySequence.fromMapKeys("a<C-B><A-C>d<M-e>").keys; expect(keys).to.have.lengthOf(5); - expect(keys[0].key).to.equal('a'); + expect(keys[0].key).to.equal("a"); expect(keys[1].ctrl).to.be.true; - expect(keys[1].key).to.equal('b'); + expect(keys[1].key).to.equal("b"); expect(keys[2].alt).to.be.true; - expect(keys[2].key).to.equal('c'); - expect(keys[3].key).to.equal('d'); + expect(keys[2].key).to.equal("c"); + expect(keys[3].key).to.equal("d"); expect(keys[4].meta).to.be.true; - expect(keys[4].key).to.equal('e'); + expect(keys[4].key).to.equal("e"); }); - }) + }); }); diff --git a/test/content/mock/MockConsoleClient.ts b/test/content/mock/MockConsoleClient.ts index 8de2d83..849c00d 100644 --- a/test/content/mock/MockConsoleClient.ts +++ b/test/content/mock/MockConsoleClient.ts @@ -1,4 +1,4 @@ -import ConsoleClient from '../../../src/content/client/ConsoleClient'; +import ConsoleClient from "../../../src/content/client/ConsoleClient"; export default class MockConsoleClient implements ConsoleClient { public isError: boolean; @@ -7,7 +7,7 @@ export default class MockConsoleClient implements ConsoleClient { constructor() { this.isError = false; - this.text = ''; + this.text = ""; } info(text: string): Promise<void> { @@ -22,5 +22,3 @@ export default class MockConsoleClient implements ConsoleClient { return Promise.resolve(); } } - - diff --git a/test/content/mock/MockScrollPresenter.ts b/test/content/mock/MockScrollPresenter.ts index 819569a..c802227 100644 --- a/test/content/mock/MockScrollPresenter.ts +++ b/test/content/mock/MockScrollPresenter.ts @@ -1,8 +1,10 @@ -import ScrollPresenter, { Point } from '../../../src/content/presenters/ScrollPresenter'; +import ScrollPresenter, { + Point, +} from "../../../src/content/presenters/ScrollPresenter"; export default class MockScrollPresenter implements ScrollPresenter { private pos: Point; - + constructor() { this.pos = { x: 0, y: 0 }; } @@ -44,4 +46,3 @@ export default class MockScrollPresenter implements ScrollPresenter { this.pos.x = Infinity; } } - diff --git a/test/content/presenters/Hint.test.ts b/test/content/presenters/Hint.test.ts index 7daa63d..f961f88 100644 --- a/test/content/presenters/Hint.test.ts +++ b/test/content/presenters/Hint.test.ts @@ -1,53 +1,55 @@ -import AbstractHint, { LinkHint, InputHint } from '../../../src/content/presenters/Hint'; -import { expect } from 'chai'; +import AbstractHint, { + LinkHint, + InputHint, +} from "../../../src/content/presenters/Hint"; +import { expect } from "chai"; -class Hint extends AbstractHint { -} +class Hint extends AbstractHint {} -describe('Hint', () => { +describe("Hint", () => { beforeEach(() => { document.body.innerHTML = `<a id='test-link' href='#'>link</a>`; }); - describe('#constructor', () => { - it('creates a hint element with tag name', () => { - const link = document.getElementById('test-link'); - new Hint(link, 'abc'); + describe("#constructor", () => { + it("creates a hint element with tag name", () => { + const link = document.getElementById("test-link")!!; + new Hint(link, "abc"); - const elem = document.querySelector('.vimvixen-hint'); - expect(elem.textContent.trim()).to.be.equal('abc'); + const elem = document.querySelector(".vimvixen-hint"); + expect(elem!!.textContent!!.trim()).to.be.equal("abc"); }); }); - describe('#show', () => { - it('shows an element', () => { - const link = document.getElementById('test-link'); - const hint = new Hint(link, 'abc'); + describe("#show", () => { + it("shows an element", () => { + const link = document.getElementById("test-link")!!; + const hint = new Hint(link, "abc"); hint.hide(); hint.show(); - const elem = document.querySelector('.vimvixen-hint') as HTMLElement; - expect(elem.style.display).to.not.equal('none'); + const elem = document.querySelector(".vimvixen-hint") as HTMLElement; + expect(elem.style.display).to.not.equal("none"); }); }); - describe('#hide', () => { - it('hides an element', () => { - const link = document.getElementById('test-link') as HTMLElement; - const hint = new Hint(link, 'abc'); + describe("#hide", () => { + it("hides an element", () => { + const link = document.getElementById("test-link") as HTMLElement; + const hint = new Hint(link, "abc"); hint.hide(); - const elem = document.querySelector('.vimvixen-hint') as HTMLElement; - expect(elem.style.display).to.equal('none'); + const elem = document.querySelector(".vimvixen-hint") as HTMLElement; + expect(elem.style.display).to.equal("none"); }); }); - describe('#remove', () => { - it('removes an element', () => { - const link = document.getElementById('test-link'); - const hint = new Hint(link, 'abc'); + describe("#remove", () => { + it("removes an element", () => { + const link = document.getElementById("test-link")!!; + const hint = new Hint(link, "abc"); - const elem = document.querySelector('.vimvixen-hint'); + const elem = document.querySelector(".vimvixen-hint")!!; expect(elem.parentElement).to.not.be.null; hint.remove(); expect(elem.parentElement).to.be.null; @@ -55,7 +57,7 @@ describe('Hint', () => { }); }); -describe('LinkHint', () => { +describe("LinkHint", () => { beforeEach(() => { document.body.innerHTML = ` <a id='test-link1' href='https://google.com/'>link</a> @@ -64,50 +66,52 @@ describe('LinkHint', () => { `; }); - describe('#getLink()', () => { + describe("#getLink()", () => { it('returns value of "href" attribute', () => { - const link = document.getElementById('test-link1') as HTMLAnchorElement; - const hint = new LinkHint(link, 'abc'); + const link = document.getElementById("test-link1") as HTMLAnchorElement; + const hint = new LinkHint(link, "abc"); - expect(hint.getLink()).to.equal('https://google.com/'); + expect(hint.getLink()).to.equal("https://google.com/"); }); }); - describe('#getLinkTarget()', () => { + describe("#getLinkTarget()", () => { it('returns value of "target" attribute', () => { - let link = document.getElementById('test-link1') as HTMLAnchorElement; - let hint = new LinkHint(link, 'abc'); + let link = document.getElementById("test-link1") as HTMLAnchorElement; + let hint = new LinkHint(link, "abc"); expect(hint.getLinkTarget()).to.be.null; - link = document.getElementById('test-link2') as HTMLAnchorElement; - hint = new LinkHint(link, 'abc'); + link = document.getElementById("test-link2") as HTMLAnchorElement; + hint = new LinkHint(link, "abc"); - expect(hint.getLinkTarget()).to.equal('_blank'); + expect(hint.getLinkTarget()).to.equal("_blank"); }); }); - describe('#click()', () => { - it('clicks a element', (done) => { - const link = document.getElementById('test-link3') as HTMLAnchorElement; - const hint = new LinkHint(link, 'abc'); - link.onclick = () => { done() }; + describe("#click()", () => { + it("clicks a element", (done) => { + const link = document.getElementById("test-link3") as HTMLAnchorElement; + const hint = new LinkHint(link, "abc"); + link.onclick = () => { + done(); + }; hint.click(); }); }); }); -describe('InputHint', () => { - describe('#activate()', () => { - context('<input>', () => { +describe("InputHint", () => { + describe("#activate()", () => { + context("<input>", () => { beforeEach(() => { document.body.innerHTML = `<input id='test-input'></input>`; }); - it('focuses to the input', () => { - const input = document.getElementById('test-input') as HTMLInputElement; - const hint = new InputHint(input, 'abc'); + it("focuses to the input", () => { + const input = document.getElementById("test-input") as HTMLInputElement; + const hint = new InputHint(input, "abc"); hint.activate(); expect(document.activeElement).to.equal(input); @@ -119,38 +123,44 @@ describe('InputHint', () => { document.body.innerHTML = `<input type="checkbox" id='test-input'></input>`; }); - it('checks and focuses to the input', () => { - const input = document.getElementById('test-input') as HTMLInputElement; - const hint = new InputHint(input, 'abc'); + it("checks and focuses to the input", () => { + const input = document.getElementById("test-input") as HTMLInputElement; + const hint = new InputHint(input, "abc"); hint.activate(); expect(input.checked).to.be.true; }); }); - context('<textarea>', () => { + context("<textarea>", () => { beforeEach(() => { document.body.innerHTML = `<textarea id='test-textarea'></textarea>`; }); - it('focuses to the textarea', () => { - const textarea = document.getElementById('test-textarea') as HTMLTextAreaElement; - const hint = new InputHint(textarea, 'abc'); + it("focuses to the textarea", () => { + const textarea = document.getElementById( + "test-textarea" + ) as HTMLTextAreaElement; + const hint = new InputHint(textarea, "abc"); hint.activate(); expect(document.activeElement).to.equal(textarea); }); }); - context('<button>', () => { + context("<button>", () => { beforeEach(() => { document.body.innerHTML = `<button id='test-button'></button>`; }); - it('clicks the button', (done) => { - const button = document.getElementById('test-button') as HTMLButtonElement; - button.onclick = () => { done() }; + it("clicks the button", (done) => { + const button = document.getElementById( + "test-button" + ) as HTMLButtonElement; + button.onclick = () => { + done(); + }; - const hint = new InputHint(button, 'abc'); + const hint = new InputHint(button, "abc"); hint.activate(); }); }); diff --git a/test/content/presenters/NavigationPresenter.test.ts b/test/content/presenters/NavigationPresenter.test.ts index 6aa057b..af3b487 100644 --- a/test/content/presenters/NavigationPresenter.test.ts +++ b/test/content/presenters/NavigationPresenter.test.ts @@ -1,11 +1,12 @@ -import { NavigationPresenterImpl } from '../../../src/content/presenters/NavigationPresenter'; -import { expect } from 'chai'; +import { NavigationPresenterImpl } from "../../../src/content/presenters/NavigationPresenter"; +import { expect } from "chai"; -describe('NavigationPresenterImpl', () => { +describe("NavigationPresenterImpl", () => { let sut: NavigationPresenterImpl; - const testRel = (done, rel, html) => { - const method = rel === 'prev' ? sut.openLinkPrev.bind(sut) : sut.openLinkNext.bind(sut); + const testRel = (done: () => void, rel: string, html: string) => { + const method = + rel === "prev" ? sut.openLinkPrev.bind(sut) : sut.openLinkNext.bind(sut); document.body.innerHTML = html; method(); setTimeout(() => { @@ -13,122 +14,167 @@ describe('NavigationPresenterImpl', () => { done(); }, 0); }; - const testPrev = html => done => testRel(done, 'prev', html); - const testNext = html => done => testRel(done, 'next', html); + const testPrev = (html: string) => (done: () => void) => + testRel(done, "prev", html); + const testNext = (html: string) => (done: () => void) => + testRel(done, "next", html); before(() => { sut = new NavigationPresenterImpl(); }); - describe('#linkPrev', () => { - it('navigates to <link> elements whose rel attribute is "prev"', testPrev( - '<link rel="prev" href="#prev" />' - )); - - it('navigates to <link> elements whose rel attribute starts with "prev"', testPrev( - '<link rel="prev bar" href="#prev" />' - )); - - it('navigates to <link> elements whose rel attribute ends with "prev"', testPrev( - '<link rel="foo prev" href="#prev" />' - )); - - it('navigates to <link> elements whose rel attribute contains "prev"', testPrev( - '<link rel="foo prev bar" href="#prev" />' - )); - - it('navigates to <a> elements whose rel attribute is "prev"', testPrev( - '<a rel="prev" href="#prev">click me</a>' - )); - - it('navigates to <a> elements whose rel attribute starts with "prev"', testPrev( - '<a rel="prev bar" href="#prev">click me</a>' - )); - - it('navigates to <a> elements whose rel attribute ends with "prev"', testPrev( - '<a rel="foo prev" href="#prev">click me</a>' - )); - - it('navigates to <a> elements whose rel attribute contains "prev"', testPrev( - '<a rel="foo prev bar" href="#prev">click me</a>' - )); - - it('navigates to <a> elements whose text matches "prev"', testPrev( - '<a href="#dummy">preview</a><a href="#prev">go to prev</a>' - )); - - it('navigates to <a> elements whose text matches "previous"', testPrev( - '<a href="#dummy">previously</a><a href="#prev">previous page</a>' - )); - - it('navigates to <a> elements whose decoded text matches "<<"', testPrev( - '<a href="#dummy">click me</a><a href="#prev"><<</a>' - )); - - it('navigates to matching <a> elements by clicking', testPrev( - `<a rel="prev" href="#dummy" onclick="return location = '#prev', false">go to prev</a>` - )); - - it('prefers link[rel~=prev] to a[rel~=prev]', testPrev( - '<a rel="prev" href="#dummy">click me</a><link rel="prev" href="#prev" />' - )); - - it('prefers a[rel~=prev] to a::text(pattern)', testPrev( - '<a href="#dummy">go to prev</a><a rel="prev" href="#prev">click me</a>' - )); + describe("#linkPrev", () => { + it( + 'navigates to <link> elements whose rel attribute is "prev"', + testPrev('<link rel="prev" href="#prev" />') + ); + + it( + 'navigates to <link> elements whose rel attribute starts with "prev"', + testPrev('<link rel="prev bar" href="#prev" />') + ); + + it( + 'navigates to <link> elements whose rel attribute ends with "prev"', + testPrev('<link rel="foo prev" href="#prev" />') + ); + + it( + 'navigates to <link> elements whose rel attribute contains "prev"', + testPrev('<link rel="foo prev bar" href="#prev" />') + ); + + it( + 'navigates to <a> elements whose rel attribute is "prev"', + testPrev('<a rel="prev" href="#prev">click me</a>') + ); + + it( + 'navigates to <a> elements whose rel attribute starts with "prev"', + testPrev('<a rel="prev bar" href="#prev">click me</a>') + ); + + it( + 'navigates to <a> elements whose rel attribute ends with "prev"', + testPrev('<a rel="foo prev" href="#prev">click me</a>') + ); + + it( + 'navigates to <a> elements whose rel attribute contains "prev"', + testPrev('<a rel="foo prev bar" href="#prev">click me</a>') + ); + + it( + 'navigates to <a> elements whose text matches "prev"', + testPrev('<a href="#dummy">preview</a><a href="#prev">go to prev</a>') + ); + + it( + 'navigates to <a> elements whose text matches "previous"', + testPrev( + '<a href="#dummy">previously</a><a href="#prev">previous page</a>' + ) + ); + + it( + 'navigates to <a> elements whose decoded text matches "<<"', + testPrev('<a href="#dummy">click me</a><a href="#prev"><<</a>') + ); + + it( + "navigates to matching <a> elements by clicking", + testPrev( + `<a rel="prev" href="#dummy" onclick="return location = '#prev', false">go to prev</a>` + ) + ); + + it( + "prefers link[rel~=prev] to a[rel~=prev]", + testPrev( + '<a rel="prev" href="#dummy">click me</a><link rel="prev" href="#prev" />' + ) + ); + + it( + "prefers a[rel~=prev] to a::text(pattern)", + testPrev( + '<a href="#dummy">go to prev</a><a rel="prev" href="#prev">click me</a>' + ) + ); }); - describe('#linkNext', () => { - it('navigates to <link> elements whose rel attribute is "next"', testNext( - '<link rel="next" href="#next" />' - )); - - it('navigates to <link> elements whose rel attribute starts with "next"', testNext( - '<link rel="next bar" href="#next" />' - )); - - it('navigates to <link> elements whose rel attribute ends with "next"', testNext( - '<link rel="foo next" href="#next" />' - )); - - it('navigates to <link> elements whose rel attribute contains "next"', testNext( - '<link rel="foo next bar" href="#next" />' - )); - - it('navigates to <a> elements whose rel attribute is "next"', testNext( - '<a rel="next" href="#next">click me</a>' - )); - - it('navigates to <a> elements whose rel attribute starts with "next"', testNext( - '<a rel="next bar" href="#next">click me</a>' - )); - - it('navigates to <a> elements whose rel attribute ends with "next"', testNext( - '<a rel="foo next" href="#next">click me</a>' - )); - - it('navigates to <a> elements whose rel attribute contains "next"', testNext( - '<a rel="foo next bar" href="#next">click me</a>' - )); - - it('navigates to <a> elements whose text matches "next"', testNext( - '<a href="#dummy">inextricable</a><a href="#next">go to next</a>' - )); - - it('navigates to <a> elements whose decoded text matches ">>"', testNext( - '<a href="#dummy">click me</a><a href="#next">>></a>' - )); - - it('navigates to matching <a> elements by clicking', testNext( - `<a rel="next" href="#dummy" onclick="return location = '#next', false">go to next</a>` - )); - - it('prefers link[rel~=next] to a[rel~=next]', testNext( - '<a rel="next" href="#dummy">click me</a><link rel="next" href="#next" />' - )); - - it('prefers a[rel~=next] to a::text(pattern)', testNext( - '<a href="#dummy">next page</a><a rel="next" href="#next">click me</a>' - )); + describe("#linkNext", () => { + it( + 'navigates to <link> elements whose rel attribute is "next"', + testNext('<link rel="next" href="#next" />') + ); + + it( + 'navigates to <link> elements whose rel attribute starts with "next"', + testNext('<link rel="next bar" href="#next" />') + ); + + it( + 'navigates to <link> elements whose rel attribute ends with "next"', + testNext('<link rel="foo next" href="#next" />') + ); + + it( + 'navigates to <link> elements whose rel attribute contains "next"', + testNext('<link rel="foo next bar" href="#next" />') + ); + + it( + 'navigates to <a> elements whose rel attribute is "next"', + testNext('<a rel="next" href="#next">click me</a>') + ); + + it( + 'navigates to <a> elements whose rel attribute starts with "next"', + testNext('<a rel="next bar" href="#next">click me</a>') + ); + + it( + 'navigates to <a> elements whose rel attribute ends with "next"', + testNext('<a rel="foo next" href="#next">click me</a>') + ); + + it( + 'navigates to <a> elements whose rel attribute contains "next"', + testNext('<a rel="foo next bar" href="#next">click me</a>') + ); + + it( + 'navigates to <a> elements whose text matches "next"', + testNext( + '<a href="#dummy">inextricable</a><a href="#next">go to next</a>' + ) + ); + + it( + 'navigates to <a> elements whose decoded text matches ">>"', + testNext('<a href="#dummy">click me</a><a href="#next">>></a>') + ); + + it( + "navigates to matching <a> elements by clicking", + testNext( + `<a rel="next" href="#dummy" onclick="return location = '#next', false">go to next</a>` + ) + ); + + it( + "prefers link[rel~=next] to a[rel~=next]", + testNext( + '<a rel="next" href="#dummy">click me</a><link rel="next" href="#next" />' + ) + ); + + it( + "prefers a[rel~=next] to a::text(pattern)", + testNext( + '<a href="#dummy">next page</a><a rel="next" href="#next">click me</a>' + ) + ); }); }); diff --git a/test/content/repositories/AddonEnabledRepository.test.ts b/test/content/repositories/AddonEnabledRepository.test.ts index 7edd50e..13dff76 100644 --- a/test/content/repositories/AddonEnabledRepository.test.ts +++ b/test/content/repositories/AddonEnabledRepository.test.ts @@ -1,8 +1,8 @@ -import { AddonEnabledRepositoryImpl } from '../../../src/content/repositories/AddonEnabledRepository'; -import { expect } from 'chai'; +import { AddonEnabledRepositoryImpl } from "../../../src/content/repositories/AddonEnabledRepository"; +import { expect } from "chai"; -describe('AddonEnabledRepositoryImpl', () => { - it('updates and gets current value', () => { +describe("AddonEnabledRepositoryImpl", () => { + it("updates and gets current value", () => { const sut = new AddonEnabledRepositoryImpl(); sut.set(true); @@ -12,4 +12,3 @@ describe('AddonEnabledRepositoryImpl', () => { expect(sut.get()).to.be.false; }); }); - diff --git a/test/content/repositories/FindRepository.test.ts b/test/content/repositories/FindRepository.test.ts index 0e50b0a..e0abb9d 100644 --- a/test/content/repositories/FindRepository.test.ts +++ b/test/content/repositories/FindRepository.test.ts @@ -1,15 +1,14 @@ -import { FindRepositoryImpl } from '../../../src/content/repositories/FindRepository'; -import { expect } from 'chai'; +import { FindRepositoryImpl } from "../../../src/content/repositories/FindRepository"; +import { expect } from "chai"; -describe('FindRepositoryImpl', () => { - it('updates and gets last keyword', () => { +describe("FindRepositoryImpl", () => { + it("updates and gets last keyword", () => { const sut = new FindRepositoryImpl(); expect(sut.getLastKeyword()).to.be.null; - sut.setLastKeyword('monkey'); + sut.setLastKeyword("monkey"); - expect(sut.getLastKeyword()).to.equal('monkey'); + expect(sut.getLastKeyword()).to.equal("monkey"); }); }); - diff --git a/test/content/repositories/FollowKeyRepository.test.ts b/test/content/repositories/FollowKeyRepository.test.ts index eae58b9..6608662 100644 --- a/test/content/repositories/FollowKeyRepository.test.ts +++ b/test/content/repositories/FollowKeyRepository.test.ts @@ -1,31 +1,29 @@ -import FollowKeyRepository, { FollowKeyRepositoryImpl } - from '../../../src/content/repositories/FollowKeyRepository'; -import { expect } from 'chai'; +import FollowKeyRepository, { + FollowKeyRepositoryImpl, +} from "../../../src/content/repositories/FollowKeyRepository"; +import { expect } from "chai"; -describe('FollowKeyRepositoryImpl', () => { +describe("FollowKeyRepositoryImpl", () => { let sut: FollowKeyRepository; before(() => { sut = new FollowKeyRepositoryImpl(); }); - describe('#getKeys()/#pushKey()/#popKey()', () => { - it('enqueues keys', () => { + describe("#getKeys()/#pushKey()/#popKey()", () => { + it("enqueues keys", () => { expect(sut.getKeys()).to.be.empty; - sut.pushKey('a'); - sut.pushKey('b'); - sut.pushKey('c'); - expect(sut.getKeys()).to.deep.equal(['a', 'b', 'c']); + sut.pushKey("a"); + sut.pushKey("b"); + sut.pushKey("c"); + expect(sut.getKeys()).to.deep.equal(["a", "b", "c"]); sut.popKey(); - expect(sut.getKeys()).to.deep.equal(['a', 'b']); + expect(sut.getKeys()).to.deep.equal(["a", "b"]); sut.clearKeys(); expect(sut.getKeys()).to.be.empty; }); }); }); - - - diff --git a/test/content/repositories/FollowMasterRepository.test.ts b/test/content/repositories/FollowMasterRepository.test.ts index 3eb172f..9b5e151 100644 --- a/test/content/repositories/FollowMasterRepository.test.ts +++ b/test/content/repositories/FollowMasterRepository.test.ts @@ -1,42 +1,43 @@ -import FollowMasterRepository, { FollowMasterRepositoryImpl } - from '../../../src/content/repositories/FollowMasterRepository'; -import { expect } from 'chai'; +import FollowMasterRepository, { + FollowMasterRepositoryImpl, +} from "../../../src/content/repositories/FollowMasterRepository"; +import { expect } from "chai"; -describe('FollowMasterRepositoryImpl', () => { +describe("FollowMasterRepositoryImpl", () => { let sut: FollowMasterRepository; before(() => { sut = new FollowMasterRepositoryImpl(); }); - describe('#getTags()/#addTag()/#clearTags()', () => { - it('gets, adds and clears tags', () => { + describe("#getTags()/#addTag()/#clearTags()", () => { + it("gets, adds and clears tags", () => { expect(sut.getTags()).to.be.empty; - sut.addTag('a'); - sut.addTag('b'); - sut.addTag('c'); - expect(sut.getTags()).to.deep.equal(['a', 'b', 'c']); + sut.addTag("a"); + sut.addTag("b"); + sut.addTag("c"); + expect(sut.getTags()).to.deep.equal(["a", "b", "c"]); sut.clearTags(); expect(sut.getTags()).to.be.empty; }); }); - describe('#getTagsByPrefix', () => { - it('gets tags matched by prefix', () => { - for (const tag of ['a', 'aa', 'ab', 'b', 'ba', 'bb']) { + describe("#getTagsByPrefix", () => { + it("gets tags matched by prefix", () => { + for (const tag of ["a", "aa", "ab", "b", "ba", "bb"]) { sut.addTag(tag); } - expect(sut.getTagsByPrefix('a')).to.deep.equal(['a', 'aa', 'ab']); - expect(sut.getTagsByPrefix('aa')).to.deep.equal(['aa']); - expect(sut.getTagsByPrefix('b')).to.deep.equal(['b', 'ba', 'bb']); - expect(sut.getTagsByPrefix('c')).to.be.empty; + expect(sut.getTagsByPrefix("a")).to.deep.equal(["a", "aa", "ab"]); + expect(sut.getTagsByPrefix("aa")).to.deep.equal(["aa"]); + expect(sut.getTagsByPrefix("b")).to.deep.equal(["b", "ba", "bb"]); + expect(sut.getTagsByPrefix("c")).to.be.empty; }); }); - describe('#setCurrentFollowMode()/#getCurrentNewTabMode()/#getCurrentBackgroundMode', () => { - it('updates and gets follow mode', () => { + describe("#setCurrentFollowMode()/#getCurrentNewTabMode()/#getCurrentBackgroundMode", () => { + it("updates and gets follow mode", () => { sut.setCurrentFollowMode(false, true); expect(sut.getCurrentNewTabMode()).to.be.false; expect(sut.getCurrentBackgroundMode()).to.be.true; diff --git a/test/content/repositories/FollowSlaveRepository.test.ts b/test/content/repositories/FollowSlaveRepository.test.ts index 10cf094..0f829b2 100644 --- a/test/content/repositories/FollowSlaveRepository.test.ts +++ b/test/content/repositories/FollowSlaveRepository.test.ts @@ -1,16 +1,17 @@ -import FollowSlaveRepository, { FollowSlaveRepositoryImpl } - from '../../../src/content/repositories/FollowSlaveRepository'; -import { expect } from 'chai'; +import FollowSlaveRepository, { + FollowSlaveRepositoryImpl, +} from "../../../src/content/repositories/FollowSlaveRepository"; +import { expect } from "chai"; -describe('FollowSlaveRepository', () => { +describe("FollowSlaveRepository", () => { let sut: FollowSlaveRepository; before(() => { sut = new FollowSlaveRepositoryImpl(); }); - describe('#isFollowMode()/#enableFollowMode()/#disableFollowMode()', () => { - it('gets, adds updates follow mode', () => { + describe("#isFollowMode()/#enableFollowMode()/#disableFollowMode()", () => { + it("gets, adds updates follow mode", () => { expect(sut.isFollowMode()).to.be.false; sut.enableFollowMode(); @@ -21,4 +22,3 @@ describe('FollowSlaveRepository', () => { }); }); }); - diff --git a/test/content/repositories/KeymapRepository.test.ts b/test/content/repositories/KeymapRepository.test.ts index 68f515c..0e01a73 100644 --- a/test/content/repositories/KeymapRepository.test.ts +++ b/test/content/repositories/KeymapRepository.test.ts @@ -1,39 +1,38 @@ -import KeymapRepository, { KeymapRepositoryImpl } - from '../../../src/content/repositories/KeymapRepository'; -import { expect } from 'chai'; +import KeymapRepository, { + KeymapRepositoryImpl, +} from "../../../src/content/repositories/KeymapRepository"; +import { expect } from "chai"; import Key from "../../../src/shared/settings/Key"; -describe('KeymapRepositoryImpl', () => { +describe("KeymapRepositoryImpl", () => { let sut: KeymapRepository; before(() => { sut = new KeymapRepositoryImpl(); }); - describe('#enqueueKey()', () => { - it('enqueues keys', () => { - sut.enqueueKey(Key.fromMapKey('a')); - sut.enqueueKey(Key.fromMapKey('b')); - const sequence = sut.enqueueKey(Key.fromMapKey('c')); + describe("#enqueueKey()", () => { + it("enqueues keys", () => { + sut.enqueueKey(Key.fromMapKey("a")); + sut.enqueueKey(Key.fromMapKey("b")); + const sequence = sut.enqueueKey(Key.fromMapKey("c")); const keys = sequence.keys; - expect(keys[0].equals(Key.fromMapKey('a'))).to.be.true; - expect(keys[1].equals(Key.fromMapKey('b'))).to.be.true; - expect(keys[2].equals(Key.fromMapKey('c'))).to.be.true; + expect(keys[0].equals(Key.fromMapKey("a"))).to.be.true; + expect(keys[1].equals(Key.fromMapKey("b"))).to.be.true; + expect(keys[2].equals(Key.fromMapKey("c"))).to.be.true; }); }); - describe('#clear()', () => { - it('clears keys', () => { - sut.enqueueKey(Key.fromMapKey('a')); - sut.enqueueKey(Key.fromMapKey('b')); - sut.enqueueKey(Key.fromMapKey('c')); + describe("#clear()", () => { + it("clears keys", () => { + sut.enqueueKey(Key.fromMapKey("a")); + sut.enqueueKey(Key.fromMapKey("b")); + sut.enqueueKey(Key.fromMapKey("c")); sut.clear(); - const sequence = sut.enqueueKey(Key.fromMapKey('a')); + const sequence = sut.enqueueKey(Key.fromMapKey("a")); expect(sequence.length()).to.equal(1); }); }); }); - - diff --git a/test/content/repositories/MarkKeyRepository.test.ts b/test/content/repositories/MarkKeyRepository.test.ts index 8592332..473b4dc 100644 --- a/test/content/repositories/MarkKeyRepository.test.ts +++ b/test/content/repositories/MarkKeyRepository.test.ts @@ -1,16 +1,17 @@ -import MarkRepository, { MarkKeyRepositoryImpl } - from '../../../src/content/repositories/MarkKeyRepository'; -import { expect } from 'chai'; +import MarkRepository, { + MarkKeyRepositoryImpl, +} from "../../../src/content/repositories/MarkKeyRepository"; +import { expect } from "chai"; -describe('MarkKeyRepositoryImpl', () => { +describe("MarkKeyRepositoryImpl", () => { let sut: MarkRepository; before(() => { sut = new MarkKeyRepositoryImpl(); - }) + }); - describe('#isSetMode/#enableSetMode/#disabeSetMode', () => { - it('enables and disables set mode', () => { + describe("#isSetMode/#enableSetMode/#disabeSetMode", () => { + it("enables and disables set mode", () => { expect(sut.isSetMode()).to.be.false; sut.enableSetMode(); @@ -21,8 +22,8 @@ describe('MarkKeyRepositoryImpl', () => { }); }); - describe('#isJumpMode/#enableJumpMode/#disabeJumpMode', () => { - it('enables and disables jump mode', () => { + describe("#isJumpMode/#enableJumpMode/#disabeJumpMode", () => { + it("enables and disables jump mode", () => { expect(sut.isJumpMode()).to.be.false; sut.enableJumpMode(); @@ -33,4 +34,3 @@ describe('MarkKeyRepositoryImpl', () => { }); }); }); - diff --git a/test/content/repositories/MarkRepository.test.ts b/test/content/repositories/MarkRepository.test.ts index 6ddd38d..f2a7326 100644 --- a/test/content/repositories/MarkRepository.test.ts +++ b/test/content/repositories/MarkRepository.test.ts @@ -1,13 +1,12 @@ -import { MarkRepositoryImpl } from '../../../src/content/repositories/MarkRepository'; -import { expect } from 'chai'; +import { MarkRepositoryImpl } from "../../../src/content/repositories/MarkRepository"; +import { expect } from "chai"; -describe('MarkRepositoryImpl', () => { - it('save and load marks', () => { +describe("MarkRepositoryImpl", () => { + it("save and load marks", () => { const sut = new MarkRepositoryImpl(); - sut.set('a', { x: 10, y: 20 }); - expect(sut.get('a')).to.deep.equal({ x: 10, y: 20 }); - expect(sut.get('b')).to.be.null; + sut.set("a", { x: 10, y: 20 }); + expect(sut.get("a")).to.deep.equal({ x: 10, y: 20 }); + expect(sut.get("b")).to.be.null; }); }); - diff --git a/test/content/repositories/SettingRepository.test.ts b/test/content/repositories/SettingRepository.test.ts index e45d7c4..99247a9 100644 --- a/test/content/repositories/SettingRepository.test.ts +++ b/test/content/repositories/SettingRepository.test.ts @@ -1,23 +1,23 @@ -import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository'; -import { expect } from 'chai'; -import Settings from '../../../src/shared/settings/Settings'; +import { SettingRepositoryImpl } from "../../../src/content/repositories/SettingRepository"; +import { expect } from "chai"; +import Settings from "../../../src/shared/settings/Settings"; -describe('SettingRepositoryImpl', () => { - it('updates and gets current value', () => { +describe("SettingRepositoryImpl", () => { + it("updates and gets current value", () => { const sut = new SettingRepositoryImpl(); const settings = Settings.fromJSON({ keymaps: {}, - search:{ - default: 'google', + search: { + default: "google", engines: { - google: 'https://google.com/?q={}', - } + google: "https://google.com/?q={}", + }, }, properties: { - hintchars: 'abcd1234', + hintchars: "abcd1234", smoothscroll: false, - complete: 'sbh', + complete: "sbh", }, blacklist: [], }); @@ -25,6 +25,6 @@ describe('SettingRepositoryImpl', () => { sut.set(settings); const actual = sut.get(); - expect(actual.properties.hintchars).to.equal('abcd1234'); + expect(actual.properties.hintchars).to.equal("abcd1234"); }); }); diff --git a/test/content/usecases/AddonEnabledUseCase.test.ts b/test/content/usecases/AddonEnabledUseCase.test.ts index 8c15099..885da83 100644 --- a/test/content/usecases/AddonEnabledUseCase.test.ts +++ b/test/content/usecases/AddonEnabledUseCase.test.ts @@ -1,7 +1,7 @@ -import AddonEnabledRepository from '../../../src/content/repositories/AddonEnabledRepository'; -import AddonEnabledUseCase from '../../../src/content/usecases/AddonEnabledUseCase'; -import AddonIndicatorClient from '../../../src/content/client/AddonIndicatorClient'; -import { expect } from 'chai'; +import AddonEnabledRepository from "../../../src/content/repositories/AddonEnabledRepository"; +import AddonEnabledUseCase from "../../../src/content/usecases/AddonEnabledUseCase"; +import AddonIndicatorClient from "../../../src/content/client/AddonIndicatorClient"; +import { expect } from "chai"; class MockAddonEnabledRepository implements AddonEnabledRepository { private enabled: boolean; @@ -28,11 +28,11 @@ class MockAddonIndicatorClient implements AddonIndicatorClient { async setEnabled(enabled: boolean): Promise<void> { this.enabled = enabled; - return + return; } } -describe('AddonEnabledUseCase', () => { +describe("AddonEnabledUseCase", () => { let repository: MockAddonEnabledRepository; let indicator: MockAddonIndicatorClient; let sut: AddonEnabledUseCase; @@ -43,8 +43,8 @@ describe('AddonEnabledUseCase', () => { sut = new AddonEnabledUseCase(indicator, repository); }); - describe('#enable', () => { - it('store and indicate as enabled', async() => { + describe("#enable", () => { + it("store and indicate as enabled", async () => { await sut.enable(); expect(repository.get()).to.be.true; @@ -52,8 +52,8 @@ describe('AddonEnabledUseCase', () => { }); }); - describe('#disable', async() => { - it('store and indicate as disabled', async() => { + describe("#disable", async () => { + it("store and indicate as disabled", async () => { await sut.disable(); expect(repository.get()).to.be.false; @@ -61,8 +61,8 @@ describe('AddonEnabledUseCase', () => { }); }); - describe('#toggle', () => { - it('toggled enabled and disabled', async() => { + describe("#toggle", () => { + it("toggled enabled and disabled", async () => { repository.set(true); await sut.toggle(); @@ -78,8 +78,8 @@ describe('AddonEnabledUseCase', () => { }); }); - describe('#getEnabled', () => { - it('returns current addon enabled', () => { + describe("#getEnabled", () => { + it("returns current addon enabled", () => { repository.set(true); expect(sut.getEnabled()).to.be.true; diff --git a/test/content/usecases/ClipboardUseCase.test.ts b/test/content/usecases/ClipboardUseCase.test.ts index 3cc82fe..5de3e69 100644 --- a/test/content/usecases/ClipboardUseCase.test.ts +++ b/test/content/usecases/ClipboardUseCase.test.ts @@ -1,14 +1,14 @@ -import ClipboardRepository from '../../../src/content/repositories/ClipboardRepository'; -import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository'; -import ClipboardUseCase from '../../../src/content/usecases/ClipboardUseCase'; -import OperationClient from '../../../src/content/client/OperationClient'; -import ConsoleClient from '../../../src/content/client/ConsoleClient'; +import ClipboardRepository from "../../../src/content/repositories/ClipboardRepository"; +import { SettingRepositoryImpl } from "../../../src/content/repositories/SettingRepository"; +import ClipboardUseCase from "../../../src/content/usecases/ClipboardUseCase"; +import OperationClient from "../../../src/content/client/OperationClient"; +import ConsoleClient from "../../../src/content/client/ConsoleClient"; -import * as sinon from 'sinon'; -import { expect } from 'chai'; -import {Operation} from "../../../src/shared/operations"; +import * as sinon from "sinon"; +import { expect } from "chai"; +import { Operation } from "../../../src/shared/operations"; -describe('ClipboardUseCase', () => { +describe("ClipboardUseCase", () => { let clipboardRepository: ClipboardRepository; let operationClient: OperationClient; @@ -18,34 +18,48 @@ describe('ClipboardUseCase', () => { let sut: ClipboardUseCase; beforeEach(() => { - clipboardRepository = new class implements ClipboardRepository { - read(): string { return ""; } + clipboardRepository = new (class implements ClipboardRepository { + read(): string { + return ""; + } write(_text: string) {} - }; - operationClient = new class implements OperationClient { - execBackgroundOp(_repeat: number, _op: Operation): Promise<void> { return Promise.resolve() } - internalOpenUrl(_url: string, _newTab?: boolean, _background?: boolean): Promise<void> { return Promise.resolve() } - }; - consoleClient = new class implements ConsoleClient { - error(_text: string): Promise<void> { return Promise.resolve() } - info(_text: string): Promise<void> { return Promise.resolve() } - }; + })(); + operationClient = new (class implements OperationClient { + execBackgroundOp(_repeat: number, _op: Operation): Promise<void> { + return Promise.resolve(); + } + internalOpenUrl( + _url: string, + _newTab?: boolean, + _background?: boolean + ): Promise<void> { + return Promise.resolve(); + } + })(); + consoleClient = new (class implements ConsoleClient { + error(_text: string): Promise<void> { + return Promise.resolve(); + } + info(_text: string): Promise<void> { + return Promise.resolve(); + } + })(); sut = new ClipboardUseCase( clipboardRepository, new SettingRepositoryImpl(), consoleClient, - operationClient, - ); + operationClient + ); }); - describe('#yankCurrentURL', () => { - it('yanks current url', async () => { + describe("#yankCurrentURL", () => { + it("yanks current url", async () => { const href = window.location.href; const mockRepository = sinon.mock(clipboardRepository); - mockRepository.expects('write').withArgs(href); + mockRepository.expects("write").withArgs(href); const mockConsoleClient = sinon.mock(consoleClient); - mockConsoleClient.expects('info').withArgs('Yanked ' + href); + mockConsoleClient.expects("info").withArgs("Yanked " + href); const yanked = await sut.yankCurrentURL(); @@ -55,23 +69,23 @@ describe('ClipboardUseCase', () => { }); }); - describe('#openOrSearch', () => { - it('opens url from the clipboard', async () => { - const url = 'https://github.com/ueokande/vim-vixen' - sinon.stub(clipboardRepository, 'read').returns(url); + describe("#openOrSearch", () => { + it("opens url from the clipboard", async () => { + const url = "https://github.com/ueokande/vim-vixen"; + sinon.stub(clipboardRepository, "read").returns(url); const mockOperationClient = sinon.mock(operationClient); - mockOperationClient.expects('internalOpenUrl').withArgs(url, true); + mockOperationClient.expects("internalOpenUrl").withArgs(url, true); await sut.openOrSearch(true); mockOperationClient.verify(); }); - it('opens search results from the clipboard', async () => { - const url = 'https://google.com/search?q=banana'; - sinon.stub(clipboardRepository, 'read').returns('banana'); + it("opens search results from the clipboard", async () => { + const url = "https://google.com/search?q=banana"; + sinon.stub(clipboardRepository, "read").returns("banana"); const mockOperationClient = sinon.mock(operationClient); - mockOperationClient.expects('internalOpenUrl').withArgs(url, true); + mockOperationClient.expects("internalOpenUrl").withArgs(url, true); await sut.openOrSearch(true); diff --git a/test/content/usecases/FindUseCase.test.ts b/test/content/usecases/FindUseCase.test.ts index 3978dbc..b53ef74 100644 --- a/test/content/usecases/FindUseCase.test.ts +++ b/test/content/usecases/FindUseCase.test.ts @@ -1,9 +1,9 @@ -import FindRepository from '../../../src/content/repositories/FindRepository'; -import FindPresenter from '../../../src/content/presenters/FindPresenter'; -import FindClient from '../../../src/content/client/FindClient'; -import FindUseCase from '../../../src/content/usecases/FindUseCase'; -import MockConsoleClient from '../mock/MockConsoleClient'; -import { expect } from 'chai'; +import FindRepository from "../../../src/content/repositories/FindRepository"; +import FindPresenter from "../../../src/content/presenters/FindPresenter"; +import FindClient from "../../../src/content/client/FindClient"; +import FindUseCase from "../../../src/content/usecases/FindUseCase"; +import MockConsoleClient from "../mock/MockConsoleClient"; +import { expect } from "chai"; class MockFindRepository implements FindRepository { public keyword: string | null; @@ -27,7 +27,7 @@ class MockFindPresenter implements FindPresenter { public highlighted: boolean; constructor() { - this.document = ''; + this.document = ""; this.highlighted = false; } @@ -59,7 +59,7 @@ class MockFindClient implements FindClient { } } -describe('FindUseCase', () => { +describe("FindUseCase", () => { let repository: MockFindRepository; let presenter: MockFindPresenter; let client: MockFindClient; @@ -74,88 +74,87 @@ describe('FindUseCase', () => { sut = new FindUseCase(presenter, repository, client, consoleClient); }); - describe('#startFind', () => { - it('find next by ketword', async() => { - presenter.document = 'monkey punch'; + describe("#startFind", () => { + it("find next by ketword", async () => { + presenter.document = "monkey punch"; - await sut.startFind('monkey'); + await sut.startFind("monkey"); expect(await presenter.highlighted).to.be.true; - expect(await consoleClient.text).to.equal('Pattern found: monkey'); - expect(await repository.getLastKeyword()).to.equal('monkey'); - expect(await client.getGlobalLastKeyword()).to.equal('monkey'); + expect(await consoleClient.text).to.equal("Pattern found: monkey"); + expect(await repository.getLastKeyword()).to.equal("monkey"); + expect(await client.getGlobalLastKeyword()).to.equal("monkey"); }); - it('find next by last keyword', async() => { - presenter.document = 'gorilla kick'; - repository.keyword = 'gorilla'; + it("find next by last keyword", async () => { + presenter.document = "gorilla kick"; + repository.keyword = "gorilla"; await sut.startFind(undefined); expect(await presenter.highlighted).to.be.true; - expect(await consoleClient.text).to.equal('Pattern found: gorilla'); - expect(await repository.getLastKeyword()).to.equal('gorilla'); - expect(await client.getGlobalLastKeyword()).to.equal('gorilla'); + expect(await consoleClient.text).to.equal("Pattern found: gorilla"); + expect(await repository.getLastKeyword()).to.equal("gorilla"); + expect(await client.getGlobalLastKeyword()).to.equal("gorilla"); }); - it('find next by global last keyword', async() => { - presenter.document = 'chimpanzee typing'; + it("find next by global last keyword", async () => { + presenter.document = "chimpanzee typing"; repository.keyword = null; - client.keyword = 'chimpanzee'; + client.keyword = "chimpanzee"; await sut.startFind(undefined); expect(await presenter.highlighted).to.be.true; - expect(await consoleClient.text).to.equal('Pattern found: chimpanzee'); - expect(await repository.getLastKeyword()).to.equal('chimpanzee'); - expect(await client.getGlobalLastKeyword()).to.equal('chimpanzee'); + expect(await consoleClient.text).to.equal("Pattern found: chimpanzee"); + expect(await repository.getLastKeyword()).to.equal("chimpanzee"); + expect(await client.getGlobalLastKeyword()).to.equal("chimpanzee"); }); - it('find not found error', async() => { - presenter.document = 'zoo'; + it("find not found error", async () => { + presenter.document = "zoo"; - await sut.startFind('giraffe'); + await sut.startFind("giraffe"); expect(await presenter.highlighted).to.be.false; - expect(await consoleClient.text).to.equal('Pattern not found: giraffe'); - expect(await repository.getLastKeyword()).to.equal('giraffe'); - expect(await client.getGlobalLastKeyword()).to.equal('giraffe'); + expect(await consoleClient.text).to.equal("Pattern not found: giraffe"); + expect(await repository.getLastKeyword()).to.equal("giraffe"); + expect(await client.getGlobalLastKeyword()).to.equal("giraffe"); }); - it('show errors when no last keywords', async() => { + it("show errors when no last keywords", async () => { repository.keyword = null; client.keyword = null; await sut.startFind(undefined); - expect(await consoleClient.text).to.equal('No previous search keywords'); + expect(await consoleClient.text).to.equal("No previous search keywords"); expect(await consoleClient.isError).to.be.true; }); }); - describe('#findNext', () => { - it('finds by last keyword', async() => { - presenter.document = 'monkey punch'; - repository.keyword = 'monkey'; + describe("#findNext", () => { + it("finds by last keyword", async () => { + presenter.document = "monkey punch"; + repository.keyword = "monkey"; await sut.findNext(); expect(await presenter.highlighted).to.be.true; - expect(await consoleClient.text).to.equal('Pattern found: monkey'); + expect(await consoleClient.text).to.equal("Pattern found: monkey"); }); - it('show errors when no last keywords', async() => { + it("show errors when no last keywords", async () => { repository.keyword = null; client.keyword = null; await sut.findNext(); - expect(await consoleClient.text).to.equal('No previous search keywords'); + expect(await consoleClient.text).to.equal("No previous search keywords"); expect(await consoleClient.isError).to.be.true; }); }); - describe('#findPrev', () => { - }); + describe("#findPrev", () => {}); }); diff --git a/test/content/usecases/HintKeyProducer.test.ts b/test/content/usecases/HintKeyProducer.test.ts index 5841ae9..f7e02ea 100644 --- a/test/content/usecases/HintKeyProducer.test.ts +++ b/test/content/usecases/HintKeyProducer.test.ts @@ -1,20 +1,34 @@ -import HintKeyProducer from '../../../src/content/usecases/HintKeyProducer'; -import { expect } from 'chai'; +import HintKeyProducer from "../../../src/content/usecases/HintKeyProducer"; +import { expect } from "chai"; -describe('HintKeyProducer class', () => { - describe('#constructor', () => { - it('throws an exception on empty charset', () => { - expect(() => new HintKeyProducer('')).to.throw(TypeError); +describe("HintKeyProducer class", () => { + describe("#constructor", () => { + it("throws an exception on empty charset", () => { + expect(() => new HintKeyProducer("")).to.throw(TypeError); }); }); - describe('#produce', () => { - it('produce incremented keys', () => { - const charset = 'abc'; + describe("#produce", () => { + it("produce incremented keys", () => { + const charset = "abc"; const sequences = [ - 'a', 'b', 'c', - 'aa', 'ab', 'ac', 'ba', 'bb', 'bc', 'ca', 'cb', 'cc', - 'aaa', 'aab', 'aac', 'aba'] + "a", + "b", + "c", + "aa", + "ab", + "ac", + "ba", + "bb", + "bc", + "ca", + "cb", + "cc", + "aaa", + "aab", + "aac", + "aba", + ]; const producer = new HintKeyProducer(charset); for (let i = 0; i < sequences.length; ++i) { diff --git a/test/content/usecases/KeymapUseCase.test.ts b/test/content/usecases/KeymapUseCase.test.ts index 032d4fc..24ac6d8 100644 --- a/test/content/usecases/KeymapUseCase.test.ts +++ b/test/content/usecases/KeymapUseCase.test.ts @@ -1,62 +1,52 @@ import "reflect-metadata"; -import KeymapUseCase from '../../../src/content/usecases/KeymapUseCase'; -import {expect} from 'chai'; +import KeymapUseCase from "../../../src/content/usecases/KeymapUseCase"; +import { expect } from "chai"; import SettingRepository from "../../../src/content/repositories/SettingRepository"; import Settings from "../../../src/shared/settings/Settings"; import AddonEnabledRepository from "../../../src/content/repositories/AddonEnabledRepository"; -import {KeymapRepositoryImpl} from "../../../src/content/repositories/KeymapRepository"; +import { KeymapRepositoryImpl } from "../../../src/content/repositories/KeymapRepository"; import Key from "../../../src/shared/settings/Key"; import AddressRepository from "../../../src/content/repositories/AddressRepository"; class MockSettingRepository implements SettingRepository { - constructor( - private readonly settings: Settings, - ) { - } + constructor(private readonly settings: Settings) {} get(): Settings { return this.settings; } set(_setting: Settings): void { - throw new Error('TODO'); + throw new Error("TODO"); } } class MockAddonEnabledRepository implements AddonEnabledRepository { - constructor( - private readonly enabled: boolean, - ) { - } + constructor(private readonly enabled: boolean) {} get(): boolean { return this.enabled; } set(_on: boolean): void { - throw new Error('TODO'); + throw new Error("TODO"); } } class MockAddressRepository implements AddressRepository { - constructor( - private url: URL, - ) { - } + constructor(private url: URL) {} getCurrentURL(): URL { return this.url; } } - -describe('KeymapUseCase', () => { - context('with no-digis keymaps', () => { +describe("KeymapUseCase", () => { + context("with no-digis keymaps", () => { const settings = Settings.fromJSON({ keymaps: { - k: {type: 'scroll.vertically', count: -1}, - j: {type: 'scroll.vertically', count: 1}, - gg: {type: 'scroll.top'}, + k: { type: "scroll.vertically", count: -1 }, + j: { type: "scroll.vertically", count: 1 }, + gg: { type: "scroll.top" }, }, }); @@ -64,34 +54,46 @@ describe('KeymapUseCase', () => { before(() => { sut = new KeymapUseCase( - new KeymapRepositoryImpl(), - new MockSettingRepository(settings), - new MockAddonEnabledRepository(true), - new MockAddressRepository(new URL('https://example.com')), + new KeymapRepositoryImpl(), + new MockSettingRepository(settings), + new MockAddonEnabledRepository(true), + new MockAddressRepository(new URL("https://example.com")) ); }); - it('returns matched operation', () => { - expect(sut.nextOps(Key.fromMapKey('k'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.vertically', count: -1}}); - expect(sut.nextOps(Key.fromMapKey('j'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.vertically', count: 1}}); - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.top'}}); - expect(sut.nextOps(Key.fromMapKey('z'))).to.be.null; + it("returns matched operation", () => { + expect(sut.nextOps(Key.fromMapKey("k"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.vertically", count: -1 }, + }); + expect(sut.nextOps(Key.fromMapKey("j"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.vertically", count: 1 }, + }); + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.top" }, + }); + expect(sut.nextOps(Key.fromMapKey("z"))).to.be.null; }); - it('repeats n-times by numeric prefix and multiple key operations', () => { - expect(sut.nextOps(Key.fromMapKey('1'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('0'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.deep.equal({ repeat: 10, op: {type: "scroll.top"}}); + it("repeats n-times by numeric prefix and multiple key operations", () => { + expect(sut.nextOps(Key.fromMapKey("1"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("0"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.deep.equal({ + repeat: 10, + op: { type: "scroll.top" }, + }); }); }); - context('when keymaps containing numeric mappings', () => { + context("when keymaps containing numeric mappings", () => { const settings = Settings.fromJSON({ keymaps: { - 20: {type: "scroll.top"}, - g5: {type: 'scroll.bottom'}, + 20: { type: "scroll.top" }, + g5: { type: "scroll.bottom" }, }, }); @@ -99,43 +101,55 @@ describe('KeymapUseCase', () => { before(() => { sut = new KeymapUseCase( - new KeymapRepositoryImpl(), - new MockSettingRepository(settings), - new MockAddonEnabledRepository(true), - new MockAddressRepository(new URL('https://example.com')), + new KeymapRepositoryImpl(), + new MockSettingRepository(settings), + new MockAddonEnabledRepository(true), + new MockAddressRepository(new URL("https://example.com")) ); }); - it('returns the matched operation ends with digit', () => { - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('5'))).to.be.deep.equal({ repeat: 1, op: { type: 'scroll.bottom'}}); + it("returns the matched operation ends with digit", () => { + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("5"))).to.be.deep.equal({ + repeat: 1, + op: { type: "scroll.bottom" }, + }); }); - it('returns an operation matched the operation with digit keymaps', () => { - expect(sut.nextOps(Key.fromMapKey('2'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('0'))).to.be.deep.equal({ repeat: 1, op: { type: 'scroll.top'}}); + it("returns an operation matched the operation with digit keymaps", () => { + expect(sut.nextOps(Key.fromMapKey("2"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("0"))).to.be.deep.equal({ + repeat: 1, + op: { type: "scroll.top" }, + }); }); - it('returns operations repeated by numeric prefix', () => { - expect(sut.nextOps(Key.fromMapKey('2'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('5'))).to.be.deep.equal({ repeat: 2, op: { type: 'scroll.bottom'}}); + it("returns operations repeated by numeric prefix", () => { + expect(sut.nextOps(Key.fromMapKey("2"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("5"))).to.be.deep.equal({ + repeat: 2, + op: { type: "scroll.bottom" }, + }); }); - it('does not matches with digit operation with numeric prefix', () => { - expect(sut.nextOps(Key.fromMapKey('3'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('2'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('0'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('5'))).to.be.deep.equal({ repeat: 320, op: { type: 'scroll.bottom'}}); + it("does not matches with digit operation with numeric prefix", () => { + expect(sut.nextOps(Key.fromMapKey("3"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("2"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("0"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("5"))).to.be.deep.equal({ + repeat: 320, + op: { type: "scroll.bottom" }, + }); }); }); - context('when the keys are mismatched with the operations', () => { + context("when the keys are mismatched with the operations", () => { const settings = Settings.fromJSON({ keymaps: { - gg: {type: "scroll.top"}, - G: {type: "scroll.bottom"}, + gg: { type: "scroll.top" }, + G: { type: "scroll.bottom" }, }, }); @@ -143,38 +157,44 @@ describe('KeymapUseCase', () => { before(() => { sut = new KeymapUseCase( - new KeymapRepositoryImpl(), - new MockSettingRepository(settings), - new MockAddonEnabledRepository(true), - new MockAddressRepository(new URL('https://example.com')), + new KeymapRepositoryImpl(), + new MockSettingRepository(settings), + new MockAddonEnabledRepository(true), + new MockAddressRepository(new URL("https://example.com")) ); }); - it('clears input keys with no-matched operations', () => { - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('x'))).to.be.null; // clear - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.deep.equal({repeat: 1, op: {type: "scroll.top"}}); + it("clears input keys with no-matched operations", () => { + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("x"))).to.be.null; // clear + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.top" }, + }); }); - it('clears input keys and the prefix with no-matched operations', () => { - expect(sut.nextOps(Key.fromMapKey('1'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('0'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('x'))).to.be.null; // clear - expect(sut.nextOps(Key.fromMapKey('1'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('0'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.deep.equal({ repeat: 10, op: {type: "scroll.top"}}); + it("clears input keys and the prefix with no-matched operations", () => { + expect(sut.nextOps(Key.fromMapKey("1"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("0"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("x"))).to.be.null; // clear + expect(sut.nextOps(Key.fromMapKey("1"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("0"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.deep.equal({ + repeat: 10, + op: { type: "scroll.top" }, + }); }); }); - context('when the site matches to the blacklist', () => { + context("when the site matches to the blacklist", () => { const settings = Settings.fromJSON({ keymaps: { - k: {type: 'scroll.vertically', count: -1}, - a: {type: 'addon.enable'}, - b: {type: 'addon.toggle.enabled'}, + k: { type: "scroll.vertically", count: -1 }, + a: { type: "addon.enable" }, + b: { type: "addon.toggle.enabled" }, }, }); @@ -182,58 +202,76 @@ describe('KeymapUseCase', () => { before(() => { sut = new KeymapUseCase( - new KeymapRepositoryImpl(), - new MockSettingRepository(settings), - new MockAddonEnabledRepository(false), - new MockAddressRepository(new URL('https://example.com')), + new KeymapRepositoryImpl(), + new MockSettingRepository(settings), + new MockAddonEnabledRepository(false), + new MockAddressRepository(new URL("https://example.com")) ); }); - it('returns only ADDON_ENABLE and ADDON_TOGGLE_ENABLED operation', () => { - expect(sut.nextOps(Key.fromMapKey('k'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('a'))).to.deep.equal({ repeat: 1, op: {type: 'addon.enable'}}); - expect(sut.nextOps(Key.fromMapKey('b'))).to.deep.equal({ repeat: 1, op: {type: 'addon.toggle.enabled'}}); + it("returns only ADDON_ENABLE and ADDON_TOGGLE_ENABLED operation", () => { + expect(sut.nextOps(Key.fromMapKey("k"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("a"))).to.deep.equal({ + repeat: 1, + op: { type: "addon.enable" }, + }); + expect(sut.nextOps(Key.fromMapKey("b"))).to.deep.equal({ + repeat: 1, + op: { type: "addon.toggle.enabled" }, + }); }); }); - context('when the site matches to the partial blacklist', () => { + context("when the site matches to the partial blacklist", () => { const settings = Settings.fromJSON({ keymaps: { - k: {type: 'scroll.vertically', count: -1}, - j: {type: 'scroll.vertically', count: 1}, - gg: {type: "scroll.top"}, - G: {type: "scroll.bottom"}, + k: { type: "scroll.vertically", count: -1 }, + j: { type: "scroll.vertically", count: 1 }, + gg: { type: "scroll.top" }, + G: { type: "scroll.bottom" }, }, blacklist: [ - { url: "example.com", keys: ['g'] }, - { url: "example.org", keys: ['<S-G>'] } + { url: "example.com", keys: ["g"] }, + { url: "example.org", keys: ["<S-G>"] }, ], }); - it('blocks keys in the partial blacklist', () => { + it("blocks keys in the partial blacklist", () => { let sut = new KeymapUseCase( - new KeymapRepositoryImpl(), - new MockSettingRepository(settings), - new MockAddonEnabledRepository(true), - new MockAddressRepository(new URL('https://example.com')), + new KeymapRepositoryImpl(), + new MockSettingRepository(settings), + new MockAddonEnabledRepository(true), + new MockAddressRepository(new URL("https://example.com")) ); - expect(sut.nextOps(Key.fromMapKey('k'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.vertically', count: -1}}); - expect(sut.nextOps(Key.fromMapKey('j'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.vertically', count: 1}}); - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('G'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.bottom'}}); + expect(sut.nextOps(Key.fromMapKey("k"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.vertically", count: -1 }, + }); + expect(sut.nextOps(Key.fromMapKey("j"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.vertically", count: 1 }, + }); + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("G"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.bottom" }, + }); sut = new KeymapUseCase( - new KeymapRepositoryImpl(), - new MockSettingRepository(settings), - new MockAddonEnabledRepository(true), - new MockAddressRepository(new URL('https://example.org')), + new KeymapRepositoryImpl(), + new MockSettingRepository(settings), + new MockAddonEnabledRepository(true), + new MockAddressRepository(new URL("https://example.org")) ); - expect(sut.nextOps(Key.fromMapKey('g'))).to.be.null; - expect(sut.nextOps(Key.fromMapKey('g'))).to.deep.equal({ repeat: 1, op: {type: 'scroll.top'}}); - expect(sut.nextOps(Key.fromMapKey('G'))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.be.null; + expect(sut.nextOps(Key.fromMapKey("g"))).to.deep.equal({ + repeat: 1, + op: { type: "scroll.top" }, + }); + expect(sut.nextOps(Key.fromMapKey("G"))).to.be.null; }); }); }); diff --git a/test/content/usecases/MarkUseCase.test.ts b/test/content/usecases/MarkUseCase.test.ts index 494497a..df3f7bf 100644 --- a/test/content/usecases/MarkUseCase.test.ts +++ b/test/content/usecases/MarkUseCase.test.ts @@ -1,14 +1,14 @@ -import MarkRepository from '../../../src/content/repositories/MarkRepository'; -import { SettingRepositoryImpl } from '../../../src/content/repositories/SettingRepository'; -import MarkUseCase from '../../../src/content/usecases/MarkUseCase'; -import MarkClient from '../../../src/content/client/MarkClient'; -import MockConsoleClient from '../mock/MockConsoleClient'; -import MockScrollPresenter from '../mock/MockScrollPresenter'; -import Mark from '../../../src/content/domains/Mark'; -import { expect } from 'chai'; +import MarkRepository from "../../../src/content/repositories/MarkRepository"; +import { SettingRepositoryImpl } from "../../../src/content/repositories/SettingRepository"; +import MarkUseCase from "../../../src/content/usecases/MarkUseCase"; +import MarkClient from "../../../src/content/client/MarkClient"; +import MockConsoleClient from "../mock/MockConsoleClient"; +import MockScrollPresenter from "../mock/MockScrollPresenter"; +import Mark from "../../../src/content/domains/Mark"; +import { expect } from "chai"; class MockMarkRepository implements MarkRepository { - private current: {[key: string]: Mark}; + private current: { [key: string]: Mark }; constructor() { this.current = {}; @@ -24,12 +24,12 @@ class MockMarkRepository implements MarkRepository { } class MockMarkClient implements MarkClient { - public marks: {[key: string]: Mark}; + public marks: { [key: string]: Mark }; public last: string; constructor() { this.marks = {}; - this.last = ''; + this.last = ""; } setGloablMark(key: string, mark: Mark): Promise<void> { @@ -38,12 +38,12 @@ class MockMarkClient implements MarkClient { } jumpGlobalMark(key: string): Promise<void> { - this.last = key + this.last = key; return Promise.resolve(); } } -describe('MarkUseCase', () => { +describe("MarkUseCase", () => { let repository: MockMarkRepository; let client: MockMarkClient; let consoleClient: MockConsoleClient; @@ -60,53 +60,56 @@ describe('MarkUseCase', () => { client, repository, new SettingRepositoryImpl(), - consoleClient, + consoleClient ); }); - describe('#set', () => { - it('sets local mark', async() => { + describe("#set", () => { + it("sets local mark", async () => { scrollPresenter.scrollTo(10, 20, false); - await sut.set('x'); + await sut.set("x"); - expect(repository.get('x')).to.deep.equals({ x: 10, y: 20 }); + expect(repository.get("x")).to.deep.equals({ x: 10, y: 20 }); expect(consoleClient.text).to.equal("Set local mark to 'x'"); }); - it('sets global mark', async() => { + it("sets global mark", async () => { scrollPresenter.scrollTo(30, 40, false); - await sut.set('Z'); + await sut.set("Z"); - expect(client.marks['Z']).to.deep.equals({ x: 30, y: 40 }); + expect(client.marks["Z"]).to.deep.equals({ x: 30, y: 40 }); expect(consoleClient.text).to.equal("Set global mark to 'Z'"); }); }); - describe('#jump', () => { - it('jumps to local mark', async() => { - repository.set('x', { x: 20, y: 40 }); + describe("#jump", () => { + it("jumps to local mark", async () => { + repository.set("x", { x: 20, y: 40 }); - await sut.jump('x'); + await sut.jump("x"); expect(scrollPresenter.getScroll()).to.deep.equals({ x: 20, y: 40 }); }); - it('throws an error when no local marks', () => { - return sut.jump('a').then(() => { - throw new Error('error'); - }).catch((e) => { - expect(e).to.be.instanceof(Error); - }) - }) + it("throws an error when no local marks", () => { + return sut + .jump("a") + .then(() => { + throw new Error("error"); + }) + .catch((e) => { + expect(e).to.be.instanceof(Error); + }); + }); - it('jumps to global mark', async() => { - client.marks['Z'] = { x: 20, y: 0 }; + it("jumps to global mark", async () => { + client.marks["Z"] = { x: 20, y: 0 }; - await sut.jump('Z'); + await sut.jump("Z"); - expect(client.last).to.equal('Z') + expect(client.last).to.equal("Z"); }); }); }); diff --git a/test/content/usecases/SettingUseCaase.test.ts b/test/content/usecases/SettingUseCaase.test.ts index cf14e6e..1cc1e8a 100644 --- a/test/content/usecases/SettingUseCaase.test.ts +++ b/test/content/usecases/SettingUseCaase.test.ts @@ -1,8 +1,10 @@ -import SettingRepository from '../../../src/content/repositories/SettingRepository'; -import SettingClient from '../../../src/content/client/SettingClient'; -import SettingUseCase from '../../../src/content/usecases/SettingUseCase'; -import Settings, { DefaultSetting } from '../../../src/shared/settings/Settings'; -import { expect } from 'chai'; +import SettingRepository from "../../../src/content/repositories/SettingRepository"; +import SettingClient from "../../../src/content/client/SettingClient"; +import SettingUseCase from "../../../src/content/usecases/SettingUseCase"; +import Settings, { + DefaultSetting, +} from "../../../src/shared/settings/Settings"; +import { expect } from "chai"; class MockSettingRepository implements SettingRepository { private current: Settings; @@ -12,7 +14,7 @@ class MockSettingRepository implements SettingRepository { } set(settings: Settings): void { - this.current= settings; + this.current = settings; } get(): Settings { @@ -32,40 +34,40 @@ class MockSettingClient implements SettingClient { } } -describe('AddonEnabledUseCase', () => { +describe("AddonEnabledUseCase", () => { let repository: MockSettingRepository; let client: MockSettingClient; let sut: SettingUseCase; beforeEach(() => { - const testSettings = { + const testSettings = Settings.fromJSON({ keymaps: {}, search: { - default: 'google', + default: "google", engines: { - google: 'https://google.com/?q={}', - } + google: "https://google.com/?q={}", + }, }, properties: { - hintchars: 'abcd1234', + hintchars: "abcd1234", smoothscroll: false, - complete: 'sbh', + complete: "sbh", }, blacklist: [], - }; + }); repository = new MockSettingRepository(); client = new MockSettingClient(testSettings); sut = new SettingUseCase(repository, client); }); - describe('#reload', () => { - it('loads settings and store to repository', async() => { + describe("#reload", () => { + it("loads settings and store to repository", async () => { const settings = await sut.reload(); - expect(settings.properties.hintchars).to.equal('abcd1234'); + expect(settings.properties.hintchars).to.equal("abcd1234"); const saved = repository.get(); - expect(saved.properties.hintchars).to.equal('abcd1234'); + expect(saved.properties.hintchars).to.equal("abcd1234"); }); }); }); diff --git a/test/main.ts b/test/main.ts index c985546..fded23a 100644 --- a/test/main.ts +++ b/test/main.ts @@ -1,6 +1 @@ -import 'reflect-metadata'; -import { expect } from 'chai'; -import browserFake from 'webextensions-api-fake'; - -global.expect = expect; -global.browser = browserFake(); +import "reflect-metadata"; diff --git a/test/settings/components/form/BlacklistForm.test.tsx b/test/settings/components/form/BlacklistForm.test.tsx index 6c329ff..e34802a 100644 --- a/test/settings/components/form/BlacklistForm.test.tsx +++ b/test/settings/components/form/BlacklistForm.test.tsx @@ -1,94 +1,120 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import { expect } from 'chai' +import React from "react"; +import ReactDOM from "react-dom"; +import ReactTestRenderer from "react-test-renderer"; +import ReactTestUtils from "react-dom/test-utils"; +import { expect } from "chai"; -import BlacklistForm from '../../../../src/settings/components/form/BlacklistForm' -import Blacklist from '../../../../src/shared/settings/Blacklist'; +import BlacklistForm from "../../../../src/settings/components/form/BlacklistForm"; +import Blacklist from "../../../../src/shared/settings/Blacklist"; +import AddButton from "../../../../src/settings/components/ui/AddButton"; describe("settings/form/BlacklistForm", () => { - describe('render', () => { - it('renders BlacklistForm', () => { + describe("render", () => { + it("renders BlacklistForm", () => { const root = ReactTestRenderer.create( - <BlacklistForm value={Blacklist.fromJSON(['*.slack.com', 'www.google.com/maps'])} />, + <BlacklistForm + value={Blacklist.fromJSON(["*.slack.com", "www.google.com/maps"])} + /> ).root; - const children = root.children[0].children; - expect(children).to.have.lengthOf(3); - expect(children[0].children[0].props.value).to.equal('*.slack.com'); - expect(children[1].children[0].props.value).to.equal('www.google.com/maps'); - expect(children[2].props.name).to.equal('add'); + const rows = root.findAllByProps({ + className: "form-blacklist-form-row", + }); + expect(rows).to.have.lengthOf(2); + expect( + rows[0].findByProps({ className: "column-url" }).props.value + ).to.equal("*.slack.com"); + expect( + rows[1].findByProps({ className: "column-url" }).props.value + ).to.equal("www.google.com/maps"); + + expect(() => root.findByType(AddButton)).not.throw(); }); - it('renders blank value', () => { + it("renders blank value", () => { const root = ReactTestRenderer.create(<BlacklistForm />).root; - const children = root.children[0].children; - expect(children).to.have.lengthOf(1); - expect(children[0].props.name).to.equal('add'); + const rows = root.findAllByProps({ + className: "form-blacklist-form-row", + }); + expect(rows).to.be.empty; }); }); - describe('onChange', () => { - let container; + describe("onChange", () => { + let container: HTMLDivElement; beforeEach(() => { - container = document.createElement('div'); + container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); - container = null; }); - it('invokes onChange event on edit', (done) => { + it("invokes onChange event on edit", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<BlacklistForm - value={Blacklist.fromJSON(['*.slack.com', 'www.google.com/maps*'])} - onChange={value => { - const urls = value.items.map(item => item.pattern); - expect(urls).to.have.members(['gitter.im', 'www.google.com/maps*']); - done(); - }} - />, container) + ReactDOM.render( + <BlacklistForm + value={Blacklist.fromJSON(["*.slack.com", "www.google.com/maps*"])} + onChange={(value) => { + const urls = value.items.map((item) => item.pattern); + expect(urls).to.have.members([ + "gitter.im", + "www.google.com/maps*", + ]); + done(); + }} + />, + container + ); }); - const input = document.querySelectorAll('input[type=text]')[0]; - input.value = 'gitter.im'; + const input = document.querySelectorAll( + "input[type=text]" + )[0] as HTMLInputElement; + input.value = "gitter.im"; ReactTestUtils.Simulate.change(input); }); - it('invokes onChange event on delete', (done) => { + it("invokes onChange event on delete", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<BlacklistForm - value={Blacklist.fromJSON(['*.slack.com', 'www.google.com/maps*'])} - onChange={value => { - const urls = value.items.map(item => item.pattern); - expect(urls).to.have.members(['www.google.com/maps*']); - done(); - }} - />, container) + ReactDOM.render( + <BlacklistForm + value={Blacklist.fromJSON(["*.slack.com", "www.google.com/maps*"])} + onChange={(value) => { + const urls = value.items.map((item) => item.pattern); + expect(urls).to.have.members(["www.google.com/maps*"]); + done(); + }} + />, + container + ); }); - const button = document.querySelectorAll('input[type=button]')[0]; + const button = document.querySelectorAll("input[type=button]")[0]; ReactTestUtils.Simulate.click(button); }); - it('invokes onChange event on add', (done) => { + it("invokes onChange event on add", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<BlacklistForm - value={Blacklist.fromJSON(['*.slack.com'])} - onChange={value => { - const urls = value.items.map(item => item.pattern); - expect(urls).to.have.members(['*.slack.com', '']); - done(); - }} - />, container); + ReactDOM.render( + <BlacklistForm + value={Blacklist.fromJSON(["*.slack.com"])} + onChange={(value) => { + const urls = value.items.map((item) => item.pattern); + expect(urls).to.have.members(["*.slack.com", ""]); + done(); + }} + />, + container + ); }); - const button = document.querySelector('input[type=button].ui-add-button'); + const button = document.querySelector( + "input[type=button].ui-add-button" + ) as HTMLButtonElement; ReactTestUtils.Simulate.click(button); }); }); diff --git a/test/settings/components/form/KeymapsForm.test.tsx b/test/settings/components/form/KeymapsForm.test.tsx index ccc772c..1cec889 100644 --- a/test/settings/components/form/KeymapsForm.test.tsx +++ b/test/settings/components/form/KeymapsForm.test.tsx @@ -1,27 +1,31 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import KeymapsForm from '../../../../src/settings/components/form/KeymapsForm' -import { FormKeymaps } from 'shared/SettingData'; -import { expect } from 'chai'; +import React from "react"; +import ReactDOM from "react-dom"; +import ReactTestRenderer from "react-test-renderer"; +import ReactTestUtils from "react-dom/test-utils"; +import KeymapsForm from "../../../../src/settings/components/form/KeymapsForm"; +import { FormKeymaps } from "../../../../src/shared/SettingData"; +import { expect } from "chai"; describe("settings/form/KeymapsForm", () => { - describe('render', () => { - it('renders keymap fields', () => { - const root = ReactTestRenderer.create(<KeymapsForm value={FormKeymaps.fromJSON({ - 'scroll.vertically?{"count":1}': 'j', - 'scroll.vertically?{"count":-1}': 'k', - })} />).root + describe("render", () => { + it("renders keymap fields", () => { + const root = ReactTestRenderer.create( + <KeymapsForm + value={FormKeymaps.fromJSON({ + 'scroll.vertically?{"count":1}': "j", + 'scroll.vertically?{"count":-1}': "k", + })} + /> + ).root; const inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); const inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); - expect(inputj.props.value).to.equal('j'); - expect(inputk.props.value).to.equal('k'); + expect(inputj.props.value).to.equal("j"); + expect(inputk.props.value).to.equal("k"); }); - it('renders blank value', () => { + it("renders blank value", () => { const root = ReactTestRenderer.create(<KeymapsForm />).root; const inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); @@ -32,34 +36,41 @@ describe("settings/form/KeymapsForm", () => { }); }); - describe('onChange event', () => { - let container; + describe("onChange event", () => { + let container: HTMLDivElement; beforeEach(() => { - container = document.createElement('div'); + container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); - container = null; }); - it('invokes onChange event on edit', (done) => { + it("invokes onChange event on edit", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<KeymapsForm - value={FormKeymaps.fromJSON({ - 'scroll.vertically?{"count":1}': 'j', - 'scroll.vertically?{"count":-1}': 'k', - })} - onChange={value => { - expect(value.toJSON()['scroll.vertically?{"count":1}']).to.equal('jjj'); - done(); - }} />, container); + ReactDOM.render( + <KeymapsForm + value={FormKeymaps.fromJSON({ + 'scroll.vertically?{"count":1}': "j", + 'scroll.vertically?{"count":-1}': "k", + })} + onChange={(value) => { + expect(value.toJSON()['scroll.vertically?{"count":1}']).to.equal( + "jjj" + ); + done(); + }} + />, + container + ); }); - const input = document.getElementById('scroll.vertically?{"count":1}'); - input.value = 'jjj'; + const input = document.getElementById( + 'scroll.vertically?{"count":1}' + ) as HTMLInputElement; + input.value = "jjj"; ReactTestUtils.Simulate.change(input); }); }); diff --git a/test/settings/components/form/PropertiesForm.test.tsx b/test/settings/components/form/PropertiesForm.test.tsx index 4a0e25a..acf02b8 100644 --- a/test/settings/components/form/PropertiesForm.test.tsx +++ b/test/settings/components/form/PropertiesForm.test.tsx @@ -1,102 +1,117 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import PropertiesForm from 'settings/components/form/PropertiesForm' +import React from "react"; +import ReactDOM from "react-dom"; +import ReactTestRenderer from "react-test-renderer"; +import ReactTestUtils from "react-dom/test-utils"; +import PropertiesForm from "../../../../src/settings/components/form/PropertiesForm"; +import { expect } from "chai"; describe("settings/form/PropertiesForm", () => { - describe('render', () => { - it('renders PropertiesForm', () => { + describe("render", () => { + it("renders PropertiesForm", () => { const types = { - mystr: 'string', - mynum: 'number', - mybool: 'boolean', - empty: 'string', - } + mystr: "string", + mynum: "number", + mybool: "boolean", + empty: "string", + }; const values = { - mystr: 'abc', + mystr: "abc", mynum: 123, mybool: true, }; const root = ReactTestRenderer.create( - <PropertiesForm types={types} value={values} />, - ).root + <PropertiesForm types={types} value={values} /> + ).root; - let input = root.findByProps({ name: 'mystr' }); - expect(input.props.type).to.equals('text'); - expect(input.props.value).to.equal('abc'); + let input = root.findByProps({ name: "mystr" }); + expect(input.props.type).to.equals("text"); + expect(input.props.value).to.equal("abc"); - input = root.findByProps({ name: 'mynum' }); - expect(input.props.type).to.equals('number'); + input = root.findByProps({ name: "mynum" }); + expect(input.props.type).to.equals("number"); expect(input.props.value).to.equal(123); - input = root.findByProps({ name: 'mybool' }); - expect(input.props.type).to.equals('checkbox'); + input = root.findByProps({ name: "mybool" }); + expect(input.props.type).to.equals("checkbox"); expect(input.props.value).to.equal(true); }); }); - describe('onChange', () => { - let container; + describe("onChange", () => { + let container: HTMLDivElement; beforeEach(() => { - container = document.createElement('div'); + container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); - container = null; }); - it('invokes onChange event on text changed', (done) => { + it("invokes onChange event on text changed", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<PropertiesForm - types={{ 'myvalue': 'string' }} - value={{ 'myvalue': 'abc' }} - onChange={value => { - expect(value).to.have.property('myvalue', 'abcd'); - done(); - }} - />, container); + ReactDOM.render( + <PropertiesForm + types={{ myvalue: "string" }} + value={{ myvalue: "abc" }} + onChange={(value) => { + expect(value).to.have.property("myvalue", "abcd"); + done(); + }} + />, + container + ); }); - const input = document.querySelector('input[name=myvalue]'); - input.value = 'abcd' + const input = document.querySelector( + "input[name=myvalue]" + ) as HTMLInputElement; + input.value = "abcd"; ReactTestUtils.Simulate.change(input); }); - it('invokes onChange event on number changeed', (done) => { + it("invokes onChange event on number changeed", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<PropertiesForm - types={{ 'myvalue': 'number' }} - value={{ '': 123 }} - onChange={value => { - expect(value).to.have.property('myvalue', 1234); - done(); - }} - />, container); + ReactDOM.render( + <PropertiesForm + types={{ myvalue: "number" }} + value={{ "": 123 }} + onChange={(value) => { + expect(value).to.have.property("myvalue", 1234); + done(); + }} + />, + container + ); }); - const input = document.querySelector('input[name=myvalue]'); - input.value = '1234' + const input = document.querySelector( + "input[name=myvalue]" + ) as HTMLInputElement; + input.value = "1234"; ReactTestUtils.Simulate.change(input); }); - it('invokes onChange event on checkbox changed', (done) => { + it("invokes onChange event on checkbox changed", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<PropertiesForm - types={{ 'myvalue': 'boolean' }} - value={{ 'myvalue': false }} - onChange={value => { - expect(value).to.have.property('myvalue', true); - done(); - }} - />, container); + ReactDOM.render( + <PropertiesForm + types={{ myvalue: "boolean" }} + value={{ myvalue: false }} + onChange={(value) => { + expect(value).to.have.property("myvalue", true); + done(); + }} + />, + container + ); }); - const input = document.querySelector('input[name=myvalue]'); + const input = document.querySelector( + "input[name=myvalue]" + ) as HTMLInputElement; input.checked = true; ReactTestUtils.Simulate.change(input); }); diff --git a/test/settings/components/form/SearchEngineForm.test.tsx b/test/settings/components/form/SearchEngineForm.test.tsx index b918203..5f835cc 100644 --- a/test/settings/components/form/SearchEngineForm.test.tsx +++ b/test/settings/components/form/SearchEngineForm.test.tsx @@ -1,109 +1,146 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestRenderer from 'react-test-renderer'; -import ReactTestUtils from 'react-dom/test-utils'; -import SearchForm from 'settings/components/form/SearchForm' -import { FormSearch } from 'shared/SettingData'; +import React from "react"; +import ReactDOM from "react-dom"; +import ReactTestRenderer from "react-test-renderer"; +import ReactTestUtils from "react-dom/test-utils"; +import SearchForm from "../../../../src/settings/components/form/SearchForm"; +import { FormSearch } from "../../../../src/shared/SettingData"; +import { expect } from "chai"; describe("settings/form/SearchForm", () => { - describe('render', () => { - it('renders SearchForm', () => { - const root = ReactTestRenderer.create(<SearchForm value={FormSearch.fromJSON({ - default: 'google', - engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']], - })} />).root; + describe("render", () => { + it("renders SearchForm", () => { + const root = ReactTestRenderer.create( + <SearchForm + value={FormSearch.fromJSON({ + default: "google", + engines: [ + ["google", "google.com"], + ["yahoo", "yahoo.com"], + ], + })} + /> + ).root; - const names = root.findAllByProps({ name: 'name' }); + const names = root.findAllByProps({ name: "name" }); expect(names).to.have.lengthOf(2); - expect(names[0].props.value).to.equal('google'); - expect(names[1].props.value).to.equal('yahoo'); + expect(names[0].props.value).to.equal("google"); + expect(names[1].props.value).to.equal("yahoo"); - const urls = root.findAllByProps({ name: 'url' }); + const urls = root.findAllByProps({ name: "url" }); expect(urls).to.have.lengthOf(2); - expect(urls[0].props.value).to.equal('google.com'); - expect(urls[1].props.value).to.equal('yahoo.com'); + expect(urls[0].props.value).to.equal("google.com"); + expect(urls[1].props.value).to.equal("yahoo.com"); }); }); - describe('onChange event', () => { - let container; + describe("onChange event", () => { + let container: HTMLDivElement; beforeEach(() => { - container = document.createElement('div'); + container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); - container = null; }); - it('invokes onChange event on edit', (done) => { + it("invokes onChange event on edit", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<SearchForm - value={FormSearch.fromJSON({ - default: 'google', - engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']] - })} - onChange={value => { - const json = value.toJSON(); - expect(json.default).to.equal('louvre'); - expect(json.engines).to.have.lengthOf(2) - expect(json.engines).to.have.deep.members( - [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] - ); - done(); - }} />, container); + ReactDOM.render( + <SearchForm + value={FormSearch.fromJSON({ + default: "google", + engines: [ + ["google", "google.com"], + ["yahoo", "yahoo.com"], + ], + })} + onChange={(value) => { + const json = value.toJSON(); + expect(json.default).to.equal("louvre"); + expect(json.engines).to.have.lengthOf(2); + expect(json.engines).to.have.deep.members([ + ["louvre", "google.com"], + ["yahoo", "yahoo.com"], + ]); + done(); + }} + />, + container + ); }); - const radio = document.querySelectorAll('input[type=radio]'); + const radio = document.querySelector( + "input[type=radio]" + ) as HTMLInputElement; radio.checked = true; - const name = document.querySelector('input[name=name]'); - name.value = 'louvre'; + const name = document.querySelector( + "input[name=name]" + ) as HTMLInputElement; + name.value = "louvre"; ReactTestUtils.Simulate.change(name); }); - it('invokes onChange event on delete', (done) => { + it("invokes onChange event on delete", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<SearchForm value={FormSearch.fromJSON({ - default: 'yahoo', - engines: [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] - })} - onChange={value => { - const json = value.toJSON(); - expect(json.default).to.equal('yahoo'); - expect(json.engines).to.have.lengthOf(1) - expect(json.engines).to.have.deep.members( - [['yahoo', 'yahoo.com']] - ); - done(); - }} />, container); + ReactDOM.render( + <SearchForm + value={FormSearch.fromJSON({ + default: "yahoo", + engines: [ + ["louvre", "google.com"], + ["yahoo", "yahoo.com"], + ], + })} + onChange={(value) => { + const json = value.toJSON(); + expect(json.default).to.equal("yahoo"); + expect(json.engines).to.have.lengthOf(1); + expect(json.engines).to.have.deep.members([ + ["yahoo", "yahoo.com"], + ]); + done(); + }} + />, + container + ); }); - const button = document.querySelector('input[type=button]'); + const button = document.querySelector( + "input[type=button]" + ) as HTMLInputElement; ReactTestUtils.Simulate.click(button); }); - it('invokes onChange event on add', (done) => { + it("invokes onChange event on add", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<SearchForm value={FormSearch.fromJSON({ - default: 'yahoo', - engines: [['google', 'google.com']] - })} - onChange={value => { - const json = value.toJSON(); - expect(json.default).to.equal('yahoo'); - expect(json.engines).to.have.lengthOf(2) - expect(json.engines).to.have.deep.members( - [['google', 'google.com'], ['', '']], - ); - done(); - }} />, container); + ReactDOM.render( + <SearchForm + value={FormSearch.fromJSON({ + default: "yahoo", + engines: [["google", "google.com"]], + })} + onChange={(value) => { + const json = value.toJSON(); + expect(json.default).to.equal("yahoo"); + expect(json.engines).to.have.lengthOf(2); + expect(json.engines).to.have.deep.members([ + ["google", "google.com"], + ["", ""], + ]); + done(); + }} + />, + container + ); }); - const button = document.querySelector('input[type=button].ui-add-button'); + const button = document.querySelector( + "input[type=button].ui-add-button" + ) as HTMLInputElement; ReactTestUtils.Simulate.click(button); }); }); diff --git a/test/settings/components/ui/input.test.tsx b/test/settings/components/ui/input.test.tsx index a3e7ff4..191bfed 100644 --- a/test/settings/components/ui/input.test.tsx +++ b/test/settings/components/ui/input.test.tsx @@ -1,110 +1,145 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestUtils from 'react-dom/test-utils'; -import Input from 'settings/components/ui/Input' +import React from "react"; +import ReactDOM from "react-dom"; +import ReactTestUtils from "react-dom/test-utils"; +import Input from "../../../../src/settings/components/ui/Input"; +import { expect } from "chai"; describe("settings/ui/Input", () => { - let container; + let container: HTMLDivElement; beforeEach(() => { - container = document.createElement('div'); + container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); - container = null; }); context("type=text", () => { - it('renders text input', () => { + it("renders text input", () => { ReactTestUtils.act(() => { ReactDOM.render( - <Input type='text' name='myname' label='myfield' value='myvalue'/>, - container); + <Input type="text" name="myname" label="myfield" value="myvalue" />, + container + ); }); - const label = document.querySelector('label'); - const input = document.querySelector('input'); - expect(label.textContent).to.contain('myfield'); - expect(input.type).to.contain('text'); - expect(input.name).to.contain('myname'); - expect(input.value).to.contain('myvalue'); + const label = document.querySelector("label")!!; + const input = document.querySelector("input")!!; + expect(label.textContent).to.contain("myfield"); + expect(input.type).to.contain("text"); + expect(input.name).to.contain("myname"); + expect(input.value).to.contain("myvalue"); }); - it('invoke onChange', (done) => { + it("invoke onChange", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<Input type='text' name='myname' label='myfield' value='myvalue' onChange={(e) => { - expect(e.target.value).to.equal('newvalue'); - done(); - }}/>, container); + ReactDOM.render( + <Input + type="text" + name="myname" + label="myfield" + value="myvalue" + onChange={(e) => { + expect((e.target as HTMLInputElement).value).to.equal("newvalue"); + done(); + }} + />, + container + ); }); - const input = document.querySelector('input'); - input.value = 'newvalue'; + const input = document.querySelector("input")!!; + input.value = "newvalue"; ReactTestUtils.Simulate.change(input); }); }); context("type=radio", () => { - it('renders radio button', () => { + it("renders radio button", () => { ReactTestUtils.act(() => { ReactDOM.render( - <Input type='radio' name='myname' label='myfield' value='myvalue'/>, - container); + <Input type="radio" name="myname" label="myfield" value="myvalue" />, + container + ); }); - const label = document.querySelector('label'); - const input = document.querySelector('input'); - expect(label.textContent).to.contain('myfield'); - expect(input.type).to.contain('radio'); - expect(input.name).to.contain('myname'); - expect(input.value).to.contain('myvalue'); + const label = document.querySelector("label")!!; + const input = document.querySelector("input")!!; + expect(label.textContent).to.contain("myfield"); + expect(input.type).to.contain("radio"); + expect(input.name).to.contain("myname"); + expect(input.value).to.contain("myvalue"); }); - it('invoke onChange', (done) => { + it("invoke onChange", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<Input type='text' name='radio' label='myfield' value='myvalue' onChange={(e) => { - expect(e.target.checked).to.be.true; - done(); - }}/>, - container); + ReactDOM.render( + <Input + type="text" + name="radio" + label="myfield" + value="myvalue" + onChange={(e) => { + expect((e.target as HTMLInputElement).checked).to.be.true; + done(); + }} + />, + container + ); }); - const input = document.querySelector('input'); + const input = document.querySelector("input") as HTMLInputElement; input.checked = true; ReactTestUtils.Simulate.change(input); }); }); context("type=textarea", () => { - it('renders textarea button', () => { + it("renders textarea button", () => { ReactTestUtils.act(() => { ReactDOM.render( - <Input type='textarea' name='myname' label='myfield' value='myvalue' error='myerror' />, - container); + <Input + type="textarea" + name="myname" + label="myfield" + value="myvalue" + error="myerror" + />, + container + ); }); - const label = document.querySelector('label'); - const textarea = document.querySelector('textarea'); - const error = document.querySelector('.settings-ui-input-error'); - expect(label.textContent).to.contain('myfield'); - expect(textarea.nodeName).to.contain('TEXTAREA'); - expect(textarea.name).to.contain('myname'); - expect(textarea.value).to.contain('myvalue'); - expect(error.textContent).to.contain('myerror'); + const label = document.querySelector("label")!!; + const textarea = document.querySelector("textarea")!!; + const error = document.querySelector(".settings-ui-input-error")!!; + expect(label.textContent).to.contain("myfield"); + expect(textarea.nodeName).to.contain("TEXTAREA"); + expect(textarea.name).to.contain("myname"); + expect(textarea.value).to.contain("myvalue"); + expect(error.textContent).to.contain("myerror"); }); - it('invoke onChange', (done) => { + it("invoke onChange", (done) => { ReactTestUtils.act(() => { - ReactDOM.render(<Input type='textarea' name='myname' label='myfield' value='myvalue' onChange={(e) => { - expect(e.target.value).to.equal('newvalue'); - done(); - }}/>, container); + ReactDOM.render( + <Input + type="textarea" + name="myname" + label="myfield" + value="myvalue" + onChange={(e) => { + expect((e.target as HTMLInputElement).value).to.equal("newvalue"); + done(); + }} + />, + container + ); }); - const input = document.querySelector('textarea'); - input.value = 'newvalue' + const input = document.querySelector("textarea")!!; + input.value = "newvalue"; ReactTestUtils.Simulate.change(input); }); }); diff --git a/test/settings/reducers/setting.test.ts b/test/settings/reducers/setting.test.ts index 60df061..99c4c80 100644 --- a/test/settings/reducers/setting.test.ts +++ b/test/settings/reducers/setting.test.ts @@ -1,54 +1,61 @@ -import * as actions from 'settings/actions'; -import settingReducer from 'settings/reducers/setting'; +import * as actions from "../../../src/settings/actions"; +import settingReducer from "../../../src/settings/reducers/setting"; +import { expect } from "chai"; +import { + FormSettings, + JSONTextSettings, + SettingSource, +} from "../../../src/shared/SettingData"; +import { DefaultSetting } from "../../../src/shared/settings/Settings"; describe("settings setting reducer", () => { - it('return the initial state', () => { - const state = settingReducer(undefined, {}); - expect(state).to.have.deep.property('source', 'json'); - expect(state).to.have.deep.property('error', ''); + it("return the initial state", () => { + const state = settingReducer(undefined, {} as any); + expect(state).to.have.deep.property("source", "json"); + expect(state).to.have.deep.property("error", ""); }); - it('return next state for SETTING_SET_SETTINGS', () => { - const action = { + it("return next state for SETTING_SET_SETTINGS", () => { + const action: actions.SettingAction = { type: actions.SETTING_SET_SETTINGS, - source: 'json', - json: '{ "key": "value" }', - form: {}, + source: SettingSource.JSON, + json: JSONTextSettings.fromText('{ "key": "value" }'), + form: FormSettings.fromSettings(DefaultSetting), }; const state = settingReducer(undefined, action); - expect(state).to.have.deep.property('source', 'json'); - expect(state).to.have.deep.property('json', '{ "key": "value" }'); - expect(state).to.have.deep.property('form', {}); + expect(state.source).to.equal("json"); + expect(state.json!!.toJSONText()).to.equal('{ "key": "value" }'); + expect(state.form).to.deep.equal(action.form); }); - it('return next state for SETTING_SHOW_ERROR', () => { - const action = { + it("return next state for SETTING_SHOW_ERROR", () => { + const action: actions.SettingAction = { type: actions.SETTING_SHOW_ERROR, - error: 'bad value', - json: '{}', + error: "bad value", + json: JSONTextSettings.fromText("{}"), }; const state = settingReducer(undefined, action); - expect(state).to.have.deep.property('error', 'bad value'); - expect(state).to.have.deep.property('json', '{}'); + expect(state.error).to.equal("bad value"); + expect(state.json!!.toJSONText()).to.equal("{}"); }); - it('return next state for SETTING_SWITCH_TO_FORM', () => { - const action = { + it("return next state for SETTING_SWITCH_TO_FORM", () => { + const action: actions.SettingAction = { type: actions.SETTING_SWITCH_TO_FORM, - form: {}, + form: FormSettings.fromSettings(DefaultSetting), }; const state = settingReducer(undefined, action); - expect(state).to.have.deep.property('form', {}); - expect(state).to.have.deep.property('source', 'form'); + expect(state.form).to.deep.equal(action.form); + expect(state.source).to.equal("form"); }); - it('return next state for SETTING_SWITCH_TO_JSON', () => { - const action = { + it("return next state for SETTING_SWITCH_TO_JSON", () => { + const action: actions.SettingAction = { type: actions.SETTING_SWITCH_TO_JSON, - json: '{}', + json: JSONTextSettings.fromText("{}"), }; const state = settingReducer(undefined, action); - expect(state).to.have.deep.property('json', '{}'); - expect(state).to.have.deep.property('source', 'json'); + expect(state.json!!.toJSONText()).to.equal("{}"); + expect(state.source).to.equal(SettingSource.JSON); }); }); diff --git a/test/shared/SettingData.test.ts b/test/shared/SettingData.test.ts index 0632176..283daa5 100644 --- a/test/shared/SettingData.test.ts +++ b/test/shared/SettingData.test.ts @@ -1,46 +1,48 @@ import SettingData, { - FormKeymaps, JSONTextSettings, FormSettings, -} from '../../src/shared/SettingData'; -import Settings from '../../src/shared/settings/Settings'; -import { expect } from 'chai'; -import Keymaps from '../../src/shared/settings/Keymaps'; + FormKeymaps, + JSONTextSettings, + FormSettings, +} from "../../src/shared/SettingData"; +import Settings from "../../src/shared/settings/Settings"; +import { expect } from "chai"; +import Keymaps from "../../src/shared/settings/Keymaps"; -describe('shared/SettingData', () => { - describe('FormKeymaps', () => { - describe('#valueOF to #toKeymaps', () => { - it('parses form keymaps and convert to operations', () => { +describe("shared/SettingData", () => { + describe("FormKeymaps", () => { + describe("#valueOF to #toKeymaps", () => { + it("parses form keymaps and convert to operations", () => { const data = { - 'scroll.vertically?{"count":1}': 'j', - 'scroll.home': '0', + 'scroll.vertically?{"count":1}': "j", + "scroll.home": "0", }; const keymaps = FormKeymaps.fromJSON(data).toKeymaps().toJSON(); expect(keymaps).to.deep.equal({ - 'j': { type: 'scroll.vertically', count: 1 }, - '0': { type: 'scroll.home' }, + j: { type: "scroll.vertically", count: 1 }, + "0": { type: "scroll.home" }, }); }); }); - describe('#fromKeymaps to #toJSON', () => { - it('create from a Keymaps and create a JSON object', () => { + describe("#fromKeymaps to #toJSON", () => { + it("create from a Keymaps and create a JSON object", () => { const keymaps: Keymaps = Keymaps.fromJSON({ - 'j': { type: 'scroll.vertically', count: 1 }, - '0': { type: 'scroll.home' }, + j: { type: "scroll.vertically", count: 1 }, + "0": { type: "scroll.home" }, }); const form = FormKeymaps.fromKeymaps(keymaps).toJSON(); expect(form).to.deep.equal({ - 'scroll.vertically?{"count":1}': 'j', - 'scroll.home': '0', + 'scroll.vertically?{"count":1}': "j", + "scroll.home": "0", }); }); }); }); - describe('JSONSettings', () => { - describe('#valueOf to #toSettings', () => { - it('parse object and create a Settings', () => { + describe("JSONSettings", () => { + describe("#valueOf to #toSettings", () => { + it("parse object and create a Settings", () => { const o = `{ "keymaps": {}, "search": { @@ -62,8 +64,8 @@ describe('shared/SettingData', () => { }); }); - describe('#fromSettings to #toJSON', () => { - it('create from a Settings and create a JSON string', () => { + describe("#fromSettings to #toJSON", () => { + it("create from a Settings and create a JSON string", () => { const o = Settings.fromJSON({ keymaps: {}, search: { @@ -75,7 +77,7 @@ describe('shared/SettingData', () => { properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, blacklist: [], }); @@ -86,67 +88,65 @@ describe('shared/SettingData', () => { }); }); - describe('FormSettings', () => { - describe('#valueOf to #toSettings', () => { - it('parse object and create a Settings', () => { + describe("FormSettings", () => { + describe("#valueOf to #toSettings", () => { + it("parse object and create a Settings", () => { const data = { keymaps: { - 'scroll.vertically?{"count":1}': 'j', - 'scroll.home': '0', + 'scroll.vertically?{"count":1}': "j", + "scroll.home": "0", }, search: { default: "google", - engines: [ - ["google", "https://google.com/search?q={}"], - ] + engines: [["google", "https://google.com/search?q={}"]], }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, - blacklist: [] + blacklist: [], }; const settings = FormSettings.fromJSON(data).toSettings(); expect(settings.toJSON()).to.deep.equal({ keymaps: { - 'j': { type: 'scroll.vertically', count: 1 }, - '0': { type: 'scroll.home' }, + j: { type: "scroll.vertically", count: 1 }, + "0": { type: "scroll.home" }, }, search: { default: "google", engines: { - "google": "https://google.com/search?q={}" - } + google: "https://google.com/search?q={}", + }, }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, - blacklist: [] + blacklist: [], }); }); }); - describe('#fromSettings to #toJSON', () => { - it('create from a Settings and create a JSON string', () => { + describe("#fromSettings to #toJSON", () => { + it("create from a Settings and create a JSON string", () => { const data: Settings = Settings.fromJSON({ keymaps: { - 'j': { type: 'scroll.vertically', count: 1 }, - '0': { type: 'scroll.home' }, + j: { type: "scroll.vertically", count: 1 }, + "0": { type: "scroll.home" }, }, search: { default: "google", engines: { - "google": "https://google.com/search?q={}" - } + google: "https://google.com/search?q={}", + }, }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, blacklist: [], }); @@ -154,19 +154,17 @@ describe('shared/SettingData', () => { const json = FormSettings.fromSettings(data).toJSON(); expect(json).to.deep.equal({ keymaps: { - 'scroll.vertically?{"count":1}': 'j', - 'scroll.home': '0', + 'scroll.vertically?{"count":1}': "j", + "scroll.home": "0", }, search: { default: "google", - engines: [ - ["google", "https://google.com/search?q={}"], - ] + engines: [["google", "https://google.com/search?q={}"]], }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, blacklist: [], }); @@ -174,11 +172,11 @@ describe('shared/SettingData', () => { }); }); - describe('SettingData', () => { - describe('#valueOf to #toJSON', () => { - it('parse object from json source', () => { + describe("SettingData", () => { + describe("#valueOf to #toJSON", () => { + it("parse object from json source", () => { const data = { - source: 'json', + source: "json", json: `{ "keymaps": {}, "search": { @@ -197,54 +195,50 @@ describe('shared/SettingData', () => { }; const j = SettingData.fromJSON(data).toJSON(); - expect(j.source).to.equal('json'); - expect(j.json).to.be.a('string'); + expect(j.source).to.equal("json"); + expect(j.json).to.be.a("string"); }); - it('parse object from form source', () => { + it("parse object from form source", () => { const data = { - source: 'form', + source: "form", form: { keymaps: {}, search: { default: "yahoo", - engines: [ - ['yahoo', 'https://yahoo.com/search?q={}'], - ], + engines: [["yahoo", "https://yahoo.com/search?q={}"]], }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, blacklist: [], }, }; const j = SettingData.fromJSON(data).toJSON(); - expect(j.source).to.equal('form'); + expect(j.source).to.equal("form"); expect(j.form).to.deep.equal({ keymaps: {}, search: { default: "yahoo", - engines: [ - ['yahoo', 'https://yahoo.com/search?q={}'], - ], + engines: [["yahoo", "https://yahoo.com/search?q={}"]], }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, blacklist: [], }); }); }); - describe('#toSettings', () => { - it('parse object from json source', () => { + describe("#toSettings", () => { + it("parse object from json source", () => { const data = { - source: 'json', + source: "json", json: `{ "keymaps": {}, "search": { @@ -263,31 +257,29 @@ describe('shared/SettingData', () => { }; const settings = SettingData.fromJSON(data).toSettings(); - expect(settings.search.defaultEngine).to.equal('google'); + expect(settings.search.defaultEngine).to.equal("google"); }); - it('parse object from form source', () => { + it("parse object from form source", () => { const data = { - source: 'form', + source: "form", form: { keymaps: {}, search: { default: "yahoo", - engines: [ - ['yahoo', 'https://yahoo.com/search?q={}'], - ], + engines: [["yahoo", "https://yahoo.com/search?q={}"]], }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, blacklist: [], }, }; const settings = SettingData.fromJSON(data).toSettings(); - expect(settings.search.defaultEngine).to.equal('yahoo'); + expect(settings.search.defaultEngine).to.equal("yahoo"); }); }); }); diff --git a/test/shared/operations.test.ts b/test/shared/operations.test.ts index fbb6193..449b25e 100644 --- a/test/shared/operations.test.ts +++ b/test/shared/operations.test.ts @@ -1,41 +1,48 @@ -import * as operations from 'shared/operations'; +import * as operations from "../../src/shared/operations"; +import { expect } from "chai"; -describe('operations', () => { - describe('#valueOf', () => { - it('returns an Operation', () => { - const op: operations.Operation = operations.valueOf({ +describe("operations", () => { + describe("#valueOf", () => { + it("returns an Operation", () => { + const op = operations.valueOf({ type: operations.SCROLL_VERTICALLY, count: 10, - }); + }) as operations.ScrollVerticallyOperation; expect(op.type).to.equal(operations.SCROLL_VERTICALLY); expect(op.count).to.equal(10); }); - it('throws an Error on missing required parameter', () => { - expect(() => operations.valueOf({ - type: operations.SCROLL_VERTICALLY, - })).to.throw(TypeError); + it("throws an Error on missing required parameter", () => { + expect(() => + operations.valueOf({ + type: operations.SCROLL_VERTICALLY, + }) + ).to.throw(TypeError); }); - it('fills default valus of optional parameter', () => { - const op: operations.Operation = operations.valueOf({ + it("fills default valus of optional parameter", () => { + const op = operations.valueOf({ type: operations.COMMAND_SHOW_OPEN, - }); + }) as operations.CommandShowOpenOperation; - expect(op.type).to.equal(operations.COMMAND_SHOW_OPEN) + expect(op.type).to.equal(operations.COMMAND_SHOW_OPEN); expect(op.alter).to.be.false; }); - it('throws an Error on mismatch of parameter', () => { - expect(() => operations.valueOf({ - type: operations.SCROLL_VERTICALLY, - count: '10', - })).to.throw(TypeError); + it("throws an Error on mismatch of parameter", () => { + expect(() => + operations.valueOf({ + type: operations.SCROLL_VERTICALLY, + count: "10", + }) + ).to.throw(TypeError); - expect(() => valueOf({ - type: operations.COMMAND_SHOW_OPEN, - alter: 'true', - })).to.throw(TypeError); + expect(() => + operations.valueOf({ + type: operations.COMMAND_SHOW_OPEN, + alter: "true", + }) + ).to.throw(TypeError); }); }); -}) +}); diff --git a/test/shared/settings/Blacklist.test.ts b/test/shared/settings/Blacklist.test.ts index bcddf18..1ccb32a 100644 --- a/test/shared/settings/Blacklist.test.ts +++ b/test/shared/settings/Blacklist.test.ts @@ -1,140 +1,178 @@ -import Blacklist, { BlacklistItem } from '../../../src/shared/settings/Blacklist'; -import { expect } from 'chai'; -import Key from '../../../src/shared/settings/Key'; - -describe('BlacklistItem', () => { - describe('#fromJSON', () => { - it('parses string pattern', () => { - const item = BlacklistItem.fromJSON('example.com'); - expect(item.pattern).to.equal('example.com'); +import Blacklist, { + BlacklistItem, +} from "../../../src/shared/settings/Blacklist"; +import { expect } from "chai"; +import Key from "../../../src/shared/settings/Key"; + +describe("BlacklistItem", () => { + describe("#fromJSON", () => { + it("parses string pattern", () => { + const item = BlacklistItem.fromJSON("example.com"); + expect(item.pattern).to.equal("example.com"); expect(item.partial).to.be.false; }); - it('parses partial blacklist item', () => { - const item = BlacklistItem.fromJSON({ url: 'example.com', keys: ['j', 'k']}); - expect(item.pattern).to.equal('example.com'); + it("parses partial blacklist item", () => { + const item = BlacklistItem.fromJSON({ + url: "example.com", + keys: ["j", "k"], + }); + expect(item.pattern).to.equal("example.com"); expect(item.partial).to.be.true; - expect(item.keys).to.deep.equal(['j', 'k']); + expect(item.keys).to.deep.equal(["j", "k"]); }); }); - describe('#matches', () => { + describe("#matches", () => { it('matches by "*"', () => { - const item = BlacklistItem.fromJSON('*'); - expect(item.matches(new URL('https://github.com/abc'))).to.be.true; + const item = BlacklistItem.fromJSON("*"); + expect(item.matches(new URL("https://github.com/abc"))).to.be.true; }); - it('matches by hostname', () => { - const item = BlacklistItem.fromJSON('github.com'); - expect(item.matches(new URL('https://github.com'))).to.be.true; - expect(item.matches(new URL('https://gist.github.com'))).to.be.false; - expect(item.matches(new URL('https://github.com/ueokande'))).to.be.true; - expect(item.matches(new URL('https://github.org'))).to.be.false; - expect(item.matches(new URL('https://google.com/search?q=github.org'))).to.be.false; + it("matches by hostname", () => { + const item = BlacklistItem.fromJSON("github.com"); + expect(item.matches(new URL("https://github.com"))).to.be.true; + expect(item.matches(new URL("https://gist.github.com"))).to.be.false; + expect(item.matches(new URL("https://github.com/ueokande"))).to.be.true; + expect(item.matches(new URL("https://github.org"))).to.be.false; + expect(item.matches(new URL("https://google.com/search?q=github.org"))).to + .be.false; }); - it('matches by hostname with wildcard', () => { - const item = BlacklistItem.fromJSON('*.github.com'); + it("matches by hostname with wildcard", () => { + const item = BlacklistItem.fromJSON("*.github.com"); - expect(item.matches(new URL('https://github.com'))).to.be.false; - expect(item.matches(new URL('https://gist.github.com'))).to.be.true; + expect(item.matches(new URL("https://github.com"))).to.be.false; + expect(item.matches(new URL("https://gist.github.com"))).to.be.true; }); - it('matches by path', () => { - const item = BlacklistItem.fromJSON('github.com/abc'); + it("matches by path", () => { + const item = BlacklistItem.fromJSON("github.com/abc"); - expect(item.matches(new URL('https://github.com/abc'))).to.be.true; - expect(item.matches(new URL('https://github.com/abcdef'))).to.be.false; - expect(item.matches(new URL('https://gist.github.com/abc'))).to.be.false; + expect(item.matches(new URL("https://github.com/abc"))).to.be.true; + expect(item.matches(new URL("https://github.com/abcdef"))).to.be.false; + expect(item.matches(new URL("https://gist.github.com/abc"))).to.be.false; }); - it('matches by path with wildcard', () => { - const item = BlacklistItem.fromJSON('github.com/abc*'); + it("matches by path with wildcard", () => { + const item = BlacklistItem.fromJSON("github.com/abc*"); - expect(item.matches(new URL('https://github.com/abc'))).to.be.true; - expect(item.matches(new URL('https://github.com/abcdef'))).to.be.true; - expect(item.matches(new URL('https://gist.github.com/abc'))).to.be.false; + expect(item.matches(new URL("https://github.com/abc"))).to.be.true; + expect(item.matches(new URL("https://github.com/abcdef"))).to.be.true; + expect(item.matches(new URL("https://gist.github.com/abc"))).to.be.false; }); - it('matches address and port', () => { - const item = BlacklistItem.fromJSON('127.0.0.1:8888'); + it("matches address and port", () => { + const item = BlacklistItem.fromJSON("127.0.0.1:8888"); - expect(item.matches(new URL('http://127.0.0.1:8888/'))).to.be.true; - expect(item.matches(new URL('http://127.0.0.1:8888/hello'))).to.be.true; + expect(item.matches(new URL("http://127.0.0.1:8888/"))).to.be.true; + expect(item.matches(new URL("http://127.0.0.1:8888/hello"))).to.be.true; }); - it('matches with partial blacklist', () => { - const item = BlacklistItem.fromJSON({ url: 'google.com', keys: ['j', 'k'] }); + it("matches with partial blacklist", () => { + const item = BlacklistItem.fromJSON({ + url: "google.com", + keys: ["j", "k"], + }); - expect(item.matches(new URL('https://google.com'))).to.be.true; - expect(item.matches(new URL('https://yahoo.com'))).to.be.false; - }) + expect(item.matches(new URL("https://google.com"))).to.be.true; + expect(item.matches(new URL("https://yahoo.com"))).to.be.false; + }); }); - describe('#includesPartialKeys', () => { - it('matches with partial keys', () => { - const item = BlacklistItem.fromJSON({url: 'google.com', keys: ['j', 'k', '<C-U>']}); - - expect(item.includeKey(new URL('http://google.com/maps'), Key.fromMapKey('j'))).to.be.true; - expect(item.includeKey(new URL('http://google.com/maps'), Key.fromMapKey('<C-U>'))).to.be.true; - expect(item.includeKey(new URL('http://google.com/maps'), Key.fromMapKey('z'))).to.be.false; - expect(item.includeKey(new URL('http://google.com/maps'), Key.fromMapKey('u'))).to.be.false; - expect(item.includeKey(new URL('http://maps.google.com/'), Key.fromMapKey('j'))).to.be.false; - }) + describe("#includesPartialKeys", () => { + it("matches with partial keys", () => { + const item = BlacklistItem.fromJSON({ + url: "google.com", + keys: ["j", "k", "<C-U>"], + }); + + expect( + item.includeKey(new URL("http://google.com/maps"), Key.fromMapKey("j")) + ).to.be.true; + expect( + item.includeKey( + new URL("http://google.com/maps"), + Key.fromMapKey("<C-U>") + ) + ).to.be.true; + expect( + item.includeKey(new URL("http://google.com/maps"), Key.fromMapKey("z")) + ).to.be.false; + expect( + item.includeKey(new URL("http://google.com/maps"), Key.fromMapKey("u")) + ).to.be.false; + expect( + item.includeKey(new URL("http://maps.google.com/"), Key.fromMapKey("j")) + ).to.be.false; + }); }); }); -describe('Blacklist', () => { - describe('#fromJSON', () => { - it('parses string list', () => { - const blacklist = Blacklist.fromJSON(['example.com', 'example.org']); - expect(blacklist.toJSON()).to.deep.equals([ - 'example.com', 'example.org', - ]); +describe("Blacklist", () => { + describe("#fromJSON", () => { + it("parses string list", () => { + const blacklist = Blacklist.fromJSON(["example.com", "example.org"]); + expect(blacklist.toJSON()).to.deep.equals(["example.com", "example.org"]); }); - it('parses mixed blacklist', () => { + it("parses mixed blacklist", () => { const blacklist = Blacklist.fromJSON([ - { url: 'example.com', keys: ['j', 'k']}, - 'example.org', + { url: "example.com", keys: ["j", "k"] }, + "example.org", ]); expect(blacklist.toJSON()).to.deep.equals([ - { url: 'example.com', keys: ['j', 'k']}, - 'example.org', + { url: "example.com", keys: ["j", "k"] }, + "example.org", ]); }); - it('parses empty blacklist', () => { + it("parses empty blacklist", () => { const blacklist = Blacklist.fromJSON([]); expect(blacklist.toJSON()).to.deep.equals([]); }); }); - describe('#includesEntireBlacklist', () => { - it('matches a url with entire blacklist', () => { - const blacklist = Blacklist.fromJSON(['google.com', '*.github.com']); - expect(blacklist.includesEntireBlacklist(new URL('https://google.com'))).to.be.true; - expect(blacklist.includesEntireBlacklist(new URL('https://github.com'))).to.be.false; - expect(blacklist.includesEntireBlacklist(new URL('https://gist.github.com'))).to.be.true; + describe("#includesEntireBlacklist", () => { + it("matches a url with entire blacklist", () => { + const blacklist = Blacklist.fromJSON(["google.com", "*.github.com"]); + expect(blacklist.includesEntireBlacklist(new URL("https://google.com"))) + .to.be.true; + expect(blacklist.includesEntireBlacklist(new URL("https://github.com"))) + .to.be.false; + expect( + blacklist.includesEntireBlacklist(new URL("https://gist.github.com")) + ).to.be.true; }); - it('does not matches with partial blacklist', () => { - const blacklist = Blacklist.fromJSON(['google.com', { url: 'yahoo.com', keys: ['j', 'k'] }]); - expect(blacklist.includesEntireBlacklist(new URL('https://google.com'))).to.be.true; - expect(blacklist.includesEntireBlacklist(new URL('https://yahoo.com'))).to.be.false; + it("does not matches with partial blacklist", () => { + const blacklist = Blacklist.fromJSON([ + "google.com", + { url: "yahoo.com", keys: ["j", "k"] }, + ]); + expect(blacklist.includesEntireBlacklist(new URL("https://google.com"))) + .to.be.true; + expect(blacklist.includesEntireBlacklist(new URL("https://yahoo.com"))).to + .be.false; }); }); - describe('#includesKeys', () => { - it('matches with entire blacklist or keys in the partial blacklist', () => { + describe("#includesKeys", () => { + it("matches with entire blacklist or keys in the partial blacklist", () => { const blacklist = Blacklist.fromJSON([ - 'google.com', - { url: 'github.com', keys: ['j', 'k'] }, + "google.com", + { url: "github.com", keys: ["j", "k"] }, ]); - expect(blacklist.includeKey(new URL('https://google.com'), Key.fromMapKey('j'))).to.be.false; - expect(blacklist.includeKey(new URL('https://github.com'), Key.fromMapKey('j'))).to.be.true; - expect(blacklist.includeKey(new URL('https://github.com'), Key.fromMapKey('a'))).to.be.false; + expect( + blacklist.includeKey(new URL("https://google.com"), Key.fromMapKey("j")) + ).to.be.false; + expect( + blacklist.includeKey(new URL("https://github.com"), Key.fromMapKey("j")) + ).to.be.true; + expect( + blacklist.includeKey(new URL("https://github.com"), Key.fromMapKey("a")) + ).to.be.false; }); }); }); diff --git a/test/shared/settings/Key.test.ts b/test/shared/settings/Key.test.ts index b8538f8..47af1d9 100644 --- a/test/shared/settings/Key.test.ts +++ b/test/shared/settings/Key.test.ts @@ -1,74 +1,74 @@ -import { expect } from 'chai' -import Key from '../../../src/shared/settings/Key'; +import { expect } from "chai"; +import Key from "../../../src/shared/settings/Key"; describe("Key", () => { - describe('fromMapKey', () => { - it('return for X', () => { - const key = Key.fromMapKey('x'); - expect(key.key).to.equal('x'); + describe("fromMapKey", () => { + it("return for X", () => { + const key = Key.fromMapKey("x"); + expect(key.key).to.equal("x"); expect(key.shift).to.be.false; expect(key.ctrl).to.be.false; expect(key.alt).to.be.false; expect(key.meta).to.be.false; }); - it('return for Shift+X', () => { - const key = Key.fromMapKey('X'); - expect(key.key).to.equal('X'); + it("return for Shift+X", () => { + const key = Key.fromMapKey("X"); + expect(key.key).to.equal("X"); expect(key.shift).to.be.true; expect(key.ctrl).to.be.false; expect(key.alt).to.be.false; expect(key.meta).to.be.false; }); - it('return for Ctrl+X', () => { - const key = Key.fromMapKey('<C-X>'); - expect(key.key).to.equal('x'); + it("return for Ctrl+X", () => { + const key = Key.fromMapKey("<C-X>"); + expect(key.key).to.equal("x"); expect(key.shift).to.be.false; expect(key.ctrl).to.be.true; expect(key.alt).to.be.false; expect(key.meta).to.be.false; }); - it('returns for Ctrl+Meta+X', () => { - const key = Key.fromMapKey('<C-M-X>'); - expect(key.key).to.equal('x'); + it("returns for Ctrl+Meta+X", () => { + const key = Key.fromMapKey("<C-M-X>"); + expect(key.key).to.equal("x"); expect(key.shift).to.be.false; expect(key.ctrl).to.be.true; expect(key.alt).to.be.false; expect(key.meta).to.be.true; }); - it('returns for Ctrl+Shift+x', () => { - const key = Key.fromMapKey('<C-S-x>'); - expect(key.key).to.equal('X'); + it("returns for Ctrl+Shift+x", () => { + const key = Key.fromMapKey("<C-S-x>"); + expect(key.key).to.equal("X"); expect(key.shift).to.be.true; expect(key.ctrl).to.be.true; expect(key.alt).to.be.false; expect(key.meta).to.be.false; }); - it('returns for Shift+Esc', () => { - const key = Key.fromMapKey('<S-Esc>'); - expect(key.key).to.equal('Esc'); + it("returns for Shift+Esc", () => { + const key = Key.fromMapKey("<S-Esc>"); + expect(key.key).to.equal("Esc"); expect(key.shift).to.be.true; expect(key.ctrl).to.be.false; expect(key.alt).to.be.false; expect(key.meta).to.be.false; }); - it('returns for Ctrl+Esc', () => { - const key = Key.fromMapKey('<C-Esc>'); - expect(key.key).to.equal('Esc'); + it("returns for Ctrl+Esc", () => { + const key = Key.fromMapKey("<C-Esc>"); + expect(key.key).to.equal("Esc"); expect(key.shift).to.be.false; expect(key.ctrl).to.be.true; expect(key.alt).to.be.false; expect(key.meta).to.be.false; }); - it('returns for Ctrl+Esc', () => { - const key = Key.fromMapKey('<C-Space>'); - expect(key.key).to.equal('Space'); + it("returns for Ctrl+Esc", () => { + const key = Key.fromMapKey("<C-Space>"); + expect(key.key).to.equal("Space"); expect(key.shift).to.be.false; expect(key.ctrl).to.be.true; expect(key.alt).to.be.false; @@ -76,30 +76,54 @@ describe("Key", () => { }); }); - describe('idDigit', () => { - it('returns true if the key is a digit', () => { - expect(new Key({ key: '0' }).isDigit()).to.be.true; - expect(new Key({ key: '9' }).isDigit()).to.be.true; - expect(new Key({ key: '9', alt: true }).isDigit()).to.be.false; + describe("idDigit", () => { + it("returns true if the key is a digit", () => { + expect(new Key({ key: "0" }).isDigit()).to.be.true; + expect(new Key({ key: "9" }).isDigit()).to.be.true; + expect(new Key({ key: "9", alt: true }).isDigit()).to.be.false; - expect(new Key({ key: 'a' }).isDigit()).to.be.false; - expect(new Key({ key: '0' }).isDigit()).to.be.false; - }) + expect(new Key({ key: "a" }).isDigit()).to.be.false; + expect(new Key({ key: "0" }).isDigit()).to.be.false; + }); }); - describe('equals', () => { - it('returns true if the keys are equivalent', () => { - expect(new Key({ - key: 'x', shift: false, ctrl: true, alt: false, meta: false, - }).equals(new Key({ - key: 'x', shift: false, ctrl: true, alt: false, meta: false, - }))).to.be.true; + describe("equals", () => { + it("returns true if the keys are equivalent", () => { + expect( + new Key({ + key: "x", + shift: false, + ctrl: true, + alt: false, + meta: false, + }).equals( + new Key({ + key: "x", + shift: false, + ctrl: true, + alt: false, + meta: false, + }) + ) + ).to.be.true; - expect(new Key({ - key: 'x', shift: false, ctrl: false, alt: false, meta: false, - }).equals(new Key({ - key: 'X', shift: true, ctrl: false, alt: false, meta: false, - }))).to.be.false; - }) + expect( + new Key({ + key: "x", + shift: false, + ctrl: false, + alt: false, + meta: false, + }).equals( + new Key({ + key: "X", + shift: true, + ctrl: false, + alt: false, + meta: false, + }) + ) + ).to.be.false; + }); }); }); diff --git a/test/shared/settings/Keymaps.test.ts b/test/shared/settings/Keymaps.test.ts index dcea6e4..264684d 100644 --- a/test/shared/settings/Keymaps.test.ts +++ b/test/shared/settings/Keymaps.test.ts @@ -1,65 +1,80 @@ -import Keymaps from '../../../src/shared/settings/Keymaps'; -import { expect } from 'chai'; +import Keymaps from "../../../src/shared/settings/Keymaps"; +import { expect } from "chai"; -describe('Keymaps', () => { - describe('#valueOf', () => { - it('returns empty object by empty settings', () => { +describe("Keymaps", () => { + describe("#valueOf", () => { + it("returns empty object by empty settings", () => { const keymaps = Keymaps.fromJSON({}).toJSON(); expect(keymaps).to.be.empty; }); - it('returns keymaps by valid settings', () => { + it("returns keymaps by valid settings", () => { const keymaps = Keymaps.fromJSON({ k: { type: "scroll.vertically", count: -1 }, j: { type: "scroll.vertically", count: 1 }, }).toJSON(); - expect(keymaps['k']).to.deep.equal({ type: "scroll.vertically", count: -1 }); - expect(keymaps['j']).to.deep.equal({ type: "scroll.vertically", count: 1 }); + expect(keymaps["k"]).to.deep.equal({ + type: "scroll.vertically", + count: -1, + }); + expect(keymaps["j"]).to.deep.equal({ + type: "scroll.vertically", + count: 1, + }); }); - it('throws a TypeError by invalid settings', () => { - expect(() => Keymaps.fromJSON({ - k: { type: "invalid.operation" }, - })).to.throw(TypeError); + it("throws a TypeError by invalid settings", () => { + expect(() => + Keymaps.fromJSON({ + k: { type: "invalid.operation" }, + }) + ).to.throw(TypeError); }); }); - describe('#combine', () => { - it('returns combined keymaps', () => { + describe("#combine", () => { + it("returns combined keymaps", () => { const keymaps = Keymaps.fromJSON({ k: { type: "scroll.vertically", count: -1 }, j: { type: "scroll.vertically", count: 1 }, - }).combine(Keymaps.fromJSON({ - n: { type: "find.next" }, - N: { type: "find.prev" }, - })); + }).combine( + Keymaps.fromJSON({ + n: { type: "find.next" }, + N: { type: "find.prev" }, + }) + ); - const entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2)); + const entries = keymaps + .entries() + .sort(([name1], [name2]) => name1.localeCompare(name2)); expect(entries).deep.equals([ - ['j', { type: "scroll.vertically", count: 1 }], - ['k', { type: "scroll.vertically", count: -1 }], - ['n', { type: "find.next" }], - ['N', { type: "find.prev" }], + ["j", { type: "scroll.vertically", count: 1 }], + ["k", { type: "scroll.vertically", count: -1 }], + ["n", { type: "find.next" }], + ["N", { type: "find.prev" }], ]); }); - it('overrides current keymaps', () => { + it("overrides current keymaps", () => { const keymaps = Keymaps.fromJSON({ k: { type: "scroll.vertically", count: -1 }, j: { type: "scroll.vertically", count: 1 }, - }).combine(Keymaps.fromJSON({ - n: { type: "find.next" }, - j: { type: "find.prev" }, - })); + }).combine( + Keymaps.fromJSON({ + n: { type: "find.next" }, + j: { type: "find.prev" }, + }) + ); - const entries = keymaps.entries().sort(([name1], [name2]) => name1.localeCompare(name2)); + const entries = keymaps + .entries() + .sort(([name1], [name2]) => name1.localeCompare(name2)); expect(entries).deep.equals([ - ['j', { type: "find.prev" }], - ['k', { type: "scroll.vertically", count: -1 }], - ['n', { type: "find.next" }], + ["j", { type: "find.prev" }], + ["k", { type: "scroll.vertically", count: -1 }], + ["n", { type: "find.next" }], ]); }); }); }); - diff --git a/test/shared/settings/Properties.test.ts b/test/shared/settings/Properties.test.ts index 4639839..6007e84 100644 --- a/test/shared/settings/Properties.test.ts +++ b/test/shared/settings/Properties.test.ts @@ -1,30 +1,29 @@ -import Properties from '../../../src/shared/settings/Properties'; -import { expect } from 'chai'; +import Properties from "../../../src/shared/settings/Properties"; +import { expect } from "chai"; -describe('Properties', () => { - describe('#propertiesValueOf', () => { - it('returns with default properties by empty settings', () => { +describe("Properties", () => { + describe("#propertiesValueOf", () => { + it("returns with default properties by empty settings", () => { const props = Properties.fromJSON({}); expect(props).to.deep.equal({ hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" - }) + complete: "sbh", + }); }); - it('returns properties by valid settings', () => { + it("returns properties by valid settings", () => { const props = Properties.fromJSON({ hintchars: "abcdefgh", smoothscroll: false, - complete: "sbh" + complete: "sbh", }); expect(props).to.deep.equal({ hintchars: "abcdefgh", smoothscroll: false, - complete: "sbh" + complete: "sbh", }); }); }); }); - diff --git a/test/shared/settings/Search.test.ts b/test/shared/settings/Search.test.ts index 8bd8d89..1feb14b 100644 --- a/test/shared/settings/Search.test.ts +++ b/test/shared/settings/Search.test.ts @@ -1,55 +1,63 @@ -import Search from '../../../src/shared/settings/Search'; -import { expect } from 'chai'; +import Search from "../../../src/shared/settings/Search"; +import { expect } from "chai"; -describe('Search', () => { - it('returns search settings by valid settings', () => { +describe("Search", () => { + it("returns search settings by valid settings", () => { const search = Search.fromJSON({ - default: 'google', + default: "google", engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?p={}', - } + google: "https://google.com/search?q={}", + yahoo: "https://search.yahoo.com/search?p={}", + }, }); - expect(search.defaultEngine).to.equal('google') + expect(search.defaultEngine).to.equal("google"); expect(search.engines).to.deep.equals({ - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?p={}', + google: "https://google.com/search?q={}", + yahoo: "https://search.yahoo.com/search?p={}", }); expect(search.toJSON()).to.deep.equal({ - default: 'google', + default: "google", engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?p={}', - } + google: "https://google.com/search?q={}", + yahoo: "https://search.yahoo.com/search?p={}", + }, }); }); - it('throws a TypeError by invalid settings', () => { - expect(() => Search.fromJSON({ - default: 'wikipedia', - engines: { - 'google': 'https://google.com/search?q={}', - 'yahoo': 'https://search.yahoo.com/search?p={}', - } - })).to.throw(TypeError); - expect(() => Search.fromJSON({ - default: 'g o o g l e', - engines: { - 'g o o g l e': 'https://google.com/search?q={}', - } - })).to.throw(TypeError); - expect(() => Search.fromJSON({ - default: 'google', - engines: { - 'google': 'https://google.com/search', - } - })).to.throw(TypeError); - expect(() => Search.fromJSON({ - default: 'google', - engines: { - 'google': 'https://google.com/search?q={}&r={}', - } - })).to.throw(TypeError); + it("throws a TypeError by invalid settings", () => { + expect(() => + Search.fromJSON({ + default: "wikipedia", + engines: { + google: "https://google.com/search?q={}", + yahoo: "https://search.yahoo.com/search?p={}", + }, + }) + ).to.throw(TypeError); + expect(() => + Search.fromJSON({ + default: "g o o g l e", + engines: { + "g o o g l e": "https://google.com/search?q={}", + }, + }) + ).to.throw(TypeError); + expect(() => + Search.fromJSON({ + default: "google", + engines: { + google: "https://google.com/search", + }, + }) + ).to.throw(TypeError); + expect(() => + Search.fromJSON({ + default: "google", + engines: { + google: "https://google.com/search?q={}&r={}", + }, + }) + ).to.throw(TypeError); }); }); diff --git a/test/shared/settings/Settings.test.ts b/test/shared/settings/Settings.test.ts index 658132c..4ecfe77 100644 --- a/test/shared/settings/Settings.test.ts +++ b/test/shared/settings/Settings.test.ts @@ -1,19 +1,19 @@ -import Settings from '../../../src/shared/settings/Settings'; -import { expect } from 'chai'; +import Settings from "../../../src/shared/settings/Settings"; +import { expect } from "chai"; -describe('Settings', () => { - describe('#valueOf', () => { - it('returns settings by valid settings', () => { +describe("Settings", () => { + describe("#valueOf", () => { + it("returns settings by valid settings", () => { const x = Settings.fromJSON({ keymaps: {}, - "search": { - "default": "google", - "engines": { - "google": "https://google.com/search?q={}", - } + search: { + default: "google", + engines: { + google: "https://google.com/search?q={}", + }, }, - "properties": {}, - "blacklist": [] + properties: {}, + blacklist: [], }); expect({ @@ -27,28 +27,28 @@ describe('Settings', () => { default: "google", engines: { google: "https://google.com/search?q={}", - } + }, }, properties: { hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: "sbh" + complete: "sbh", }, - blacklist: [] + blacklist: [], }); }); - it('sets default settings', () => { + it("sets default settings", () => { const value = Settings.fromJSON({}); expect(value.keymaps.toJSON()).to.not.be.empty; expect(value.properties.toJSON()).to.not.be.empty; - expect(value.search.defaultEngine).to.be.a('string'); - expect(value.search.engines).to.be.an('object'); + expect(value.search.defaultEngine).to.be.a("string"); + expect(value.search.engines).to.be.an("object"); expect(value.blacklist.toJSON()).to.be.empty; }); - it('throws a TypeError with an unknown field', () => { - expect(() => Settings.fromJSON({ name: 'alice' })).to.throw(TypeError) + it("throws a TypeError with an unknown field", () => { + expect(() => Settings.fromJSON({ name: "alice" })).to.throw(TypeError); }); }); }); diff --git a/test/shared/urls.test.ts b/test/shared/urls.test.ts index 6206d03..f264ad9 100644 --- a/test/shared/urls.test.ts +++ b/test/shared/urls.test.ts @@ -1,64 +1,78 @@ -import * as parsers from '../../src/shared/urls'; -import { expect } from 'chai'; -import Search from '../../src/shared/settings/Search'; +import * as parsers from "../../src/shared/urls"; +import { expect } from "chai"; +import Search from "../../src/shared/settings/Search"; describe("shared/commands/parsers", () => { - describe('#searchUrl', () => { + describe("#searchUrl", () => { const config = Search.fromJSON({ - default: 'google', + default: "google", engines: { - google: 'https://google.com/search?q={}', - yahoo: 'https://yahoo.com/search?q={}', - } + google: "https://google.com/search?q={}", + yahoo: "https://yahoo.com/search?q={}", + }, }); - it('convertes search url', () => { - expect(parsers.searchUrl('google.com', config)) - .to.equal('http://google.com'); - expect(parsers.searchUrl('google apple', config)) - .to.equal('https://google.com/search?q=apple'); - expect(parsers.searchUrl('yahoo apple', config)) - .to.equal('https://yahoo.com/search?q=apple'); - expect(parsers.searchUrl('google apple banana', config)) - .to.equal('https://google.com/search?q=apple%20banana'); - expect(parsers.searchUrl('yahoo C++CLI', config)) - .to.equal('https://yahoo.com/search?q=C%2B%2BCLI'); + it("convertes search url", () => { + expect(parsers.searchUrl("google.com", config)).to.equal( + "http://google.com" + ); + expect(parsers.searchUrl("google apple", config)).to.equal( + "https://google.com/search?q=apple" + ); + expect(parsers.searchUrl("yahoo apple", config)).to.equal( + "https://yahoo.com/search?q=apple" + ); + expect(parsers.searchUrl("google apple banana", config)).to.equal( + "https://google.com/search?q=apple%20banana" + ); + expect(parsers.searchUrl("yahoo C++CLI", config)).to.equal( + "https://yahoo.com/search?q=C%2B%2BCLI" + ); }); - it('user default search engine', () => { - expect(parsers.searchUrl('apple banana', config)) - .to.equal('https://google.com/search?q=apple%20banana'); + it("user default search engine", () => { + expect(parsers.searchUrl("apple banana", config)).to.equal( + "https://google.com/search?q=apple%20banana" + ); }); - it('searches with a word containing a colon', () => { - expect(parsers.searchUrl('foo:', config)) - .to.equal('https://google.com/search?q=foo%3A'); - expect(parsers.searchUrl('std::vector', config)) - .to.equal('https://google.com/search?q=std%3A%3Avector'); + it("searches with a word containing a colon", () => { + expect(parsers.searchUrl("foo:", config)).to.equal( + "https://google.com/search?q=foo%3A" + ); + expect(parsers.searchUrl("std::vector", config)).to.equal( + "https://google.com/search?q=std%3A%3Avector" + ); }); - it('localhost urls', () => { - expect(parsers.searchUrl('localhost', config)) - .to.equal('http://localhost'); - expect(parsers.searchUrl('http://localhost', config)) - .to.equal('http://localhost/'); - expect(parsers.searchUrl('localhost:8080', config)) - .to.equal('http://localhost:8080'); - expect(parsers.searchUrl('localhost:80nan', config)) - .to.equal('https://google.com/search?q=localhost%3A80nan'); - expect(parsers.searchUrl('localhost 8080', config)) - .to.equal('https://google.com/search?q=localhost%208080'); - expect(parsers.searchUrl('localhost:80/build', config)) - .to.equal('http://localhost:80/build') - }) + it("localhost urls", () => { + expect(parsers.searchUrl("localhost", config)).to.equal( + "http://localhost" + ); + expect(parsers.searchUrl("http://localhost", config)).to.equal( + "http://localhost/" + ); + expect(parsers.searchUrl("localhost:8080", config)).to.equal( + "http://localhost:8080" + ); + expect(parsers.searchUrl("localhost:80nan", config)).to.equal( + "https://google.com/search?q=localhost%3A80nan" + ); + expect(parsers.searchUrl("localhost 8080", config)).to.equal( + "https://google.com/search?q=localhost%208080" + ); + expect(parsers.searchUrl("localhost:80/build", config)).to.equal( + "http://localhost:80/build" + ); + }); }); - describe('#normalizeUrl', () => { - it('normalize urls', () => { - expect(parsers.normalizeUrl('https://google.com/')) - .to.equal('https://google.com/'); - expect(parsers.normalizeUrl('google.com')) - .to.equal('http://google.com'); + describe("#normalizeUrl", () => { + it("normalize urls", () => { + expect(parsers.normalizeUrl("https://google.com/")).to.equal( + "https://google.com/" + ); + expect(parsers.normalizeUrl("google.com")).to.equal("http://google.com"); }); }); }); |