Merge pull request #655 from ueokande/partial-blacklist
Partial blacklist
This commit is contained in:
commit
18c72bf15c
37 changed files with 773 additions and 364 deletions
|
@ -5,10 +5,12 @@ 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", () => {
|
||||
let server = new TestServer().receiveContent('/*',
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html">`,
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`,
|
||||
);
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
@ -24,17 +26,12 @@ describe("blacklist test", () => {
|
|||
await server.start();
|
||||
|
||||
let url = server.url('/a').replace('http://', '');
|
||||
await browser.storage.local.set({
|
||||
settings: {
|
||||
source: 'json',
|
||||
json: `{
|
||||
"keymaps": {
|
||||
"j": { "type": "scroll.vertically", "count": 1 }
|
||||
},
|
||||
"blacklist": [ "${url}" ]
|
||||
}`,
|
||||
await new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
keymaps: {
|
||||
j: { type: "scroll.vertically", count: 1 },
|
||||
},
|
||||
});
|
||||
blacklist: [ url ],
|
||||
}));
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
|
@ -46,7 +43,7 @@ describe("blacklist test", () => {
|
|||
|
||||
it('should disable add-on if the URL is in the blacklist', async () => {
|
||||
let page = await Page.navigateTo(webdriver, server.url('/a'));
|
||||
await page.sendKeys('j')
|
||||
await page.sendKeys('j');
|
||||
|
||||
let scrollY = await page.getScrollY();
|
||||
assert.strictEqual(scrollY, 0);
|
||||
|
|
|
@ -4,10 +4,11 @@ import * as path from 'path';
|
|||
import TestServer from './lib/TestServer';
|
||||
import eventually from './eventually';
|
||||
import * as clipboard from './lib/clipboard';
|
||||
import settings from './settings';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver, Key } from 'selenium-webdriver';
|
||||
import Page from './lib/Page';
|
||||
import SettingRepository from "./lib/SettingRepository";
|
||||
import Settings from "../src/shared/settings/Settings";
|
||||
|
||||
describe("clipboard test", () => {
|
||||
let server = new TestServer(12321).receiveContent('/happy', 'ok');
|
||||
|
@ -23,9 +24,14 @@ describe("clipboard test", () => {
|
|||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
await new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
search: {
|
||||
default: "google",
|
||||
engines: {
|
||||
"google": "http://127.0.0.1:12321/google?q={}",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
await server.start();
|
||||
});
|
||||
|
@ -42,7 +48,7 @@ describe("clipboard test", () => {
|
|||
for (let tab of tabs.slice(1)) {
|
||||
await browser.tabs.remove(tab.id);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('should copy current URL by y', async () => {
|
||||
let page = await Page.navigateTo(webdriver, server.url('/#should_copy_url'));
|
||||
|
|
|
@ -10,7 +10,7 @@ import Page from './lib/Page';
|
|||
describe('addbookmark command test', () => {
|
||||
let server = new TestServer().receiveContent('/happy', `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"><head><title>how to be happy</title></head></html">`,
|
||||
<html lang="en"><head><title>how to be happy</title></head></html>`,
|
||||
);
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
|
|
@ -36,10 +36,10 @@ describe('bdelete/bdeletes command test', () => {
|
|||
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.create({ url: server.url('/site2'), pinned: true });
|
||||
await browser.tabs.create({ url: server.url('/site3'), pinned: true });
|
||||
await browser.tabs.create({ url: server.url('/site4'), });
|
||||
await browser.tabs.create({ url: server.url('/site5'), });
|
||||
|
||||
await eventually(async() => {
|
||||
let handles = await webdriver.getAllWindowHandles();
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('buffer command test', () => {
|
|||
<head>
|
||||
<title>my_${req.path.slice(1)}</title>
|
||||
</head>
|
||||
</html">`);
|
||||
</html>`);
|
||||
});
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
|
|
@ -34,7 +34,7 @@ describe("help command test", () => {
|
|||
|
||||
beforeEach(async() => {
|
||||
page = await Page.navigateTo(webdriver, server.url());
|
||||
})
|
||||
});
|
||||
|
||||
it('should open help page by help command ', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
|
|
@ -2,14 +2,15 @@ import * as path from 'path';
|
|||
import * as assert from 'assert';
|
||||
|
||||
import TestServer from './lib/TestServer';
|
||||
import settings from './settings';
|
||||
import eventually from './eventually';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver } from 'selenium-webdriver';
|
||||
import Page from './lib/Page';
|
||||
import SettingRepository from "./lib/SettingRepository";
|
||||
import Settings from "../src/shared/settings/Settings";
|
||||
|
||||
describe("open command test", () => {
|
||||
let server = new TestServer(12321)
|
||||
let server = new TestServer()
|
||||
.receiveContent('/google', 'google')
|
||||
.receiveContent('/yahoo', 'yahoo');
|
||||
let lanthan: Lanthan;
|
||||
|
@ -25,11 +26,16 @@ describe("open command test", () => {
|
|||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
|
||||
await server.start();
|
||||
await new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
search: {
|
||||
default: "google",
|
||||
engines: {
|
||||
"google": server.url('/google?q={}'),
|
||||
"yahoo": server.url('/yahoo?q={}'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
|
@ -42,7 +48,7 @@ describe("open command test", () => {
|
|||
beforeEach(async() => {
|
||||
await webdriver.switchTo().defaultContent();
|
||||
page = await Page.navigateTo(webdriver, server.url());
|
||||
})
|
||||
});
|
||||
|
||||
it('should open default search for keywords by open command ', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -60,7 +66,7 @@ describe("open command test", () => {
|
|||
await console.execCommand('open yahoo an apple');
|
||||
|
||||
await eventually(async() => {
|
||||
let tabs = await browser.tabs.query({ active: true })
|
||||
let tabs = await browser.tabs.query({ active: true });
|
||||
let url = new URL(tabs[0].url);
|
||||
assert.strictEqual(url.href, server.url('/yahoo?q=an%20apple'))
|
||||
});
|
||||
|
@ -71,7 +77,7 @@ describe("open command test", () => {
|
|||
await console.execCommand('open');
|
||||
|
||||
await eventually(async() => {
|
||||
let tabs = await browser.tabs.query({ active: true })
|
||||
let tabs = await browser.tabs.query({ active: true });
|
||||
let url = new URL(tabs[0].url);
|
||||
assert.strictEqual(url.href, server.url('/google?q='))
|
||||
});
|
||||
|
@ -82,7 +88,7 @@ describe("open command test", () => {
|
|||
await console.execCommand('open yahoo');
|
||||
|
||||
await eventually(async() => {
|
||||
let tabs = await browser.tabs.query({ active: true })
|
||||
let tabs = await browser.tabs.query({ active: true });
|
||||
let url = new URL(tabs[0].url);
|
||||
assert.strictEqual(url.href, server.url('/yahoo?q='))
|
||||
});
|
||||
|
@ -93,7 +99,7 @@ describe("open command test", () => {
|
|||
await console.execCommand('open example.com');
|
||||
|
||||
await eventually(async() => {
|
||||
let tabs = await browser.tabs.query({ active: true })
|
||||
let tabs = await browser.tabs.query({ active: true });
|
||||
let url = new URL(tabs[0].url);
|
||||
assert.strictEqual(url.href, 'http://example.com/')
|
||||
});
|
||||
|
@ -104,7 +110,7 @@ describe("open command test", () => {
|
|||
await console.execCommand('open https://example.com/');
|
||||
|
||||
await eventually(async() => {
|
||||
let tabs = await browser.tabs.query({ active: true })
|
||||
let tabs = await browser.tabs.query({ active: true });
|
||||
let url = new URL(tabs[0].url);
|
||||
assert.strictEqual(url.href, 'https://example.com/')
|
||||
});
|
||||
|
|
|
@ -2,14 +2,15 @@ import * as path from 'path';
|
|||
import * as assert from 'assert';
|
||||
|
||||
import TestServer from './lib/TestServer';
|
||||
import settings from './settings';
|
||||
import eventually from './eventually';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver } from 'selenium-webdriver';
|
||||
import Page from './lib/Page';
|
||||
import SettingRepository from "./lib/SettingRepository";
|
||||
import Settings from "../src/shared/settings/Settings";
|
||||
|
||||
describe("tabopen command test", () => {
|
||||
let server = new TestServer(12321)
|
||||
let server = new TestServer()
|
||||
.receiveContent('/google', 'google')
|
||||
.receiveContent('/yahoo', 'yahoo');
|
||||
let lanthan: Lanthan;
|
||||
|
@ -25,11 +26,16 @@ describe("tabopen command test", () => {
|
|||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
|
||||
await server.start();
|
||||
await new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
search: {
|
||||
default: "google",
|
||||
engines: {
|
||||
"google": server.url('/google?q={}'),
|
||||
"yahoo": server.url('/yahoo?q={}'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
|
@ -46,7 +52,7 @@ describe("tabopen command test", () => {
|
|||
}
|
||||
|
||||
page = await Page.navigateTo(webdriver, server.url());
|
||||
})
|
||||
});
|
||||
|
||||
it('should open default search for keywords by tabopen command ', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
|
|
@ -2,14 +2,15 @@ import * as path from 'path';
|
|||
import * as assert from 'assert';
|
||||
|
||||
import TestServer from './lib/TestServer';
|
||||
import settings from './settings';
|
||||
import eventually from './eventually';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver } from 'selenium-webdriver';
|
||||
import Page from './lib/Page';
|
||||
import SettingRepository from "./lib/SettingRepository";
|
||||
import Settings from "../src/shared/settings/Settings";
|
||||
|
||||
describe("winopen command test", () => {
|
||||
let server = new TestServer(12321)
|
||||
let server = new TestServer()
|
||||
.receiveContent('/google', 'google')
|
||||
.receiveContent('/yahoo', 'yahoo');
|
||||
let lanthan: Lanthan;
|
||||
|
@ -24,11 +25,17 @@ describe("winopen command test", () => {
|
|||
.build();
|
||||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
|
||||
await server.start();
|
||||
await new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
search: {
|
||||
default: "google",
|
||||
engines: {
|
||||
"google": server.url('/google?q={}'),
|
||||
"yahoo": server.url('/yahoo?q={}'),
|
||||
},
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
|
@ -45,7 +52,7 @@ describe("winopen command test", () => {
|
|||
}
|
||||
|
||||
page = await Page.navigateTo(webdriver, server.url());
|
||||
})
|
||||
});
|
||||
|
||||
it('should open default search for keywords by winopen command ', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
|
|
@ -2,7 +2,6 @@ import * as path from 'path';
|
|||
import * as assert from 'assert';
|
||||
|
||||
import eventually from './eventually';
|
||||
import settings from './settings';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver, Key } from 'selenium-webdriver';
|
||||
import Page from './lib/Page';
|
||||
|
@ -10,7 +9,6 @@ import Page from './lib/Page';
|
|||
describe("general completion test", () => {
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
let browser: any;
|
||||
let page: Page;
|
||||
|
||||
before(async() => {
|
||||
|
@ -19,11 +17,6 @@ describe("general completion test", () => {
|
|||
.spyAddon(path.join(__dirname, '..'))
|
||||
.build();
|
||||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
|
@ -42,8 +35,8 @@ describe("general completion test", () => {
|
|||
let items = await console.getCompletions();
|
||||
assert.strictEqual(items.length, 11);
|
||||
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[1].text.startsWith('set'));
|
||||
assert.ok(items[2].text.startsWith('open'));
|
||||
assert.ok(items[3].text.startsWith('tabopen'))
|
||||
});
|
||||
|
||||
|
@ -54,8 +47,8 @@ describe("general completion test", () => {
|
|||
let items = await console.getCompletions();
|
||||
assert.strictEqual(items.length, 4);
|
||||
assert.deepStrictEqual(items[0], { type: 'title', text: 'Console Command' });
|
||||
assert.ok(items[1].text.startsWith('buffer'))
|
||||
assert.ok(items[2].text.startsWith('bdelete'))
|
||||
assert.ok(items[1].text.startsWith('buffer'));
|
||||
assert.ok(items[2].text.startsWith('bdelete'));
|
||||
assert.ok(items[3].text.startsWith('bdeletes'))
|
||||
});
|
||||
|
||||
|
@ -74,14 +67,14 @@ describe("general completion test", () => {
|
|||
await console.sendKeys(Key.TAB);
|
||||
await eventually(async() => {
|
||||
let items = await console.getCompletions();
|
||||
assert.ok(items[1].highlight)
|
||||
assert.ok(items[1].highlight);
|
||||
assert.strictEqual(await console.currentValue(), 'buffer');
|
||||
});
|
||||
|
||||
await console.sendKeys(Key.TAB, Key.TAB);
|
||||
await eventually(async() => {
|
||||
let items = await console.getCompletions();
|
||||
assert.ok(items[3].highlight)
|
||||
assert.ok(items[3].highlight);
|
||||
assert.strictEqual(await console.currentValue(), 'bdeletes');
|
||||
});
|
||||
|
||||
|
@ -93,7 +86,7 @@ describe("general completion test", () => {
|
|||
await console.sendKeys(Key.SHIFT, Key.TAB);
|
||||
await eventually(async() => {
|
||||
let items = await console.getCompletions();
|
||||
assert.ok(items[3].highlight)
|
||||
assert.ok(items[3].highlight);
|
||||
assert.strictEqual(await console.currentValue(), 'bdeletes');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import * as path from 'path';
|
|||
|
||||
import { Request, Response } from 'express'
|
||||
import TestServer from './lib/TestServer';
|
||||
import settings from './settings';
|
||||
import eventually from './eventually';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver } from 'selenium-webdriver';
|
||||
|
@ -17,7 +16,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
<head>
|
||||
<title>title_${req.path.slice(1)}</title>
|
||||
</head>
|
||||
</html">`);
|
||||
</html>`);
|
||||
});
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
@ -32,10 +31,6 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
|
||||
await server.start();
|
||||
});
|
||||
|
||||
|
@ -53,7 +48,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
}
|
||||
|
||||
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('/site2'), pinned: true });
|
||||
for (let i = 3; i <= 5; ++i) {
|
||||
await browser.tabs.create({ url: server.url('/site' + i) });
|
||||
}
|
||||
|
@ -84,7 +79,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.ok(items[3].text.includes('%'));
|
||||
assert.ok(items[5].text.includes('#'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should filter items with URLs by keywords on "buffer" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -97,7 +92,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.ok(items[1].text.includes('title_site2'));
|
||||
assert.ok(items[1].text.includes(server.url('/site2')));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should filter items with titles by keywords on "buffer" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -108,7 +103,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' });
|
||||
assert.ok(items[1].text.startsWith('2:'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should show one item by number on "buffer" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -120,7 +115,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.deepStrictEqual(items[0], { type: 'title', text: 'Buffers' });
|
||||
assert.ok(items[1].text.startsWith('2:'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should show unpinned tabs "bdelete" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -133,7 +128,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.ok(items[2].text.includes('site4'));
|
||||
assert.ok(items[3].text.includes('site5'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should show unpinned tabs "bdeletes" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -146,7 +141,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.ok(items[2].text.includes('site4'));
|
||||
assert.ok(items[3].text.includes('site5'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should show both pinned and unpinned tabs "bdelete!" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -161,7 +156,7 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.ok(items[4].text.includes('site4'));
|
||||
assert.ok(items[5].text.includes('site5'));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should show both pinned and unpinned tabs "bdeletes!" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -176,5 +171,5 @@ describe("completion on buffer/bdelete/bdeletes", () => {
|
|||
assert.ok(items[4].text.includes('site4'));
|
||||
assert.ok(items[5].text.includes('site5'));
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import * as path from 'path';
|
||||
import * as assert from 'assert';
|
||||
|
||||
import Settings from "../src/shared/settings/Settings";
|
||||
import TestServer from './lib/TestServer';
|
||||
import settings from './settings';
|
||||
import eventually from './eventually';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver } from 'selenium-webdriver';
|
||||
import Page from './lib/Page';
|
||||
import SettingRepository from "./lib/SettingRepository";
|
||||
|
||||
describe("completion on open/tabopen/winopen commands", () => {
|
||||
let server = new TestServer().receiveContent('/*', 'ok');
|
||||
|
@ -25,10 +26,6 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
|
||||
// Add item into hitories
|
||||
await webdriver.navigate().to(('https://i-beam.org/404'));
|
||||
});
|
||||
|
@ -65,7 +62,7 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
let items = completions.filter(x => x.type === 'item').map(x => x.text);
|
||||
assert.ok(items.every(x => x.includes('https://')));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should filter items with titles by keywords on "open" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -76,7 +73,7 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
let items = completions.filter(x => x.type === 'item').map(x => x.text);
|
||||
assert.ok(items.every(x => x.toLowerCase().includes('getting')));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should filter items with titles by keywords on "tabopen" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -87,7 +84,7 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
let items = completions.filter(x => x.type === 'item').map(x => x.text);
|
||||
assert.ok(items.every(x => x.includes('https://')));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should filter items with titles by keywords on "winopen" command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -98,7 +95,7 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
let items = completions.filter(x => x.type === 'item').map(x => x.text);
|
||||
assert.ok(items.every(x => x.includes('https://')));
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should display only specified items in "complete" property by set command', async() => {
|
||||
let console = await page.showConsole();
|
||||
|
@ -127,24 +124,12 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
let titles = completions.filter(x => x.type === 'title').map(x => x.text);
|
||||
assert.deepStrictEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines'])
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should display only specified items in "complete" property by setting', async() => {
|
||||
await browser.storage.local.set({ settings: {
|
||||
source: 'json',
|
||||
json: `{
|
||||
"keymaps": {
|
||||
":": { "type": "command.show" }
|
||||
},
|
||||
"search": {
|
||||
"default": "google",
|
||||
"engines": { "google": "https://google.com/search?q={}" }
|
||||
},
|
||||
"properties": {
|
||||
"complete": "sbh"
|
||||
}
|
||||
}`,
|
||||
}});
|
||||
new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
properties: { complete: "sbh" },
|
||||
}));
|
||||
|
||||
let console = await page.showConsole();
|
||||
await console.inputKeys('open ');
|
||||
|
@ -158,21 +143,9 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
await console.close();
|
||||
await (webdriver.switchTo() as any).parentFrame();
|
||||
|
||||
await browser.storage.local.set({ settings: {
|
||||
source: 'json',
|
||||
json: `{
|
||||
"keymaps": {
|
||||
":": { "type": "command.show" }
|
||||
},
|
||||
"search": {
|
||||
"default": "google",
|
||||
"engines": { "google": "https://google.com/search?q={}" }
|
||||
},
|
||||
"properties": {
|
||||
"complete": "bss"
|
||||
}
|
||||
}`,
|
||||
}});
|
||||
new SettingRepository(browser).saveJSON(Settings.fromJSON({
|
||||
properties: { complete: "bss" },
|
||||
}));
|
||||
|
||||
console = await page.showConsole();
|
||||
await console.inputKeys('open ');
|
||||
|
@ -182,5 +155,5 @@ describe("completion on open/tabopen/winopen commands", () => {
|
|||
let titles = completions.filter(x => x.type === 'title').map(x => x.text);
|
||||
assert.deepStrictEqual(titles, ['Bookmarks', 'Search Engines', 'Search Engines'])
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import * as path from 'path';
|
||||
import * as assert from 'assert';
|
||||
|
||||
import settings from './settings';
|
||||
import eventually from './eventually';
|
||||
import { Builder, Lanthan } from 'lanthan';
|
||||
import { WebDriver } from 'selenium-webdriver';
|
||||
|
@ -10,7 +9,6 @@ import Page from './lib/Page';
|
|||
describe("completion on set commands", () => {
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
let browser: any;
|
||||
let page: Page;
|
||||
|
||||
before(async() => {
|
||||
|
@ -19,11 +17,6 @@ describe("completion on set commands", () => {
|
|||
.spyAddon(path.join(__dirname, '..'))
|
||||
.build();
|
||||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
|
||||
await browser.storage.local.set({
|
||||
settings,
|
||||
});
|
||||
});
|
||||
|
||||
after(async() => {
|
||||
|
@ -44,9 +37,9 @@ describe("completion on set commands", () => {
|
|||
let items = await console.getCompletions();
|
||||
assert.strictEqual(items.length, 5);
|
||||
assert.deepStrictEqual(items[0], { type: 'title', text: 'Properties' });
|
||||
assert.ok(items[1].text.startsWith('hintchars'))
|
||||
assert.ok(items[2].text.startsWith('smoothscroll'))
|
||||
assert.ok(items[3].text.startsWith('nosmoothscroll'))
|
||||
assert.ok(items[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'))
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,7 +8,7 @@ import Page from './lib/Page';
|
|||
|
||||
describe("console test", () => {
|
||||
let server = new TestServer().receiveContent('/',
|
||||
`<!DOCTYPE html><html lang="en"><head><title>Hello, world!</title></head></html">`,
|
||||
`<!DOCTYPE html><html lang="en"><head><title>Hello, world!</title></head></html>`,
|
||||
);
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
|
|
@ -14,13 +14,13 @@ const newApp = () => {
|
|||
<!DOCTYPE html>
|
||||
<html lang="en"><body>
|
||||
<a href="hello">hello</a>
|
||||
</body></html">`);
|
||||
</body></html>`);
|
||||
|
||||
server.receiveContent('/follow-input', `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"><body>
|
||||
<input>
|
||||
</body></html">`);
|
||||
</body></html>`);
|
||||
|
||||
server.receiveContent('/area', `
|
||||
<!DOCTYPE html>
|
||||
|
@ -34,7 +34,7 @@ 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
|
||||
|
@ -52,7 +52,7 @@ const newApp = () => {
|
|||
<div><a href="link1">link1</a></div>
|
||||
<div style="min-height:3000px"></div>
|
||||
<div><a href="link2">link2</a></div>
|
||||
</body></html">`);
|
||||
</body></html>`);
|
||||
|
||||
/*
|
||||
* test case 2: link2 and link3 are out of window of the frame
|
||||
|
@ -69,14 +69,14 @@ const newApp = () => {
|
|||
<!DOCTYPE html>
|
||||
<html lang="en"><body>
|
||||
<iframe height="5000" src='/test2-frame'>
|
||||
</body></html">`);
|
||||
</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">`);
|
||||
</body></html>`);
|
||||
|
||||
/* test case 3: link2 is out of window of the frame
|
||||
* +-----------------+
|
||||
|
@ -92,14 +92,14 @@ const newApp = () => {
|
|||
<!DOCTYPE html>
|
||||
<html lang="en"><body>
|
||||
<iframe src='/test3-frame'>
|
||||
</body></html">`);
|
||||
</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;
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ 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;
|
||||
|
|
18
e2e/lib/SettingRepository.ts
Normal file
18
e2e/lib/SettingRepository.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { JSONTextSettings, SettingSource } from '../../src/shared/SettingData';
|
||||
import Settings from '../../src/shared/settings/Settings';
|
||||
|
||||
export default class SettingRepository {
|
||||
constructor(
|
||||
private readonly browser: any,
|
||||
) {
|
||||
}
|
||||
|
||||
async saveJSON(settings: Settings): Promise<void> {
|
||||
await this.browser.storage.local.set({
|
||||
settings: {
|
||||
source: SettingSource.JSON,
|
||||
json: JSONTextSettings.fromSettings(settings).toJSONText(),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import Page from './lib/Page';
|
|||
|
||||
describe("mark test", () => {
|
||||
let server = new TestServer().receiveContent('/',
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html">`,
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`,
|
||||
);
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
|
|
@ -16,7 +16,7 @@ const newApp = () => {
|
|||
<html lang="en">
|
||||
<a href="/pagenation-a/${Number(req.params.page) - 1}">prev</a>
|
||||
<a href="/pagenation-a/${Number(req.params.page) + 1}">next</a>
|
||||
</html">`);
|
||||
</html>`);
|
||||
});
|
||||
|
||||
server.handle('/pagenation-link/:page', (req, res) => {
|
||||
|
@ -27,7 +27,7 @@ const newApp = () => {
|
|||
<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">`);
|
||||
</html>`);
|
||||
});
|
||||
server.receiveContent('/reload', `
|
||||
<!DOCTYPE html>
|
||||
|
@ -36,7 +36,7 @@ const newApp = () => {
|
|||
<script>window.location.hash = Date.now()</script>
|
||||
</head>
|
||||
<body style="width:10000px; height:10000px"></body>
|
||||
</html">`);
|
||||
</html>`);
|
||||
|
||||
server.receiveContent('/*', `ok`);
|
||||
|
||||
|
@ -75,7 +75,7 @@ describe("navigate test", () => {
|
|||
for (let tab of tabs.slice(1)) {
|
||||
await browser.tabs.remove(tab.id);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('should go to parent path without hash by gu', async () => {
|
||||
let page = await Page.navigateTo(webdriver, server.url('/a/b/c'));
|
||||
|
@ -95,7 +95,7 @@ describe("navigate test", () => {
|
|||
await eventually(async() => {
|
||||
let tab = (await browser.tabs.query({}))[0];
|
||||
let url = new URL(tab.url);
|
||||
assert.strictEqual(url.hash, '')
|
||||
assert.strictEqual(url.hash, '');
|
||||
assert.strictEqual(url.pathname, `/a/b/c`)
|
||||
});
|
||||
});
|
||||
|
@ -213,7 +213,7 @@ describe("navigate test", () => {
|
|||
|
||||
await page.sendKeys('r');
|
||||
|
||||
let after
|
||||
let after;
|
||||
await eventually(async() => {
|
||||
let tab = (await browser.tabs.query({}))[0];
|
||||
after = Number(new URL(tab.url).hash.split('#')[1]);
|
||||
|
@ -239,7 +239,7 @@ describe("navigate test", () => {
|
|||
|
||||
await page.sendKeys(Key.SHIFT, 'R');
|
||||
|
||||
let after
|
||||
let after;
|
||||
await eventually(async() => {
|
||||
let tab = (await browser.tabs.query({}))[0];
|
||||
after = Number(new URL(tab.url).hash.split('#')[1]);
|
||||
|
|
|
@ -10,7 +10,7 @@ import OptionPage from './lib/OptionPage';
|
|||
|
||||
describe("options page", () => {
|
||||
let server = new TestServer().receiveContent('/',
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html">`,
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`,
|
||||
);
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
|
@ -39,22 +39,22 @@ describe("options page", () => {
|
|||
for (let tab of tabs.slice(1)) {
|
||||
await browser.tabs.remove(tab.id);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('saves current config on blur', async () => {
|
||||
let page = await OptionPage.open(lanthan);
|
||||
let jsonPage = await page.asJSONOptionPage();
|
||||
await jsonPage.updateSettings(`{ "blacklist": [ "https://example.com" ] }`)
|
||||
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" ] } ')
|
||||
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" ] } ')
|
||||
assert.strictEqual(settings.source, 'json');
|
||||
assert.strictEqual(settings.json, '{ "blacklist": [ "https://example.com" ] } ');
|
||||
|
||||
let message = await jsonPage.getErrorMessage();
|
||||
assert.ok(message.startsWith('SyntaxError:'))
|
||||
|
|
|
@ -19,13 +19,13 @@ describe("options form page", () => {
|
|||
for (let tab of tabs.slice(1)) {
|
||||
await browser.tabs.remove(tab.id);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
afterEach(async() => {
|
||||
if (lanthan) {
|
||||
await lanthan.quit();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
it('switch to form settings', async () => {
|
||||
let page = await OptionPage.open(lanthan);
|
||||
|
@ -33,7 +33,7 @@ describe("options form page", () => {
|
|||
|
||||
let { settings } = await browser.storage.local.get('settings');
|
||||
assert.strictEqual(settings.source, 'form')
|
||||
})
|
||||
});
|
||||
|
||||
it('add blacklist', async () => {
|
||||
let page = await OptionPage.open(lanthan);
|
||||
|
@ -43,20 +43,20 @@ describe("options form page", () => {
|
|||
|
||||
// assert default
|
||||
let settings = (await browser.storage.local.get('settings')).settings;
|
||||
assert.deepStrictEqual(settings.form.blacklist, [])
|
||||
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'])
|
||||
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'])
|
||||
assert.deepStrictEqual(settings.form.blacklist, ['google.com', 'yahoo.com']);
|
||||
|
||||
// delete first item
|
||||
await forms.removeBlackList(0);
|
||||
|
|
58
e2e/partial_blacklist.test.ts
Normal file
58
e2e/partial_blacklist.test.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
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';
|
||||
|
||||
describe("partial blacklist test", () => {
|
||||
let server = new TestServer().receiveContent('/*',
|
||||
`<!DOCTYPE html><html lang="en"><body style="width:10000px; height:10000px"></body></html>`,
|
||||
);
|
||||
let lanthan: Lanthan;
|
||||
let webdriver: WebDriver;
|
||||
let browser: any;
|
||||
|
||||
before(async() => {
|
||||
lanthan = await Builder
|
||||
.forBrowser('firefox')
|
||||
.spyAddon(path.join(__dirname, '..'))
|
||||
.build();
|
||||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
await server.start();
|
||||
|
||||
let url = server.url().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() => {
|
||||
await server.stop();
|
||||
if (lanthan) {
|
||||
await lanthan.quit();
|
||||
}
|
||||
});
|
||||
|
||||
it('should disable keys in the partial blacklist', async () => {
|
||||
let page = await Page.navigateTo(webdriver, server.url('/'));
|
||||
|
||||
await page.sendKeys('j');
|
||||
let scrollY = await page.getScrollY();
|
||||
assert.strictEqual(scrollY, 64);
|
||||
|
||||
await page.sendKeys('k');
|
||||
scrollY = await page.getScrollY();
|
||||
assert.strictEqual(scrollY, 64);
|
||||
});
|
||||
});
|
|
@ -1,86 +0,0 @@
|
|||
export default {
|
||||
source: 'json',
|
||||
json: `{
|
||||
"keymaps": {
|
||||
"0": { "type": "scroll.home" },
|
||||
":": { "type": "command.show" },
|
||||
"o": { "type": "command.show.open", "alter": false },
|
||||
"O": { "type": "command.show.open", "alter": true },
|
||||
"t": { "type": "command.show.tabopen", "alter": false },
|
||||
"T": { "type": "command.show.tabopen", "alter": true },
|
||||
"w": { "type": "command.show.winopen", "alter": false },
|
||||
"W": { "type": "command.show.winopen", "alter": true },
|
||||
"b": { "type": "command.show.buffer" },
|
||||
"a": { "type": "command.show.addbookmark", "alter": true },
|
||||
"k": { "type": "scroll.vertically", "count": -1 },
|
||||
"j": { "type": "scroll.vertically", "count": 1 },
|
||||
"h": { "type": "scroll.horizonally", "count": -1 },
|
||||
"l": { "type": "scroll.horizonally", "count": 1 },
|
||||
"<C-U>": { "type": "scroll.pages", "count": -0.5 },
|
||||
"<C-D>": { "type": "scroll.pages", "count": 0.5 },
|
||||
"<C-B>": { "type": "scroll.pages", "count": -1 },
|
||||
"<C-F>": { "type": "scroll.pages", "count": 1 },
|
||||
"gg": { "type": "scroll.top" },
|
||||
"G": { "type": "scroll.bottom" },
|
||||
"$": { "type": "scroll.end" },
|
||||
"d": { "type": "tabs.close" },
|
||||
"D": { "type": "tabs.close", "select": "left" },
|
||||
"x$": { "type": "tabs.close.right" },
|
||||
"!d": { "type": "tabs.close.force" },
|
||||
"u": { "type": "tabs.reopen" },
|
||||
"K": { "type": "tabs.prev", "count": 1 },
|
||||
"J": { "type": "tabs.next", "count": 1 },
|
||||
"gT": { "type": "tabs.prev", "count": 1 },
|
||||
"gt": { "type": "tabs.next", "count": 1 },
|
||||
"g0": { "type": "tabs.first" },
|
||||
"g$": { "type": "tabs.last" },
|
||||
"<C-6>": { "type": "tabs.prevsel" },
|
||||
"r": { "type": "tabs.reload", "cache": false },
|
||||
"R": { "type": "tabs.reload", "cache": true },
|
||||
"zp": { "type": "tabs.pin.toggle" },
|
||||
"zd": { "type": "tabs.duplicate" },
|
||||
"zi": { "type": "zoom.in" },
|
||||
"zo": { "type": "zoom.out" },
|
||||
"zz": { "type": "zoom.neutral" },
|
||||
"f": { "type": "follow.start", "newTab": false },
|
||||
"F": { "type": "follow.start", "newTab": true, "background": false },
|
||||
"m": { "type": "mark.set.prefix" },
|
||||
"'": { "type": "mark.jump.prefix" },
|
||||
"H": { "type": "navigate.history.prev" },
|
||||
"L": { "type": "navigate.history.next" },
|
||||
"[[": { "type": "navigate.link.prev" },
|
||||
"]]": { "type": "navigate.link.next" },
|
||||
"gu": { "type": "navigate.parent" },
|
||||
"gU": { "type": "navigate.root" },
|
||||
"gi": { "type": "focus.input" },
|
||||
"gf": { "type": "page.source" },
|
||||
"gh": { "type": "page.home" },
|
||||
"gH": { "type": "page.home", "newTab": true },
|
||||
"y": { "type": "urls.yank" },
|
||||
"p": { "type": "urls.paste", "newTab": false },
|
||||
"P": { "type": "urls.paste", "newTab": true },
|
||||
"/": { "type": "find.start" },
|
||||
"n": { "type": "find.next" },
|
||||
"N": { "type": "find.prev" },
|
||||
"<S-Esc>": { "type": "addon.toggle.enabled" }
|
||||
},
|
||||
"search": {
|
||||
"default": "google",
|
||||
"engines": {
|
||||
"google": "http://127.0.0.1:12321/google?q={}",
|
||||
"yahoo": "http://127.0.0.1:12321/yahoo?q={}",
|
||||
"bing": "http://127.0.0.1:12321/bind?q={}",
|
||||
"duckduckgo": "http://127.0.0.1:12321/duplicate?q={}",
|
||||
"twitter": "http://127.0.0.1:12321/twitter?q={}",
|
||||
"wikipedia": "http://127.0.0.1:12321/wikipedia?q={}"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"hintchars": "abcdefghijklmnopqrstuvwxyz",
|
||||
"smoothscroll": false,
|
||||
"complete": "sbh"
|
||||
},
|
||||
"blacklist": [
|
||||
]
|
||||
}`,
|
||||
};
|
|
@ -20,7 +20,7 @@ describe("zoom test", () => {
|
|||
.build();
|
||||
webdriver = lanthan.getWebDriver();
|
||||
browser = lanthan.getWebExtBrowser();
|
||||
tab = (await browser.tabs.query({}))[0]
|
||||
tab = (await browser.tabs.query({}))[0];
|
||||
page = await Page.currentContext(webdriver);
|
||||
});
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ export default class SettingController {
|
|||
async initSettings(): Promise<void> {
|
||||
try {
|
||||
let current = await this.settingUseCase.reload();
|
||||
let disabled = current.blacklist.includes(window.location.href);
|
||||
let url = new URL(window.location.href);
|
||||
let disabled = current.blacklist.includesEntireBlacklist(url);
|
||||
if (disabled) {
|
||||
this.addonEnabledUseCase.disable();
|
||||
} else {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
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';
|
||||
|
@ -31,6 +32,7 @@ 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 });
|
||||
|
|
9
src/content/repositories/AddressRepository.ts
Normal file
9
src/content/repositories/AddressRepository.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export default interface AddressRepository {
|
||||
getCurrentURL(): URL
|
||||
}
|
||||
|
||||
export class AddressRepositoryImpl implements AddressRepository {
|
||||
getCurrentURL(): URL {
|
||||
return new URL(window.location.href);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import * as operations from '../../shared/operations';
|
|||
import Keymaps from '../../shared/settings/Keymaps';
|
||||
import Key from '../../shared/settings/Key';
|
||||
import KeySequence from '../../shared/settings/KeySequence';
|
||||
import AddressRepository from '../repositories/AddressRepository';
|
||||
|
||||
type KeymapEntityMap = Map<KeySequence, operations.Operation>;
|
||||
|
||||
|
@ -25,11 +26,19 @@ export default class KeymapUseCase {
|
|||
|
||||
@inject('AddonEnabledRepository')
|
||||
private addonEnabledRepository: AddonEnabledRepository,
|
||||
|
||||
@inject('AddressRepository')
|
||||
private addressRepository: AddressRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
nextOp(key: Key): operations.Operation | null {
|
||||
let sequence = this.repository.enqueueKey(key);
|
||||
if (sequence.length() === 1 && this.blacklistKey(key)) {
|
||||
// ignore if the input starts with black list keys
|
||||
this.repository.clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
let keymaps = this.keymapEntityMap();
|
||||
let matched = Array.from(keymaps.keys()).filter(
|
||||
|
@ -71,4 +80,10 @@ export default class KeymapUseCase {
|
|||
) as [KeySequence, operations.Operation][];
|
||||
return new Map<KeySequence, operations.Operation>(entries);
|
||||
}
|
||||
|
||||
private blacklistKey(key: Key): boolean {
|
||||
let url = this.addressRepository.getCurrentURL();
|
||||
let blacklist = this.settingRepository.get().blacklist;
|
||||
return blacklist.includeKey(url, key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,17 @@ import './BlacklistForm.scss';
|
|||
import AddButton from '../ui/AddButton';
|
||||
import DeleteButton from '../ui/DeleteButton';
|
||||
import React from 'react';
|
||||
import { BlacklistJSON } from '../../../shared/settings/Blacklist';
|
||||
import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist';
|
||||
|
||||
interface Props {
|
||||
value: BlacklistJSON;
|
||||
onChange: (value: BlacklistJSON) => void;
|
||||
value: Blacklist;
|
||||
onChange: (value: Blacklist) => void;
|
||||
onBlur: () => void;
|
||||
}
|
||||
|
||||
class BlacklistForm extends React.Component<Props> {
|
||||
public static defaultProps: Props = {
|
||||
value: [],
|
||||
value: new Blacklist([]),
|
||||
onChange: () => {},
|
||||
onBlur: () => {},
|
||||
};
|
||||
|
@ -20,24 +20,22 @@ class BlacklistForm extends React.Component<Props> {
|
|||
render() {
|
||||
return <div className='form-blacklist-form'>
|
||||
{
|
||||
this.props.value
|
||||
.map((item, index) => {
|
||||
if (typeof item !== 'string') {
|
||||
// TODO support partial blacklist;
|
||||
return null;
|
||||
}
|
||||
return <div key={index} className='form-blacklist-form-row'>
|
||||
<input data-index={index} type='text' name='url'
|
||||
className='column-url' value={item}
|
||||
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>;
|
||||
})
|
||||
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)} />
|
||||
|
@ -47,17 +45,17 @@ class BlacklistForm extends React.Component<Props> {
|
|||
bindValue(e: any) {
|
||||
let name = e.target.name;
|
||||
let index = e.target.getAttribute('data-index');
|
||||
let next = this.props.value.slice();
|
||||
let items = this.props.value.items;
|
||||
|
||||
if (name === 'url') {
|
||||
next[index] = e.target.value;
|
||||
items[index] = new BlacklistItem(e.target.value, false, []);
|
||||
} else if (name === 'add') {
|
||||
next.push('');
|
||||
items.push(new BlacklistItem('', false, []));
|
||||
} else if (name === 'delete') {
|
||||
next.splice(index, 1);
|
||||
items.splice(index, 1);
|
||||
}
|
||||
|
||||
this.props.onChange(next);
|
||||
this.props.onChange(new Blacklist(items));
|
||||
if (name === 'delete') {
|
||||
this.props.onBlur();
|
||||
}
|
||||
|
|
28
src/settings/components/form/PartialBlacklistForm.scss
Normal file
28
src/settings/components/form/PartialBlacklistForm.scss
Normal file
|
@ -0,0 +1,28 @@
|
|||
.form-partial-blacklist-form {
|
||||
@mixin row-base {
|
||||
display: flex;
|
||||
|
||||
.column-url {
|
||||
flex: 5;
|
||||
min-width: 0;
|
||||
}
|
||||
.column-keys {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.column-delete {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-header {
|
||||
@include row-base;
|
||||
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-row {
|
||||
@include row-base;
|
||||
}
|
||||
}
|
79
src/settings/components/form/PartialBlacklistForm.tsx
Normal file
79
src/settings/components/form/PartialBlacklistForm.tsx
Normal file
|
@ -0,0 +1,79 @@
|
|||
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;
|
||||
onChange: (value: Blacklist) => void;
|
||||
onBlur: () => void;
|
||||
}
|
||||
|
||||
class PartialBlacklistForm extends React.Component<Props> {
|
||||
public static defaultProps: Props = {
|
||||
value: new Blacklist([]),
|
||||
onChange: () => {},
|
||||
onBlur: () => {},
|
||||
};
|
||||
|
||||
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) => {
|
||||
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>;
|
||||
}
|
||||
|
||||
bindValue(e: any) {
|
||||
let name = e.target.name;
|
||||
let index = e.target.getAttribute('data-index');
|
||||
let items = this.props.value.items;
|
||||
|
||||
if (name === 'url') {
|
||||
let current = items[index];
|
||||
items[index] = new BlacklistItem(e.target.value, true, current.keys);
|
||||
} else if (name === 'keys') {
|
||||
let 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') {
|
||||
items.splice(index, 1);
|
||||
}
|
||||
|
||||
this.props.onChange(new Blacklist(items));
|
||||
if (name === 'delete') {
|
||||
this.props.onBlur();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PartialBlacklistForm;
|
|
@ -6,6 +6,7 @@ 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,
|
||||
|
@ -53,7 +54,15 @@ class SettingsComponent extends React.Component<Props> {
|
|||
<fieldset>
|
||||
<legend>Blacklist</legend>
|
||||
<BlacklistForm
|
||||
value={form.blacklist.toJSON()}
|
||||
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)}
|
||||
/>
|
||||
|
@ -138,11 +147,10 @@ class SettingsComponent extends React.Component<Props> {
|
|||
this.props.dispatch(settingActions.set(data));
|
||||
}
|
||||
|
||||
bindBlacklistForm(value: any) {
|
||||
bindBlacklistForm(blacklist: Blacklist) {
|
||||
let data = new SettingData({
|
||||
source: this.props.source,
|
||||
form: (this.props.form as FormSettings).buildWithBlacklist(
|
||||
Blacklist.fromJSON(value)),
|
||||
form: (this.props.form as FormSettings).buildWithBlacklist(blacklist),
|
||||
});
|
||||
this.props.dispatch(settingActions.set(data));
|
||||
}
|
||||
|
|
|
@ -1,39 +1,125 @@
|
|||
export type BlacklistJSON = string[];
|
||||
import Key from './Key';
|
||||
|
||||
const fromWildcard = (pattern: string): RegExp => {
|
||||
export type BlacklistItemJSON = string | {
|
||||
url: string,
|
||||
keys: string[],
|
||||
};
|
||||
|
||||
export type BlacklistJSON = BlacklistItemJSON[];
|
||||
|
||||
const regexFromWildcard = (pattern: string): RegExp => {
|
||||
let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$';
|
||||
return new RegExp(regexStr);
|
||||
};
|
||||
|
||||
const isArrayOfString = (raw: any): boolean => {
|
||||
if (!Array.isArray(raw)) {
|
||||
return false;
|
||||
}
|
||||
for (let x of Array.from(raw)) {
|
||||
if (typeof x !== 'string') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export class BlacklistItem {
|
||||
public readonly pattern: string;
|
||||
|
||||
private regex: RegExp;
|
||||
|
||||
public readonly partial: boolean;
|
||||
|
||||
public readonly keys: string[];
|
||||
|
||||
private readonly keyEntities: Key[];
|
||||
|
||||
constructor(
|
||||
pattern: string,
|
||||
partial: boolean,
|
||||
keys: string[]
|
||||
) {
|
||||
this.pattern = pattern;
|
||||
this.regex = regexFromWildcard(pattern);
|
||||
this.partial = partial;
|
||||
this.keys = keys;
|
||||
this.keyEntities = this.keys.map(Key.fromMapKey);
|
||||
}
|
||||
|
||||
static fromJSON(raw: any): BlacklistItem {
|
||||
if (typeof raw === 'string') {
|
||||
return new BlacklistItem(raw, false, []);
|
||||
} else if (typeof raw === 'object' && raw !== null) {
|
||||
if (!('url' in raw)) {
|
||||
throw new TypeError(
|
||||
`missing field "url" of blacklist item: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
if (typeof raw.url !== 'string') {
|
||||
throw new TypeError(
|
||||
`invalid field "url" of blacklist item: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
if (!('keys' in raw)) {
|
||||
throw new TypeError(
|
||||
`missing field "keys" of blacklist item: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
if (!isArrayOfString(raw.keys)) {
|
||||
throw new TypeError(
|
||||
`invalid field "keys" of blacklist item: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
return new BlacklistItem(raw.url as string, true, raw.keys as string[]);
|
||||
}
|
||||
throw new TypeError(
|
||||
`invalid format of blacklist item: ${JSON.stringify(raw)}`);
|
||||
}
|
||||
|
||||
toJSON(): BlacklistItemJSON {
|
||||
if (!this.partial) {
|
||||
return this.pattern;
|
||||
}
|
||||
return { url: this.pattern, keys: this.keys };
|
||||
}
|
||||
|
||||
matches(url: URL): boolean {
|
||||
return this.pattern.includes('/')
|
||||
? this.regex.test(url.host + url.pathname)
|
||||
: this.regex.test(url.host);
|
||||
}
|
||||
|
||||
includeKey(url: URL, key: Key): boolean {
|
||||
if (!this.matches(url)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.partial) {
|
||||
return true;
|
||||
}
|
||||
return this.keyEntities.some(k => k.equals(key));
|
||||
}
|
||||
}
|
||||
|
||||
export default class Blacklist {
|
||||
constructor(
|
||||
private blacklist: string[],
|
||||
public readonly items: BlacklistItem[],
|
||||
) {
|
||||
}
|
||||
|
||||
static fromJSON(json: any): Blacklist {
|
||||
if (!Array.isArray(json)) {
|
||||
throw new TypeError(`"blacklist" is not an array of string`);
|
||||
throw new TypeError('blacklist is not an array: ' + JSON.stringify(json));
|
||||
}
|
||||
for (let x of json) {
|
||||
if (typeof x !== 'string') {
|
||||
throw new TypeError(`"blacklist" is not an array of string`);
|
||||
}
|
||||
}
|
||||
return new Blacklist(json);
|
||||
let items = Array.from(json).map(item => BlacklistItem.fromJSON(item));
|
||||
return new Blacklist(items);
|
||||
}
|
||||
|
||||
toJSON(): BlacklistJSON {
|
||||
return this.blacklist;
|
||||
return this.items.map(item => item.toJSON());
|
||||
}
|
||||
|
||||
includes(url: string): boolean {
|
||||
let u = new URL(url);
|
||||
return this.blacklist.some((item) => {
|
||||
if (!item.includes('/')) {
|
||||
return fromWildcard(item).test(u.host);
|
||||
}
|
||||
return fromWildcard(item).test(u.host + u.pathname);
|
||||
});
|
||||
includesEntireBlacklist(url: URL): boolean {
|
||||
return this.items.some(item => !item.partial && item.matches(url));
|
||||
}
|
||||
|
||||
includeKey(url: URL, key: Key) {
|
||||
return this.items.some(item => item.includeKey(url, key));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Key from '../../shared/settings/Key';
|
||||
import Key from './Key';
|
||||
|
||||
export default class KeySequence {
|
||||
constructor(
|
||||
|
|
133
test/content/usecases/KeymapUseCase.test.ts
Normal file
133
test/content/usecases/KeymapUseCase.test.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
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 Key from "../../../src/shared/settings/Key";
|
||||
import AddressRepository from "../../../src/content/repositories/AddressRepository";
|
||||
|
||||
class MockSettingRepository implements SettingRepository {
|
||||
constructor(
|
||||
private readonly settings: Settings,
|
||||
) {
|
||||
}
|
||||
|
||||
get(): Settings {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
set(_setting: Settings): void {
|
||||
throw new Error('TODO');
|
||||
}
|
||||
}
|
||||
|
||||
class MockAddonEnabledRepository implements AddonEnabledRepository {
|
||||
constructor(
|
||||
private readonly enabled: boolean,
|
||||
) {
|
||||
}
|
||||
|
||||
get(): boolean {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
set(_on: boolean): void {
|
||||
throw new Error('TODO');
|
||||
}
|
||||
}
|
||||
|
||||
class MockAddressRepository implements AddressRepository {
|
||||
constructor(
|
||||
private url: URL,
|
||||
) {
|
||||
}
|
||||
|
||||
getCurrentURL(): URL {
|
||||
return this.url;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
describe('KeymapUseCase', () => {
|
||||
it('returns matched operation', () => {
|
||||
let settings = Settings.fromJSON({
|
||||
keymaps: {
|
||||
k: {type: 'scroll.vertically', count: -1},
|
||||
j: {type: 'scroll.vertically', count: 1},
|
||||
gg: {type: 'scroll.top'},
|
||||
},
|
||||
});
|
||||
let sut = new KeymapUseCase(
|
||||
new KeymapRepositoryImpl(),
|
||||
new MockSettingRepository(settings),
|
||||
new MockAddonEnabledRepository(true),
|
||||
new MockAddressRepository(new URL('https://example.com')),
|
||||
);
|
||||
|
||||
expect(sut.nextOp(Key.fromMapKey('k'))).to.deep.equal({type: 'scroll.vertically', count: -1});
|
||||
expect(sut.nextOp(Key.fromMapKey('j'))).to.deep.equal({type: 'scroll.vertically', count: 1});
|
||||
expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null;
|
||||
expect(sut.nextOp(Key.fromMapKey('g'))).to.deep.equal({type: 'scroll.top'});
|
||||
expect(sut.nextOp(Key.fromMapKey('z'))).to.be.null;
|
||||
});
|
||||
|
||||
it('returns only ADDON_ENABLE and ADDON_TOGGLE_ENABLED operation', () => {
|
||||
let settings = Settings.fromJSON({
|
||||
keymaps: {
|
||||
k: {type: 'scroll.vertically', count: -1},
|
||||
a: {type: 'addon.enable'},
|
||||
b: {type: 'addon.toggle.enabled'},
|
||||
},
|
||||
});
|
||||
let sut = new KeymapUseCase(
|
||||
new KeymapRepositoryImpl(),
|
||||
new MockSettingRepository(settings),
|
||||
new MockAddonEnabledRepository(false),
|
||||
new MockAddressRepository(new URL('https://example.com')),
|
||||
);
|
||||
|
||||
expect(sut.nextOp(Key.fromMapKey('k'))).to.be.null;
|
||||
expect(sut.nextOp(Key.fromMapKey('a'))).to.deep.equal({type: 'addon.enable'});
|
||||
expect(sut.nextOp(Key.fromMapKey('b'))).to.deep.equal({type: 'addon.toggle.enabled'});
|
||||
});
|
||||
|
||||
it('blocks keys in the partial blacklist', () => {
|
||||
let settings = Settings.fromJSON({
|
||||
keymaps: {
|
||||
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>'] }
|
||||
],
|
||||
});
|
||||
|
||||
let sut = new KeymapUseCase(
|
||||
new KeymapRepositoryImpl(),
|
||||
new MockSettingRepository(settings),
|
||||
new MockAddonEnabledRepository(true),
|
||||
new MockAddressRepository(new URL('https://example.com')),
|
||||
);
|
||||
|
||||
expect(sut.nextOp(Key.fromMapKey('k'))).to.deep.equal({type: 'scroll.vertically', count: -1});
|
||||
expect(sut.nextOp(Key.fromMapKey('j'))).to.deep.equal({type: 'scroll.vertically', count: 1});
|
||||
expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null;
|
||||
expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null;
|
||||
expect(sut.nextOp(Key.fromMapKey('G'))).to.deep.equal({type: 'scroll.bottom'});
|
||||
|
||||
sut = new KeymapUseCase(
|
||||
new KeymapRepositoryImpl(),
|
||||
new MockSettingRepository(settings),
|
||||
new MockAddonEnabledRepository(true),
|
||||
new MockAddressRepository(new URL('https://example.org')),
|
||||
);
|
||||
|
||||
expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null;
|
||||
expect(sut.nextOp(Key.fromMapKey('g'))).to.deep.equal({type: 'scroll.top'});
|
||||
expect(sut.nextOp(Key.fromMapKey('G'))).to.be.null;
|
||||
});
|
||||
});
|
|
@ -2,13 +2,16 @@ import React from 'react';
|
|||
import ReactDOM from 'react-dom';
|
||||
import ReactTestRenderer from 'react-test-renderer';
|
||||
import ReactTestUtils from 'react-dom/test-utils';
|
||||
import BlacklistForm from 'settings/components/form/BlacklistForm'
|
||||
import { expect } from 'chai'
|
||||
|
||||
import BlacklistForm from '../../../../src/settings/components/form/BlacklistForm'
|
||||
import Blacklist from '../../../../src/shared/settings/Blacklist';
|
||||
|
||||
describe("settings/form/BlacklistForm", () => {
|
||||
describe('render', () => {
|
||||
it('renders BlacklistForm', () => {
|
||||
let root = ReactTestRenderer.create(
|
||||
<BlacklistForm value={['*.slack.com', 'www.google.com/maps']} />,
|
||||
<BlacklistForm value={Blacklist.fromJSON(['*.slack.com', 'www.google.com/maps'])} />,
|
||||
).root;
|
||||
|
||||
let children = root.children[0].children;
|
||||
|
@ -43,10 +46,10 @@ describe("settings/form/BlacklistForm", () => {
|
|||
it('invokes onChange event on edit', (done) => {
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(<BlacklistForm
|
||||
value={['*.slack.com', 'www.google.com/maps*']}
|
||||
value={Blacklist.fromJSON(['*.slack.com', 'www.google.com/maps*'])}
|
||||
onChange={value => {
|
||||
expect(value).to.have.lengthOf(2);
|
||||
expect(value).to.have.members(['gitter.im', 'www.google.com/maps*']);
|
||||
let urls = value.items.map(item => item.pattern);
|
||||
expect(urls).to.have.members(['gitter.im', 'www.google.com/maps*']);
|
||||
done();
|
||||
}}
|
||||
/>, container)
|
||||
|
@ -60,10 +63,10 @@ describe("settings/form/BlacklistForm", () => {
|
|||
it('invokes onChange event on delete', (done) => {
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(<BlacklistForm
|
||||
value={['*.slack.com', 'www.google.com/maps*']}
|
||||
value={Blacklist.fromJSON(['*.slack.com', 'www.google.com/maps*'])}
|
||||
onChange={value => {
|
||||
expect(value).to.have.lengthOf(1);
|
||||
expect(value).to.have.members(['www.google.com/maps*']);
|
||||
let urls = value.items.map(item => item.pattern);
|
||||
expect(urls).to.have.members(['www.google.com/maps*']);
|
||||
done();
|
||||
}}
|
||||
/>, container)
|
||||
|
@ -76,10 +79,10 @@ describe("settings/form/BlacklistForm", () => {
|
|||
it('invokes onChange event on add', (done) => {
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(<BlacklistForm
|
||||
value={['*.slack.com']}
|
||||
value={Blacklist.fromJSON(['*.slack.com'])}
|
||||
onChange={value => {
|
||||
expect(value).to.have.lengthOf(2);
|
||||
expect(value).to.have.members(['*.slack.com', '']);
|
||||
let urls = value.items.map(item => item.pattern);
|
||||
expect(urls).to.have.members(['*.slack.com', '']);
|
||||
done();
|
||||
}}
|
||||
/>, container);
|
||||
|
|
|
@ -1,77 +1,158 @@
|
|||
import Blacklist from '../../../src/shared/settings/Blacklist';
|
||||
import Blacklist, { BlacklistItem } from '../../../src/shared/settings/Blacklist';
|
||||
import { expect } from 'chai';
|
||||
import Key from '../../../src/shared/settings/Key';
|
||||
|
||||
describe('Blacklist', () => {
|
||||
describe('fromJSON', () => {
|
||||
it('returns empty array by empty settings', () => {
|
||||
let blacklist = Blacklist.fromJSON([]);
|
||||
expect(blacklist.toJSON()).to.be.empty;
|
||||
describe('BlacklistItem', () => {
|
||||
describe('#fromJSON', () => {
|
||||
it('parses string pattern', () => {
|
||||
let item = BlacklistItem.fromJSON('example.com');
|
||||
expect(item.pattern).to.equal('example.com');
|
||||
expect(item.partial).to.be.false;
|
||||
});
|
||||
|
||||
it('returns blacklist by valid settings', () => {
|
||||
let blacklist = Blacklist.fromJSON([
|
||||
'github.com',
|
||||
'circleci.com',
|
||||
]);
|
||||
|
||||
expect(blacklist.toJSON()).to.deep.equal([
|
||||
'github.com',
|
||||
'circleci.com',
|
||||
]);
|
||||
it('parses partial blacklist item', () => {
|
||||
let 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']);
|
||||
});
|
||||
|
||||
it('throws a TypeError by invalid settings', () => {
|
||||
expect(() => Blacklist.fromJSON(null)).to.throw(TypeError);
|
||||
expect(() => Blacklist.fromJSON({})).to.throw(TypeError);
|
||||
expect(() => Blacklist.fromJSON([1,2,3])).to.throw(TypeError);
|
||||
it('throws a TypeError', () => {
|
||||
expect(() => BlacklistItem.fromJSON(null)).to.throw(TypeError);
|
||||
expect(() => BlacklistItem.fromJSON(100)).to.throw(TypeError);
|
||||
expect(() => BlacklistItem.fromJSON({})).to.throw(TypeError);
|
||||
expect(() => BlacklistItem.fromJSON({url: 'google.com'})).to.throw(TypeError);
|
||||
expect(() => BlacklistItem.fromJSON({keys: ['a']})).to.throw(TypeError);
|
||||
expect(() => BlacklistItem.fromJSON({url: 'google.com', keys: 10})).to.throw(TypeError);
|
||||
expect(() => BlacklistItem.fromJSON({url: 'google.com', keys: ['a', 'b', 3]})).to.throw(TypeError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#includes', () => {
|
||||
it('matches by *', () => {
|
||||
let blacklist = new Blacklist(['*']);
|
||||
|
||||
expect(blacklist.includes('https://github.com/abc')).to.be.true;
|
||||
describe('#matches', () => {
|
||||
it('matches by "*"', () => {
|
||||
let item = BlacklistItem.fromJSON('*');
|
||||
expect(item.matches(new URL('https://github.com/abc'))).to.be.true;
|
||||
});
|
||||
|
||||
it('matches by hostname', () => {
|
||||
let blacklist = new Blacklist(['github.com']);
|
||||
|
||||
expect(blacklist.includes('https://github.com')).to.be.true;
|
||||
expect(blacklist.includes('https://gist.github.com')).to.be.false;
|
||||
expect(blacklist.includes('https://github.com/ueokande')).to.be.true;
|
||||
expect(blacklist.includes('https://github.org')).to.be.false;
|
||||
expect(blacklist.includes('https://google.com/search?q=github.org')).to.be.false;
|
||||
let 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', () => {
|
||||
let blacklist = new Blacklist(['*.github.com']);
|
||||
let item = BlacklistItem.fromJSON('*.github.com');
|
||||
|
||||
expect(blacklist.includes('https://github.com')).to.be.false;
|
||||
expect(blacklist.includes('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', () => {
|
||||
let blacklist = new Blacklist(['github.com/abc']);
|
||||
let item = BlacklistItem.fromJSON('github.com/abc');
|
||||
|
||||
expect(blacklist.includes('https://github.com/abc')).to.be.true;
|
||||
expect(blacklist.includes('https://github.com/abcdef')).to.be.false;
|
||||
expect(blacklist.includes('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', () => {
|
||||
let blacklist = new Blacklist(['github.com/abc*']);
|
||||
let item = BlacklistItem.fromJSON('github.com/abc*');
|
||||
|
||||
expect(blacklist.includes('https://github.com/abc')).to.be.true;
|
||||
expect(blacklist.includes('https://github.com/abcdef')).to.be.true;
|
||||
expect(blacklist.includes('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', () => {
|
||||
let blacklist = new Blacklist(['127.0.0.1:8888']);
|
||||
let item = BlacklistItem.fromJSON('127.0.0.1:8888');
|
||||
|
||||
expect(blacklist.includes('http://127.0.0.1:8888/')).to.be.true;
|
||||
expect(blacklist.includes('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', () => {
|
||||
let 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;
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
describe('#includesPartialKeys', () => {
|
||||
it('matches with partial keys', () => {
|
||||
let 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', () => {
|
||||
let blacklist = Blacklist.fromJSON(['example.com', 'example.org']);
|
||||
expect(blacklist.toJSON()).to.deep.equals([
|
||||
'example.com', 'example.org',
|
||||
]);
|
||||
});
|
||||
|
||||
it('parses mixed blacklist', () => {
|
||||
let blacklist = Blacklist.fromJSON([
|
||||
{ url: 'example.com', keys: ['j', 'k']},
|
||||
'example.org',
|
||||
]);
|
||||
expect(blacklist.toJSON()).to.deep.equals([
|
||||
{ url: 'example.com', keys: ['j', 'k']},
|
||||
'example.org',
|
||||
]);
|
||||
});
|
||||
|
||||
it('parses empty blacklist', () => {
|
||||
let blacklist = Blacklist.fromJSON([]);
|
||||
expect(blacklist.toJSON()).to.deep.equals([]);
|
||||
});
|
||||
|
||||
it('throws a TypeError', () => {
|
||||
expect(() => Blacklist.fromJSON(null)).to.throw(TypeError);
|
||||
expect(() => Blacklist.fromJSON(100)).to.throw(TypeError);
|
||||
expect(() => Blacklist.fromJSON({})).to.throw(TypeError);
|
||||
expect(() => Blacklist.fromJSON([100])).to.throw(TypeError);
|
||||
expect(() => Blacklist.fromJSON([{}])).to.throw(TypeError);
|
||||
})
|
||||
});
|
||||
|
||||
describe('#includesEntireBlacklist', () => {
|
||||
it('matches a url with entire blacklist', () => {
|
||||
let 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', () => {
|
||||
let 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', () => {
|
||||
let blacklist = Blacklist.fromJSON([
|
||||
'google.com',
|
||||
{ url: 'github.com', keys: ['j', 'k'] },
|
||||
]);
|
||||
|
||||
expect(blacklist.includeKey(new URL('https://google.com'), Key.fromMapKey('j'))).to.be.true;
|
||||
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;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Reference in a new issue