aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/background/actions/find.test.js13
-rw-r--r--test/background/reducers/find.test.js19
-rw-r--r--test/background/reducers/setting.test.js36
-rw-r--r--test/console/actions/console.test.js6
-rw-r--r--test/console/reducers/console.test.js6
-rw-r--r--test/content/actions/setting.test.js2
-rw-r--r--test/content/navigates.test.js156
-rw-r--r--test/content/reducers/find.test.js2
-rw-r--r--test/settings/components/form/blacklist-form.test.jsx82
-rw-r--r--test/settings/components/form/keymaps-form.test.jsx53
-rw-r--r--test/settings/components/form/properties-form.test.jsx86
-rw-r--r--test/settings/components/form/search-engine-form.test.jsx104
-rw-r--r--test/settings/components/ui/input.test.jsx83
-rw-r--r--test/shared/commands/parsers.test.js85
-rw-r--r--test/shared/settings/validator.test.js (renamed from test/shared/validators/setting.test.js)2
-rw-r--r--test/shared/settings/values.test.js139
16 files changed, 835 insertions, 39 deletions
diff --git a/test/background/actions/find.test.js b/test/background/actions/find.test.js
new file mode 100644
index 0000000..467604f
--- /dev/null
+++ b/test/background/actions/find.test.js
@@ -0,0 +1,13 @@
+import { expect } from "chai";
+import actions from 'background/actions';
+import * as findActions from 'background/actions/find';
+
+describe("find actions", () => {
+ describe("setKeyword", () => {
+ it('create FIND_SET_KEYWORD action', () => {
+ let action = findActions.setKeyword('banana');
+ expect(action.type).to.equal(actions.FIND_SET_KEYWORD);
+ expect(action.keyword).to.equal('banana');
+ });
+ });
+});
diff --git a/test/background/reducers/find.test.js b/test/background/reducers/find.test.js
new file mode 100644
index 0000000..707d73a
--- /dev/null
+++ b/test/background/reducers/find.test.js
@@ -0,0 +1,19 @@
+import { expect } from "chai";
+import actions from 'background/actions';
+import findReducer from 'background/reducers/find';
+
+describe("find reducer", () => {
+ it('return the initial state', () => {
+ let state = findReducer(undefined, {});
+ expect(state).to.have.deep.property('keyword', null);
+ });
+
+ it('return next state for FIND_SET_KEYWORD', () => {
+ let action = {
+ type: actions.FIND_SET_KEYWORD,
+ keyword: 'cherry',
+ };
+ let state = findReducer(undefined, action);
+ expect(state).to.have.deep.property('keyword', 'cherry')
+ });
+});
diff --git a/test/background/reducers/setting.test.js b/test/background/reducers/setting.test.js
new file mode 100644
index 0000000..8df5abe
--- /dev/null
+++ b/test/background/reducers/setting.test.js
@@ -0,0 +1,36 @@
+import { expect } from "chai";
+import actions from 'background/actions';
+import settingReducer from 'background/reducers/setting';
+
+describe("setting reducer", () => {
+ it('return the initial state', () => {
+ let state = settingReducer(undefined, {});
+ expect(state).to.have.deep.property('value', {});
+ });
+
+ it('return next state for SETTING_SET_SETTINGS', () => {
+ let action = {
+ type: actions.SETTING_SET_SETTINGS,
+ value: { key: 123 },
+ };
+ let state = settingReducer(undefined, action);
+ expect(state).to.have.deep.property('value', { key: 123 });
+ });
+
+ it('return next state for SETTING_SET_PROPERTY', () => {
+ let state = {
+ value: {
+ properties: { smoothscroll: true }
+ }
+ }
+ let action = {
+ type: actions.SETTING_SET_PROPERTY,
+ name: 'encoding',
+ value: 'utf-8',
+ };
+ state = settingReducer(state, action);
+
+ expect(state.value.properties).to.have.property('smoothscroll', true);
+ expect(state.value.properties).to.have.property('encoding', 'utf-8');
+ });
+});
diff --git a/test/console/actions/console.test.js b/test/console/actions/console.test.js
index 9af13d4..1774431 100644
--- a/test/console/actions/console.test.js
+++ b/test/console/actions/console.test.js
@@ -3,6 +3,12 @@ import actions from 'console/actions';
import * as consoleActions from 'console/actions/console';
describe("console actions", () => {
+ describe('hide', () => {
+ it('create CONSOLE_HIDE action', () => {
+ let action = consoleActions.hide();
+ expect(action.type).to.equal(actions.CONSOLE_HIDE);
+ });
+ });
describe("showCommand", () => {
it('create CONSOLE_SHOW_COMMAND action', () => {
let action = consoleActions.showCommand('hello');
diff --git a/test/console/reducers/console.test.js b/test/console/reducers/console.test.js
index 438d513..d196011 100644
--- a/test/console/reducers/console.test.js
+++ b/test/console/reducers/console.test.js
@@ -13,6 +13,12 @@ describe("console reducer", () => {
expect(state).to.have.property('itemSelection', -1);
});
+ it('return next state for CONSOLE_HIDE', () => {
+ let action = { type: actions.CONSOLE_HIDE };
+ let state = reducer({ mode: 'error' }, action);
+ expect(state).to.have.property('mode', '');
+ })
+
it('return next state for CONSOLE_SHOW_COMMAND', () => {
let action = { type: actions.CONSOLE_SHOW_COMMAND, text: 'open ' };
let state = reducer({}, action);
diff --git a/test/content/actions/setting.test.js b/test/content/actions/setting.test.js
index 1248edf..3112b2d 100644
--- a/test/content/actions/setting.test.js
+++ b/test/content/actions/setting.test.js
@@ -23,6 +23,8 @@ describe("setting actions", () => {
let map = new Map(keymaps);
expect(map).to.have.deep.all.keys(
[
+ [{ key: 'Esc', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }],
+ [{ key: '[', shiftKey: false, ctrlKey: true, altKey: false, metaKey: false }],
[{ key: 'd', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
{ key: 'd', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false }],
[{ key: 'z', shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
diff --git a/test/content/navigates.test.js b/test/content/navigates.test.js
index b5144e9..f1f0741 100644
--- a/test/content/navigates.test.js
+++ b/test/content/navigates.test.js
@@ -1,56 +1,138 @@
-import { expect } from "chai";
+import { expect } from 'chai';
import * as navigates from 'content/navigates';
+const testRel = (done, rel, html) => {
+ const method = rel === 'prev' ? 'linkPrev' : 'linkNext';
+ document.body.innerHTML = html;
+ navigates[method](window);
+ setTimeout(() => {
+ expect(document.location.hash).to.equal(`#${rel}`);
+ done();
+ }, 0);
+};
+
+const testPrev = html => done => testRel(done, 'prev', html);
+const testNext = html => done => testRel(done, 'next', html);
+
describe('navigates module', () => {
describe('#linkPrev', () => {
- it('clicks prev link by text content', (done) => {
- document.body.innerHTML = '<a href="#dummy">xprevx</a> <a href="#prev">go to prev</a>';
- navigates.linkPrev(window);
- setTimeout(() => {
- expect(document.location.hash).to.equal('#prev');
- done();
- }, 0);
- });
+ it('navigates to <link> elements whose rel attribute is "prev"', testPrev(
+ '<link rel="prev" href="#prev" />'
+ ));
- it('clicks a[rel=prev] element preferentially', (done) => {
- document.body.innerHTML = '<a href="#dummy">prev</a> <a rel="prev" href="#prev">rel</a>';
- navigates.linkPrev(window);
- setTimeout(() => {
- expect(document.location.hash).to.equal('#prev');
- done();
- }, 0);
- });
- });
+ 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">&lt;&lt;</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('clicks next link by text content', (done) => {
- document.body.innerHTML = '<a href="#dummy">xnextx</a> <a href="#next">go to next</a>';
- navigates.linkNext(window);
- setTimeout(() => {
- expect(document.location.hash).to.equal('#next');
- done();
- }, 0);
- });
+ it('navigates to <link> elements whose rel attribute is "next"', testNext(
+ '<link rel="next" href="#next" />'
+ ));
- it('clicks a[rel=next] element preferentially', (done) => {
- document.body.innerHTML = '<a href="#dummy">next</a> <a rel="next" href="#next">rel</a>';
- navigates.linkNext(window);
- setTimeout(() => {
- expect(document.location.hash).to.equal('#next');
- done();
- }, 0);
- });
+ 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">&gt;&gt;</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('#parent', () => {
// NOTE: not able to test location
it('removes hash', () => {
- window.location.hash = "#section-1";
+ window.location.hash = '#section-1';
navigates.parent(window);
expect(document.location.hash).to.be.empty;
});
});
});
-
-
diff --git a/test/content/reducers/find.test.js b/test/content/reducers/find.test.js
index 93625da..908b01b 100644
--- a/test/content/reducers/find.test.js
+++ b/test/content/reducers/find.test.js
@@ -5,7 +5,7 @@ import findReducer from 'content/reducers/find';
describe("find reducer", () => {
it('return the initial state', () => {
let state = findReducer(undefined, {});
- expect(state).to.have.property('keyword', '');
+ expect(state).to.have.property('keyword', null);
expect(state).to.have.property('found', false);
});
diff --git a/test/settings/components/form/blacklist-form.test.jsx b/test/settings/components/form/blacklist-form.test.jsx
new file mode 100644
index 0000000..95f5cde
--- /dev/null
+++ b/test/settings/components/form/blacklist-form.test.jsx
@@ -0,0 +1,82 @@
+import { expect } from 'chai';
+import { h, render } from 'preact';
+import BlacklistForm from 'settings/components/form/blacklist-form'
+
+describe("settings/form/BlacklistForm", () => {
+ beforeEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ describe('render', () => {
+ it('renders BlacklistForm', () => {
+ render(<BlacklistForm value={['*.slack.com', 'www.google.com/maps']} />, document.body);
+
+ let inputs = document.querySelectorAll('input[type=text]');
+ expect(inputs).to.have.lengthOf(2);
+ expect(inputs[0].value).to.equal('*.slack.com');
+ expect(inputs[1].value).to.equal('www.google.com/maps');
+ });
+
+ it('renders blank value', () => {
+ render(<BlacklistForm />, document.body);
+
+ let inputs = document.querySelectorAll('input[type=text]');
+ expect(inputs).to.be.empty;
+ });
+
+ it('renders blank value', () => {
+ render(<BlacklistForm />, document.body);
+
+ let inputs = document.querySelectorAll('input[type=text]');
+ expect(inputs).to.be.empty;
+ });
+ });
+
+ describe('onChange', () => {
+ it('invokes onChange event on edit', (done) => {
+ render(<BlacklistForm
+ value={['*.slack.com', 'www.google.com/maps*']}
+ onChange={value => {
+ expect(value).to.have.lengthOf(2)
+ .and.have.members(['gitter.im', 'www.google.com/maps*']);
+
+ done();
+ }}
+ />, document.body);
+
+ let input = document.querySelectorAll('input[type=text]')[0];
+ input.value = 'gitter.im';
+ input.dispatchEvent(new Event('change'))
+ });
+
+ it('invokes onChange event on delete', (done) => {
+ render(<BlacklistForm
+ value={['*.slack.com', 'www.google.com/maps*']}
+ onChange={value => {
+ expect(value).to.have.lengthOf(1)
+ .and.have.members(['www.google.com/maps*']);
+
+ done();
+ }}
+ />, document.body);
+
+ let button = document.querySelectorAll('input[type=button]')[0];
+ button.click();
+ });
+
+ it('invokes onChange event on add', (done) => {
+ render(<BlacklistForm
+ value={['*.slack.com']}
+ onChange={value => {
+ expect(value).to.have.lengthOf(2)
+ .and.have.members(['*.slack.com', '']);
+
+ done();
+ }}
+ />, document.body);
+
+ let button = document.querySelector('input[type=button].ui-add-button');
+ button.click();
+ });
+ });
+});
diff --git a/test/settings/components/form/keymaps-form.test.jsx b/test/settings/components/form/keymaps-form.test.jsx
new file mode 100644
index 0000000..e9f9359
--- /dev/null
+++ b/test/settings/components/form/keymaps-form.test.jsx
@@ -0,0 +1,53 @@
+import { expect } from 'chai';
+import { h, render } from 'preact';
+import KeymapsForm from 'settings/components/form/keymaps-form'
+
+describe("settings/form/KeymapsForm", () => {
+ beforeEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ describe('render', () => {
+ it('renders KeymapsForm', () => {
+ render(<KeymapsForm value={{
+ 'scroll.vertically?{"count":1}': 'j',
+ 'scroll.vertically?{"count":-1}': 'k',
+ }} />, document.body);
+
+ let inputj = document.getElementById('scroll.vertically?{"count":1}');
+ let inputk = document.getElementById('scroll.vertically?{"count":-1}');
+
+ expect(inputj.value).to.equal('j');
+ expect(inputk.value).to.equal('k');
+ });
+
+ it('renders blank value', () => {
+ render(<KeymapsForm />, document.body);
+
+ let inputj = document.getElementById('scroll.vertically?{"count":1}');
+ let inputk = document.getElementById('scroll.vertically?{"count":-1}');
+
+ expect(inputj.value).to.be.empty;
+ expect(inputk.value).to.be.empty;
+ });
+ });
+
+ describe('onChange event', () => {
+ it('invokes onChange event on edit', (done) => {
+ render(<KeymapsForm
+ value={{
+ 'scroll.vertically?{"count":1}': 'j',
+ 'scroll.vertically?{"count":-1}': 'k',
+ }}
+ onChange={value => {
+ expect(value['scroll.vertically?{"count":1}']).to.equal('jjj');
+
+ done();
+ }} />, document.body);
+
+ let input = document.getElementById('scroll.vertically?{"count":1}');
+ input.value = 'jjj';
+ input.dispatchEvent(new Event('change'))
+ });
+ });
+});
diff --git a/test/settings/components/form/properties-form.test.jsx b/test/settings/components/form/properties-form.test.jsx
new file mode 100644
index 0000000..4807361
--- /dev/null
+++ b/test/settings/components/form/properties-form.test.jsx
@@ -0,0 +1,86 @@
+import { expect } from 'chai';
+import { h, render } from 'preact';
+import PropertiesForm from 'settings/components/form/properties-form'
+
+describe("settings/form/PropertiesForm", () => {
+ beforeEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ describe('render', () => {
+ it('renders PropertiesForm', () => {
+ let types = {
+ mystr: 'string',
+ mynum: 'number',
+ mybool: 'boolean',
+ empty: 'string',
+ }
+ let value = {
+ mystr: 'abc',
+ mynum: 123,
+ mybool: true,
+ };
+ render(<PropertiesForm types={types} value={value} />, document.body);
+
+ let strInput = document.querySelector('input[name=mystr]');
+ let numInput = document.querySelector('input[name=mynum]');
+ let boolInput = document.querySelector('input[name=mybool]');
+ let emptyInput = document.querySelector('input[name=empty]');
+
+ expect(strInput.type).to.equals('text');
+ expect(strInput.value).to.equal('abc');
+ expect(numInput.type).to.equals('number');
+ expect(numInput.value).to.equal('123');
+ expect(boolInput.type).to.equals('checkbox');
+ expect(boolInput.checked).to.be.true;
+ expect(emptyInput.type).to.equals('text');
+ expect(emptyInput.value).to.be.empty;
+ });
+ });
+
+ describe('onChange', () => {
+ it('invokes onChange event on text changed', (done) => {
+ render(<PropertiesForm
+ types={{ 'myvalue': 'string' }}
+ value={{ 'myvalue': 'abc' }}
+ onChange={value => {
+ expect(value).to.have.property('myvalue', 'abcd');
+ done();
+ }}
+ />, document.body);
+
+ let input = document.querySelector('input[name=myvalue]');
+ input.value = 'abcd'
+ input.dispatchEvent(new Event('change'))
+ });
+
+ it('invokes onChange event on number changeed', (done) => {
+ render(<PropertiesForm
+ types={{ 'myvalue': 'number' }}
+ value={{ '': 123 }}
+ onChange={value => {
+ expect(value).to.have.property('myvalue', 1234);
+ done();
+ }}
+ />, document.body);
+
+ let input = document.querySelector('input[name=myvalue]');
+ input.value = '1234'
+ input.dispatchEvent(new Event('change'))
+ });
+
+ it('invokes onChange event on checkbox changed', (done) => {
+ render(<PropertiesForm
+ types={{ 'myvalue': 'boolean' }}
+ value={{ 'myvalue': false }}
+ onChange={value => {
+ expect(value).to.have.property('myvalue', true);
+ done();
+ }}
+ />, document.body);
+
+ let input = document.querySelector('input[name=myvalue]');
+ input.click();
+ });
+ });
+});
diff --git a/test/settings/components/form/search-engine-form.test.jsx b/test/settings/components/form/search-engine-form.test.jsx
new file mode 100644
index 0000000..9600cae
--- /dev/null
+++ b/test/settings/components/form/search-engine-form.test.jsx
@@ -0,0 +1,104 @@
+import { expect } from 'chai';
+import { h, render } from 'preact';
+import SearchForm from 'settings/components/form/search-form'
+
+describe("settings/form/SearchForm", () => {
+ beforeEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ describe('render', () => {
+ it('renders SearchForm', () => {
+ render(<SearchForm value={{
+ default: 'google',
+ engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']],
+ }} />, document.body);
+
+ let names = document.querySelectorAll('input[name=name]');
+ expect(names).to.have.lengthOf(2);
+ expect(names[0].value).to.equal('google');
+ expect(names[1].value).to.equal('yahoo');
+
+ let urls = document.querySelectorAll('input[name=url]');
+ expect(urls).to.have.lengthOf(2);
+ expect(urls[0].value).to.equal('google.com');
+ expect(urls[1].value).to.equal('yahoo.com');
+ });
+
+ it('renders blank value', () => {
+ render(<SearchForm />, document.body);
+
+ let names = document.querySelectorAll('input[name=name]');
+ let urls = document.querySelectorAll('input[name=url]');
+ expect(names).to.have.lengthOf(0);
+ expect(urls).to.have.lengthOf(0);
+ });
+
+ it('renders blank engines', () => {
+ render(<SearchForm value={{ default: 'google' }} />, document.body);
+
+ let names = document.querySelectorAll('input[name=name]');
+ let urls = document.querySelectorAll('input[name=url]');
+ expect(names).to.have.lengthOf(0);
+ expect(urls).to.have.lengthOf(0);
+ });
+ });
+
+ describe('onChange event', () => {
+ it('invokes onChange event on edit', (done) => {
+ render(<SearchForm
+ value={{
+ default: 'google',
+ engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']]
+ }}
+ onChange={value => {
+ expect(value.default).to.equal('louvre');
+ expect(value.engines).to.have.lengthOf(2)
+ .and.have.deep.members([['louvre', 'google.com'], ['yahoo', 'yahoo.com']])
+
+ done();
+ }} />, document.body);
+
+ let radio = document.querySelectorAll('input[type=radio]');
+ radio.checked = true;
+
+ let name = document.querySelector('input[name=name]');
+ name.value = 'louvre';
+ name.dispatchEvent(new Event('change'))
+ });
+
+ it('invokes onChange event on delete', (done) => {
+ render(<SearchForm value={{
+ default: 'yahoo',
+ engines: [['louvre', 'google.com'], ['yahoo', 'yahoo.com']]
+ }}
+ onChange={value => {
+ expect(value.default).to.equal('yahoo');
+ expect(value.engines).to.have.lengthOf(1)
+ .and.have.deep.members([['yahoo', 'yahoo.com']])
+
+ done();
+ }} />, document.body);
+
+ let button = document.querySelector('input[type=button]');
+ button.click();
+ });
+
+ it('invokes onChange event on add', (done) => {
+ render(<SearchForm value={{
+ default: 'yahoo',
+ engines: [['google', 'google.com']]
+ }}
+ onChange={value => {
+ expect(value.default).to.equal('yahoo');
+ expect(value.engines).to.have.lengthOf(2)
+ .and.have.deep.members([['google', 'google.com'], ['', '']])
+
+ done();
+ }} />, document.body);
+
+ let button = document.querySelector('input[type=button].ui-add-button');
+ button.click();
+ });
+ });
+});
diff --git a/test/settings/components/ui/input.test.jsx b/test/settings/components/ui/input.test.jsx
new file mode 100644
index 0000000..98f2cef
--- /dev/null
+++ b/test/settings/components/ui/input.test.jsx
@@ -0,0 +1,83 @@
+import { expect } from 'chai';
+import { h, render } from 'preact';
+import Input from 'settings/components/ui/input'
+
+describe("settings/ui/Input", () => {
+ beforeEach(() => {
+ document.body.innerHTML = '';
+ });
+
+ context("type=text", () => {
+ it('renders text input', () => {
+ render(<Input type='text' name='myname' label='myfield' value='myvalue'/>, document.body)
+
+ let label = document.querySelector('label');
+ let 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) => {
+ render(<Input type='text' name='myname' label='myfield' value='myvalue' onChange={(e) => {
+ expect(e.target.value).to.equal('newvalue');
+ done();
+ }}/>, document.body);
+
+ let input = document.querySelector('input');
+ input.value = 'newvalue';
+ input.dispatchEvent(new Event('change'))
+ });
+ });
+
+ context("type=radio", () => {
+ it('renders radio button', () => {
+ render(<Input type='radio' name='myname' label='myfield' value='myvalue'/>, document.body)
+
+ let label = document.querySelector('label');
+ let 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) => {
+ render(<Input type='text' name='radio' label='myfield' value='myvalue' onChange={(e) => {
+ expect(e.target.checked).to.be.true;
+ done();
+ }}/>, document.body);
+
+ let input = document.querySelector('input');
+ input.checked = true;
+ input.dispatchEvent(new Event('change'))
+ });
+ });
+
+ context("type=textarea", () => {
+ it('renders textarea button', () => {
+ render(<Input type='textarea' name='myname' label='myfield' value='myvalue' error='myerror' />, document.body)
+
+ let label = document.querySelector('label');
+ let textarea = document.querySelector('textarea');
+ let 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) => {
+ render(<Input type='textarea' name='myname' label='myfield' value='myvalue' onChange={(e) => {
+ expect(e.target.value).to.equal('newvalue');
+ done();
+ }}/>, document.body);
+
+ let input = document.querySelector('textarea');
+ input.value = 'newvalue'
+ input.dispatchEvent(new Event('change'))
+ });
+ });
+});
diff --git a/test/shared/commands/parsers.test.js b/test/shared/commands/parsers.test.js
new file mode 100644
index 0000000..0a1960c
--- /dev/null
+++ b/test/shared/commands/parsers.test.js
@@ -0,0 +1,85 @@
+import { expect } from "chai";
+import * as parsers from 'shared/commands/parsers';
+
+describe("shared/commands/parsers", () => {
+ describe("#parsers.parseSetOption", () => {
+ it('parse set string', () => {
+ let [key, value] = parsers.parseSetOption('encoding=utf-8', { encoding: 'string' });
+ expect(key).to.equal('encoding');
+ expect(value).to.equal('utf-8');
+ });
+
+ it('parse set empty string', () => {
+ let [key, value] = parsers.parseSetOption('encoding=', { encoding: 'string' });
+ expect(key).to.equal('encoding');
+ expect(value).to.equal('');
+ });
+
+ it('parse set string', () => {
+ let [key, value] = parsers.parseSetOption('history=50', { history: 'number' });
+ expect(key).to.equal('history');
+ expect(value).to.equal(50);
+ });
+
+ it('parse set boolean', () => {
+ let [key, value] = parsers.parseSetOption('paste', { paste: 'boolean' });
+ expect(key).to.equal('paste');
+ expect(value).to.be.true;
+
+ [key, value] = parsers.parseSetOption('nopaste', { paste: 'boolean' });
+ expect(key).to.equal('paste');
+ expect(value).to.be.false;
+ });
+
+ it('throws error on unknown property', () => {
+ expect(() => parsers.parseSetOption('charset=utf-8', {})).to.throw(Error, 'Unknown');
+ expect(() => parsers.parseSetOption('smoothscroll', {})).to.throw(Error, 'Unknown');
+ expect(() => parsers.parseSetOption('nosmoothscroll', {})).to.throw(Error, 'Unknown');
+ })
+
+ it('throws error on invalid property', () => {
+ expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'number' })).to.throw(Error, 'Not number');
+ expect(() => parsers.parseSetOption('charset=utf-8', { charset: 'boolean' })).to.throw(Error, 'Invalid');
+ expect(() => parsers.parseSetOption('charset=', { charset: 'boolean' })).to.throw(Error, 'Invalid');
+ expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'string' })).to.throw(Error, 'Invalid');
+ expect(() => parsers.parseSetOption('smoothscroll', { smoothscroll: 'number' })).to.throw(Error, 'Invalid');
+ })
+ });
+
+ describe('#normalizeUrl', () => {
+ const config = {
+ default: 'google',
+ engines: {
+ google: 'https://google.com/search?q={}',
+ yahoo: 'https://yahoo.com/search?q={}',
+ }
+ };
+
+ it('convertes search url', () => {
+ expect(parsers.normalizeUrl(['google', 'apple'], config))
+ .to.equal('https://google.com/search?q=apple');
+ expect(parsers.normalizeUrl(['yahoo', 'apple'], config))
+ .to.equal('https://yahoo.com/search?q=apple');
+ expect(parsers.normalizeUrl(['google', 'apple', 'banana'], config))
+ .to.equal('https://google.com/search?q=apple%20banana');
+ expect(parsers.normalizeUrl(['yahoo', 'C++CLI'], config))
+ .to.equal('https://yahoo.com/search?q=C%2B%2BCLI');
+ });
+
+ it('user default search engine', () => {
+ expect(parsers.normalizeUrl(['apple', 'banana'], config))
+ .to.equal('https://google.com/search?q=apple%20banana');
+ });
+ });
+
+ describe('#parseCommandLine', () => {
+ it('parse command line as name and args', () => {
+ expect(parsers.parseCommandLine('open google apple')).to.deep.equal(['open', ['google', 'apple']]);
+ expect(parsers.parseCommandLine(' open google apple ')).to.deep.equal(['open', ['google', 'apple']]);
+ expect(parsers.parseCommandLine('')).to.deep.equal(['', []]);
+ expect(parsers.parseCommandLine(' ')).to.deep.equal(['', []]);
+ expect(parsers.parseCommandLine('exit')).to.deep.equal(['exit', []]);
+ expect(parsers.parseCommandLine(' exit ')).to.deep.equal(['exit', []]);
+ });
+ });
+});
diff --git a/test/shared/validators/setting.test.js b/test/shared/settings/validator.test.js
index 15d6a10..61d976a 100644
--- a/test/shared/validators/setting.test.js
+++ b/test/shared/settings/validator.test.js
@@ -1,5 +1,5 @@
import { expect } from "chai";
-import { validate } from 'shared/validators/setting';
+import { validate } from 'shared/settings/validator';
describe("setting validator", () => {
describe("unknown top keys", () => {
diff --git a/test/shared/settings/values.test.js b/test/shared/settings/values.test.js
new file mode 100644
index 0000000..62cfb5f
--- /dev/null
+++ b/test/shared/settings/values.test.js
@@ -0,0 +1,139 @@
+import { expect } from 'chai';
+import * as values from 'shared/settings/values';
+
+describe("settings values", () => {
+ describe('valueFromJson', () => {
+ it('return object from json string', () => {
+ let json = `{
+ "keymaps": { "0": {"type": "scroll.home"}},
+ "search": { "default": "google", "engines": { "google": "https://google.com/search?q={}" }},
+ "blacklist": [ "*.slack.com"],
+ "properties": {
+ "mystr": "value",
+ "mynum": 123,
+ "mybool": true
+ }
+ }`;
+ let value = values.valueFromJson(json);
+
+ expect(value.keymaps).to.deep.equal({ 0: {type: "scroll.home"}});
+ expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} });
+ expect(value.blacklist).to.deep.equal(["*.slack.com"]);
+ expect(value.properties).to.have.property('mystr', 'value');
+ expect(value.properties).to.have.property('mynum', 123);
+ expect(value.properties).to.have.property('mybool', true);
+ });
+ });
+
+ describe('valueFromForm', () => {
+ it('returns value from form', () => {
+ let form = {
+ keymaps: {
+ 'scroll.vertically?{"count":1}': 'j',
+ 'scroll.home': '0',
+ },
+ search: {
+ default: 'google',
+ engines: [['google', 'https://google.com/search?q={}']],
+ },
+ blacklist: ['*.slack.com'],
+ "properties": {
+ "mystr": "value",
+ "mynum": 123,
+ "mybool": true,
+ }
+ };
+ let value = values.valueFromForm(form);
+
+ expect(value.keymaps).to.have.deep.property('j', { type: "scroll.vertically", count: 1 });
+ expect(value.keymaps).to.have.deep.property('0', { type: "scroll.home" });
+ expect(JSON.stringify(value.search)).to.deep.equal(JSON.stringify({ default: "google", engines: { google: "https://google.com/search?q={}"} }));
+ expect(value.search).to.deep.equal({ default: "google", engines: { google: "https://google.com/search?q={}"} });
+ expect(value.blacklist).to.deep.equal(["*.slack.com"]);
+ expect(value.properties).to.have.property('mystr', 'value');
+ expect(value.properties).to.have.property('mynum', 123);
+ expect(value.properties).to.have.property('mybool', true);
+ });
+
+ it('convert from empty form', () => {
+ let form = {};
+ let value = values.valueFromForm(form);
+ expect(value).to.not.have.key('keymaps');
+ expect(value).to.not.have.key('search');
+ expect(value).to.not.have.key('blacklist');
+ expect(value).to.not.have.key('properties');
+ });
+
+ it('override keymaps', () => {
+ let form = {
+ keymaps: {
+ 'scroll.vertically?{"count":1}': 'j',
+ 'scroll.vertically?{"count":-1}': 'j',
+ }
+ };
+ let value = values.valueFromForm(form);
+
+ expect(value.keymaps).to.have.key('j');
+ });
+
+ it('override search engine', () => {
+ let form = {
+ search: {
+ default: 'google',
+ engines: [
+ ['google', 'https://google.com/search?q={}'],
+ ['google', 'https://google.co.jp/search?q={}'],
+ ]
+ }
+ };
+ let value = values.valueFromForm(form);
+
+ expect(value.search.engines).to.have.property('google', 'https://google.co.jp/search?q={}');
+ });
+ });
+
+ describe('jsonFromValue', () => {
+ });
+
+ describe('formFromValue', () => {
+ it('convert empty value to form', () => {
+ let value = {};
+ let form = values.formFromValue(value);
+
+ expect(value).to.not.have.key('keymaps');
+ expect(value).to.not.have.key('search');
+ expect(value).to.not.have.key('blacklist');
+ });
+
+ it('convert value to form', () => {
+ let value = {
+ keymaps: {
+ j: { type: 'scroll.vertically', count: 1 },
+ JJ: { type: 'scroll.vertically', count: 100 },
+ 0: { type: 'scroll.home' },
+ },
+ search: { default: 'google', engines: { google: 'https://google.com/search?q={}' }},
+ blacklist: [ '*.slack.com'],
+ properties: {
+ "mystr": "value",
+ "mynum": 123,
+ "mybool": true,
+ }
+ };
+ let allowed = ['scroll.vertically?{"count":1}', 'scroll.home' ];
+ let form = values.formFromValue(value, allowed);
+
+ expect(form.keymaps).to.have.property('scroll.vertically?{"count":1}', 'j');
+ expect(form.keymaps).to.not.have.property('scroll.vertically?{"count":100}');
+ expect(form.keymaps).to.have.property('scroll.home', '0');
+ expect(Object.keys(form.keymaps)).to.have.lengthOf(2);
+ expect(form.search).to.have.property('default', 'google');
+ expect(form.search).to.have.deep.property('engines', [['google', 'https://google.com/search?q={}']]);
+ expect(form.blacklist).to.have.lengthOf(1);
+ expect(form.blacklist).to.include('*.slack.com');
+ expect(form.properties).to.have.property('mystr', 'value');
+ expect(form.properties).to.have.property('mynum', 123);
+ expect(form.properties).to.have.property('mybool', true);
+ });
+ });
+});