From be900aa25ca205c467dcbbab9c284ef680441996 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 29 Apr 2019 15:27:23 +0900 Subject: Clean settings components --- src/settings/components/form/BlacklistForm.jsx | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/settings/components/form/BlacklistForm.jsx (limited to 'src/settings/components/form/BlacklistForm.jsx') diff --git a/src/settings/components/form/BlacklistForm.jsx b/src/settings/components/form/BlacklistForm.jsx new file mode 100644 index 0000000..13571f1 --- /dev/null +++ b/src/settings/components/form/BlacklistForm.jsx @@ -0,0 +1,52 @@ +import './BlacklistForm.scss'; +import AddButton from '../ui/AddButton'; +import DeleteButton from '../ui/DeleteButton'; +import React from 'react'; + +class BlacklistForm extends React.Component { + + render() { + let value = this.props.value; + if (!value) { + value = []; + } + + return
+ { + value.map((url, index) => { + return
+ + +
; + }) + } + +
; + } + + bindValue(e) { + if (!this.props.onChange) { + return; + } + + let name = e.target.name; + let index = e.target.getAttribute('data-index'); + let next = this.props.value ? this.props.value.slice() : []; + + if (name === 'url') { + next[index] = e.target.value; + } else if (name === 'add') { + next.push(''); + } else if (name === 'delete') { + next.splice(index, 1); + } + + this.props.onChange(next); + } +} + +export default BlacklistForm; -- cgit v1.2.3 From ee078c677bbb7756636898830f766465d426f68b Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 29 Apr 2019 15:47:42 +0900 Subject: Declare types on settings --- src/settings/components/form/BlacklistForm.jsx | 6 ++++++ src/settings/components/form/KeymapsForm.jsx | 6 ++++++ src/settings/components/form/PropertiesForm.jsx | 6 ++++++ src/settings/components/form/SearchForm.jsx | 10 ++++++++++ src/settings/components/ui/Input.jsx | 8 ++++++++ 5 files changed, 36 insertions(+) (limited to 'src/settings/components/form/BlacklistForm.jsx') diff --git a/src/settings/components/form/BlacklistForm.jsx b/src/settings/components/form/BlacklistForm.jsx index 13571f1..7dad9ee 100644 --- a/src/settings/components/form/BlacklistForm.jsx +++ b/src/settings/components/form/BlacklistForm.jsx @@ -2,6 +2,7 @@ import './BlacklistForm.scss'; import AddButton from '../ui/AddButton'; import DeleteButton from '../ui/DeleteButton'; import React from 'react'; +import PropTypes from 'prop-types'; class BlacklistForm extends React.Component { @@ -49,4 +50,9 @@ class BlacklistForm extends React.Component { } } +BlacklistForm.propTypes = { + value: PropTypes.arrayOf(PropTypes.string), + onChange: PropTypes.func, +}; + export default BlacklistForm; diff --git a/src/settings/components/form/KeymapsForm.jsx b/src/settings/components/form/KeymapsForm.jsx index 25a3710..f5444fc 100644 --- a/src/settings/components/form/KeymapsForm.jsx +++ b/src/settings/components/form/KeymapsForm.jsx @@ -1,5 +1,6 @@ import './KeymapsForm.scss'; import React from 'react'; +import PropTypes from 'prop-types'; import Input from '../ui/Input'; import keymaps from '../../keymaps'; @@ -44,4 +45,9 @@ class KeymapsForm extends React.Component { } } +KeymapsForm.propTypes = { + value: PropTypes.objectOf(PropTypes.string), + onChange: PropTypes.func, +}; + export default KeymapsForm; diff --git a/src/settings/components/form/PropertiesForm.jsx b/src/settings/components/form/PropertiesForm.jsx index 77991fc..9143a7a 100644 --- a/src/settings/components/form/PropertiesForm.jsx +++ b/src/settings/components/form/PropertiesForm.jsx @@ -1,5 +1,6 @@ import './PropertiesForm.scss'; import React from 'react'; +import PropTypes from 'prop-types'; class PropertiesForm extends React.Component { @@ -57,4 +58,9 @@ class PropertiesForm extends React.Component { } } +PropertiesForm.propTypes = { + value: PropTypes.objectOf(PropTypes.any), + onChange: PropTypes.func, +}; + export default PropertiesForm; diff --git a/src/settings/components/form/SearchForm.jsx b/src/settings/components/form/SearchForm.jsx index f52fd5f..718cca1 100644 --- a/src/settings/components/form/SearchForm.jsx +++ b/src/settings/components/form/SearchForm.jsx @@ -1,5 +1,6 @@ import './SearchForm.scss'; import React from 'react'; +import PropTypes from 'prop-types'; import AddButton from '../ui/AddButton'; import DeleteButton from '../ui/DeleteButton'; @@ -75,4 +76,13 @@ class SearchForm extends React.Component { } } +SearchForm.propTypes = { + value: PropTypes.shape({ + default: PropTypes.string, + engines: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)), + }), + onChange: PropTypes.func, + +}; + export default SearchForm; diff --git a/src/settings/components/ui/Input.jsx b/src/settings/components/ui/Input.jsx index d090f5b..13a246b 100644 --- a/src/settings/components/ui/Input.jsx +++ b/src/settings/components/ui/Input.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import './Input.scss'; class Input extends React.Component { @@ -49,4 +50,11 @@ class Input extends React.Component { } } +Input.propTypes = { + type: PropTypes.string, + error: PropTypes.string, + label: PropTypes.string, + value: PropTypes.string, +}; + export default Input; -- cgit v1.2.3 From 808344eecfedd04149551867724e46a7988c45a0 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 30 Apr 2019 09:03:01 +0900 Subject: Fix React Component tests --- karma.conf.js | 1 + src/settings/components/form/BlacklistForm.jsx | 11 +- src/settings/components/form/KeymapsForm.jsx | 10 +- src/settings/components/form/SearchForm.jsx | 6 +- .../console/components/console/Completion.test.jsx | 168 +++++++++++++++++++++ .../console/components/console/completion.test.jsx | 138 ----------------- .../components/form/BlacklistForm.test.jsx | 92 +++++++++++ test/settings/components/form/KeymapsForm.test.jsx | 64 ++++++++ .../components/form/PropertiesForm.test.jsx | 104 +++++++++++++ .../components/form/SearchEngineForm.test.jsx | 128 ++++++++++++++++ .../components/form/blacklist-form.test.jsx | 81 ---------- .../settings/components/form/keymaps-form.test.jsx | 52 ------- .../components/form/properties-form.test.jsx | 85 ----------- .../components/form/search-engine-form.test.jsx | 103 ------------- test/settings/components/ui/input.test.jsx | 71 ++++++--- 15 files changed, 620 insertions(+), 494 deletions(-) create mode 100644 test/console/components/console/Completion.test.jsx delete mode 100644 test/console/components/console/completion.test.jsx create mode 100644 test/settings/components/form/BlacklistForm.test.jsx create mode 100644 test/settings/components/form/KeymapsForm.test.jsx create mode 100644 test/settings/components/form/PropertiesForm.test.jsx create mode 100644 test/settings/components/form/SearchEngineForm.test.jsx delete mode 100644 test/settings/components/form/blacklist-form.test.jsx delete mode 100644 test/settings/components/form/keymaps-form.test.jsx delete mode 100644 test/settings/components/form/properties-form.test.jsx delete mode 100644 test/settings/components/form/search-engine-form.test.jsx (limited to 'src/settings/components/form/BlacklistForm.jsx') diff --git a/karma.conf.js b/karma.conf.js index 5e69f9e..32da469 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -29,6 +29,7 @@ module.exports = function (config) { singleRun: true, webpack: { + mode: 'development', devtool: 'inline-source-map', resolve: webpackConfig.resolve, module: webpackConfig.module diff --git a/src/settings/components/form/BlacklistForm.jsx b/src/settings/components/form/BlacklistForm.jsx index 7dad9ee..cee04bd 100644 --- a/src/settings/components/form/BlacklistForm.jsx +++ b/src/settings/components/form/BlacklistForm.jsx @@ -7,14 +7,9 @@ import PropTypes from 'prop-types'; class BlacklistForm extends React.Component { render() { - let value = this.props.value; - if (!value) { - value = []; - } - return
{ - value.map((url, index) => { + this.props.value.map((url, index) => { return
{ keymaps.fields.map((group, index) => { @@ -19,7 +15,7 @@ class KeymapsForm extends React.Component { group.map((field) => { let name = field[0]; let label = field[1]; - let value = values[name]; + let value = this.props.value[name] || ''; return { + let completions = [{ + name: "Fruit", + items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], + }, { + name: "Element", + items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], + }]; + + it('renders Completion component', () => { + let root = ReactTestRenderer.create().root; + + expect(root.children).to.have.lengthOf(1); + + let children = root.children[0].children; + expect(children).to.have.lengthOf(8); + expect(children[0].props.title).to.equal('Fruit'); + expect(children[1].props.caption).to.equal('apple'); + expect(children[2].props.caption).to.equal('banana'); + expect(children[3].props.caption).to.equal('cherry'); + expect(children[4].props.title).to.equal('Element'); + expect(children[5].props.caption).to.equal('argon'); + expect(children[6].props.caption).to.equal('boron'); + expect(children[7].props.caption).to.equal('carbon'); + }); + + it('highlight current item', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + expect(children[5].props.highlight).to.be.true; + }); + + it('does not highlight any items', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + for (let li of children[0].children) { + expect(li.props.highlight).not.to.be.ok; + } + }); + + it('limits completion items', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + + expect(children[0].props.title).to.equal('Fruit'); + expect(children[1].props.caption).to.equal('apple'); + expect(children[2].props.caption).to.equal('banana'); + + root = ReactTestRenderer.create().root; + + children = root.children[0].children; + expect(children[1].props.highlight).to.be.true; + }) + + it('scrolls up to down with select', () => { + let component = ReactTestRenderer.create(); + let instance = component.getInstance(); + let root = component.root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.title).to.equal('Fruit'); + expect(children[1].props.caption).to.equal('apple'); + expect(children[2].props.caption).to.equal('banana'); + + component.update(); + + children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.caption).to.equal('apple'); + expect(children[1].props.caption).to.equal('banana'); + expect(children[2].props.caption).to.equal('cherry'); + expect(children[2].props.highlight).to.be.true; + + component.update(); + + children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.caption).to.equal('cherry'); + expect(children[1].props.title).to.equal('Element'); + expect(children[2].props.caption).to.equal('argon'); + expect(children[2].props.highlight).to.be.true; + }); + + it('scrolls down to up with select', () => { + let component = ReactTestRenderer.create(); + let root = component.root; + let instance = component.getInstance(); + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].props.caption).to.equal('argon'); + expect(children[1].props.caption).to.equal('boron'); + expect(children[2].props.caption).to.equal('carbon'); + + component.update(); + + children = root.children[0].children; + expect(children[1].props.highlight).to.be.true; + + component.update(); + + children = root.children[0].children; + expect(children[0].props.highlight).to.be.true; + + component.update(); + + children = root.children[0].children; + expect(children[0].props.caption).to.equal('cherry'); + expect(children[1].props.title).to.equal('Element'); + expect(children[2].props.caption).to.equal('argon'); + expect(children[0].props.highlight).to.be.true; + }); +}); diff --git a/test/console/components/console/completion.test.jsx b/test/console/components/console/completion.test.jsx deleted file mode 100644 index 8d81ce8..0000000 --- a/test/console/components/console/completion.test.jsx +++ /dev/null @@ -1,138 +0,0 @@ -import { render } from 'react'; -import Completion from 'console/components/console/completion' - -describe("console/components/console/completion", () => { - let completions = [{ - name: "Fruit", - items: [{ caption: "apple" }, { caption: "banana" }, { caption: "cherry" }], - }, { - name: "Element", - items: [{ caption: "argon" }, { caption: "boron" }, { caption: "carbon" }], - }]; - - beforeEach(() => { - document.body.innerHTML = ''; - }); - - it('renders Completion component', () => { - let ul = render(, document.body); - - expect(ul.children).to.have.lengthOf(8); - expect(ul.children[0].textContent).to.equal('Fruit'); - expect(ul.children[1].textContent).to.equal('apple'); - expect(ul.children[2].textContent).to.equal('banana'); - expect(ul.children[3].textContent).to.equal('cherry'); - expect(ul.children[4].textContent).to.equal('Element'); - expect(ul.children[5].textContent).to.equal('argon'); - expect(ul.children[6].textContent).to.equal('boron'); - expect(ul.children[7].textContent).to.equal('carbon'); - }); - - it('highlight current item', () => { - let ul = render(, document.body); - expect(ul.children[5].className.split(' ')).to.include('vimvixen-completion-selected'); - }); - - it('does not highlight any items', () => { - let ul = render(, document.body); - for (let li of ul.children) { - expect(li.className.split(' ')).not.to.include('vimvixen-completion-selected'); - } - }); - - - it('limits completion items', () => { - let ul = render(, document.body); - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); - - ul = render(, document.body, ul); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); - expect(ul.children[1].className.split(' ')).to.include('vimvixen-completion-selected'); - }) - - it('scrolls up to down with select', () => { - let ul = render(, document.body); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']); - expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - - ul = render(, document.body, ul); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['apple', 'banana', 'cherry']); - expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - - ul = render(, document.body, ul); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['cherry', 'Element', 'argon']); - expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - }); - - it('scrolls up to down with select', () => { - let ul = render(, document.body); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); - expect(ul.children[2].className.split(' ')).to.include('vimvixen-completion-selected'); - - ul = render(, document.body, ul); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); - expect(ul.children[1].className.split(' ')).to.include('vimvixen-completion-selected'); - - ul = render(, document.body, ul); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['argon', 'boron', 'carbon']); - expect(ul.children[0].className.split(' ')).to.include('vimvixen-completion-selected'); - - ul = render(, document.body, ul); - - expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['cherry', 'Element', 'argon']); - expect(ul.children[0].className.split(' ')).to.include('vimvixen-completion-selected'); - }); -}); diff --git a/test/settings/components/form/BlacklistForm.test.jsx b/test/settings/components/form/BlacklistForm.test.jsx new file mode 100644 index 0000000..2be5d96 --- /dev/null +++ b/test/settings/components/form/BlacklistForm.test.jsx @@ -0,0 +1,92 @@ +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' + +describe("settings/form/BlacklistForm", () => { + describe('render', () => { + it('renders BlacklistForm', () => { + let root = ReactTestRenderer.create( + , + ).root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(3); + expect(children[0].children[0].props.value).to.equal('*.slack.com'); + expect(children[1].children[0].props.value).to.equal('www.google.com/maps'); + expect(children[2].props.name).to.equal('add'); + }); + + it('renders blank value', () => { + let root = ReactTestRenderer.create().root; + + let children = root.children[0].children; + expect(children).to.have.lengthOf(1); + expect(children[0].props.name).to.equal('add'); + }); + }); + + describe('onChange', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on edit', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.lengthOf(2); + expect(value).to.have.members(['gitter.im', 'www.google.com/maps*']); + done(); + }} + />, container) + }); + + let input = document.querySelectorAll('input[type=text]')[0]; + input.value = 'gitter.im'; + ReactTestUtils.Simulate.change(input); + }); + + it('invokes onChange event on delete', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.lengthOf(1); + expect(value).to.have.members(['www.google.com/maps*']); + done(); + }} + />, container) + }); + + let button = document.querySelectorAll('input[type=button]')[0]; + ReactTestUtils.Simulate.click(button); + }); + + it('invokes onChange event on add', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.lengthOf(2); + expect(value).to.have.members(['*.slack.com', '']); + done(); + }} + />, container); + }); + + let button = document.querySelector('input[type=button].ui-add-button'); + ReactTestUtils.Simulate.click(button); + }); + }); +}); diff --git a/test/settings/components/form/KeymapsForm.test.jsx b/test/settings/components/form/KeymapsForm.test.jsx new file mode 100644 index 0000000..6ac57c9 --- /dev/null +++ b/test/settings/components/form/KeymapsForm.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import KeymapsForm from 'settings/components/form/KeymapsForm' + +describe("settings/form/KeymapsForm", () => { + describe('render', () => { + it('renders keymap fields', () => { + let root = ReactTestRenderer.create().root + + let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); + let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); + + expect(inputj.props.value).to.equal('j'); + expect(inputk.props.value).to.equal('k'); + }); + + it('renders blank value', () => { + let root = ReactTestRenderer.create().root; + + let inputj = root.findByProps({ id: 'scroll.vertically?{"count":1}' }); + let inputk = root.findByProps({ id: 'scroll.vertically?{"count":-1}' }); + + expect(inputj.props.value).to.be.empty; + expect(inputk.props.value).to.be.empty; + }); + }); + + describe('onChange event', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on edit', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value['scroll.vertically?{"count":1}']).to.equal('jjj'); + done(); + }} />, container); + }); + + let input = document.getElementById('scroll.vertically?{"count":1}'); + input.value = 'jjj'; + ReactTestUtils.Simulate.change(input); + }); + }); +}); diff --git a/test/settings/components/form/PropertiesForm.test.jsx b/test/settings/components/form/PropertiesForm.test.jsx new file mode 100644 index 0000000..80f60d2 --- /dev/null +++ b/test/settings/components/form/PropertiesForm.test.jsx @@ -0,0 +1,104 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import PropertiesForm from 'settings/components/form/PropertiesForm' + +describe("settings/form/PropertiesForm", () => { + describe('render', () => { + it('renders PropertiesForm', () => { + let types = { + mystr: 'string', + mynum: 'number', + mybool: 'boolean', + empty: 'string', + } + let value = { + mystr: 'abc', + mynum: 123, + mybool: true, + }; + + let root = ReactTestRenderer.create( + , + ).root + + let input = root.findByProps({ name: 'mystr' }); + expect(input.props.type).to.equals('text'); + expect(input.props.value).to.equal('abc'); + + input = root.findByProps({ name: 'mynum' }); + expect(input.props.type).to.equals('number'); + expect(input.props.value).to.equal(123); + + input = root.findByProps({ name: 'mybool' }); + expect(input.props.type).to.equals('checkbox'); + expect(input.props.value).to.equal(true); + }); + }); + + describe('onChange', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on text changed', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.property('myvalue', 'abcd'); + done(); + }} + />, container); + }); + + let input = document.querySelector('input[name=myvalue]'); + input.value = 'abcd' + ReactTestUtils.Simulate.change(input); + }); + + it('invokes onChange event on number changeed', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.property('myvalue', 1234); + done(); + }} + />, container); + }); + + let input = document.querySelector('input[name=myvalue]'); + input.value = '1234' + ReactTestUtils.Simulate.change(input); + }); + + it('invokes onChange event on checkbox changed', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value).to.have.property('myvalue', true); + done(); + }} + />, container); + }); + + let input = document.querySelector('input[name=myvalue]'); + input.checked = true; + ReactTestUtils.Simulate.change(input); + }); + }); +}); diff --git a/test/settings/components/form/SearchEngineForm.test.jsx b/test/settings/components/form/SearchEngineForm.test.jsx new file mode 100644 index 0000000..06822f2 --- /dev/null +++ b/test/settings/components/form/SearchEngineForm.test.jsx @@ -0,0 +1,128 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestRenderer from 'react-test-renderer'; +import ReactTestUtils from 'react-dom/test-utils'; +import SearchForm from 'settings/components/form/SearchForm' + +describe("settings/form/SearchForm", () => { + describe('render', () => { + it('renders SearchForm', () => { + let root = ReactTestRenderer.create().root; + + let names = root.findAllByProps({ name: 'name' }); + expect(names).to.have.lengthOf(2); + expect(names[0].props.value).to.equal('google'); + expect(names[1].props.value).to.equal('yahoo'); + + let urls = root.findAllByProps({ name: 'url' }); + expect(urls).to.have.lengthOf(2); + expect(urls[0].props.value).to.equal('google.com'); + expect(urls[1].props.value).to.equal('yahoo.com'); + }); + + it('renders blank value', () => { + let root = ReactTestRenderer.create().root; + + let names = root.findAllByProps({ name: 'name' }); + expect(names).to.be.empty; + + let urls = root.findAllByProps({ name: 'url' }); + expect(urls).to.be.empty; + }); + + it('renders blank engines', () => { + let root = ReactTestRenderer.create( + , + ).root; + + let names = root.findAllByProps({ name: 'name' }); + expect(names).to.be.empty; + + let urls = root.findAllByProps({ name: 'url' }); + expect(urls).to.be.empty; + }); + }); + + describe('onChange event', () => { + let container; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; + }); + + it('invokes onChange event on edit', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value.default).to.equal('louvre'); + expect(value.engines).to.have.lengthOf(2) + expect(value.engines).to.have.deep.members( + [['louvre', 'google.com'], ['yahoo', 'yahoo.com']] + ); + done(); + }} />, container); + }); + + let radio = document.querySelectorAll('input[type=radio]'); + radio.checked = true; + + let name = document.querySelector('input[name=name]'); + name.value = 'louvre'; + + ReactTestUtils.Simulate.change(name); + }); + + it('invokes onChange event on delete', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value.default).to.equal('yahoo'); + expect(value.engines).to.have.lengthOf(1) + expect(value.engines).to.have.deep.members( + [['yahoo', 'yahoo.com']] + ); + done(); + }} />, container); + }); + + let button = document.querySelector('input[type=button]'); + ReactTestUtils.Simulate.click(button); + }); + + it('invokes onChange event on add', (done) => { + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(value.default).to.equal('yahoo'); + expect(value.engines).to.have.lengthOf(2) + expect(value.engines).to.have.deep.members( + [['google', 'google.com'], ['', '']], + ); + done(); + }} />, container); + }); + + let button = document.querySelector('input[type=button].ui-add-button'); + ReactTestUtils.Simulate.click(button); + }); + }); +}); diff --git a/test/settings/components/form/blacklist-form.test.jsx b/test/settings/components/form/blacklist-form.test.jsx deleted file mode 100644 index 40067d0..0000000 --- a/test/settings/components/form/blacklist-form.test.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import { render } from 'react'; -import BlacklistForm from 'settings/components/form/blacklist-form' - -describe("settings/form/BlacklistForm", () => { - beforeEach(() => { - document.body.innerHTML = ''; - }); - - describe('render', () => { - it('renders BlacklistForm', () => { - render(, 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(, document.body); - - let inputs = document.querySelectorAll('input[type=text]'); - expect(inputs).to.be.empty; - }); - - it('renders blank value', () => { - render(, document.body); - - let inputs = document.querySelectorAll('input[type=text]'); - expect(inputs).to.be.empty; - }); - }); - - describe('onChange', () => { - it('invokes onChange event on edit', (done) => { - render( { - 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( { - 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( { - 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 deleted file mode 100644 index 79d8d20..0000000 --- a/test/settings/components/form/keymaps-form.test.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import { render } from 'react'; -import KeymapsForm from 'settings/components/form/keymaps-form' - -describe("settings/form/KeymapsForm", () => { - beforeEach(() => { - document.body.innerHTML = ''; - }); - - describe('render', () => { - it('renders KeymapsForm', () => { - render(, 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(, 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( { - 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 deleted file mode 100644 index 171dcb6..0000000 --- a/test/settings/components/form/properties-form.test.jsx +++ /dev/null @@ -1,85 +0,0 @@ -import { render } from 'react'; -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(, 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( { - 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( { - 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( { - 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 deleted file mode 100644 index d1cbb30..0000000 --- a/test/settings/components/form/search-engine-form.test.jsx +++ /dev/null @@ -1,103 +0,0 @@ -import { render } from 'react'; -import SearchForm from 'settings/components/form/search-form' - -describe("settings/form/SearchForm", () => { - beforeEach(() => { - document.body.innerHTML = ''; - }); - - describe('render', () => { - it('renders SearchForm', () => { - render(, 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(, 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(, 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( { - 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( { - 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( { - 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 index db12bf8..432efcb 100644 --- a/test/settings/components/ui/input.test.jsx +++ b/test/settings/components/ui/input.test.jsx @@ -1,14 +1,28 @@ -import { render } from 'react'; -import Input from 'settings/components/ui/input' +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactTestUtils from 'react-dom/test-utils'; +import Input from 'settings/components/ui/Input' describe("settings/ui/Input", () => { + let container; + beforeEach(() => { - document.body.innerHTML = ''; + container = document.createElement('div'); + document.body.appendChild(container); + }); + + afterEach(() => { + document.body.removeChild(container); + container = null; }); context("type=text", () => { it('renders text input', () => { - render(, document.body) + ReactTestUtils.act(() => { + ReactDOM.render( + , + container); + }); let label = document.querySelector('label'); let input = document.querySelector('input'); @@ -19,20 +33,26 @@ describe("settings/ui/Input", () => { }); it('invoke onChange', (done) => { - render( { - expect(e.target.value).to.equal('newvalue'); - done(); - }}/>, document.body); + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(e.target.value).to.equal('newvalue'); + done(); + }}/>, container); + }); let input = document.querySelector('input'); input.value = 'newvalue'; - input.dispatchEvent(new Event('change')) + ReactTestUtils.Simulate.change(input); }); }); context("type=radio", () => { it('renders radio button', () => { - render(, document.body) + ReactTestUtils.act(() => { + ReactDOM.render( + , + container); + }); let label = document.querySelector('label'); let input = document.querySelector('input'); @@ -43,20 +63,27 @@ describe("settings/ui/Input", () => { }); it('invoke onChange', (done) => { - render( { - expect(e.target.checked).to.be.true; - done(); - }}/>, document.body); + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(e.target.checked).to.be.true; + done(); + }}/>, + container); + }); let input = document.querySelector('input'); input.checked = true; - input.dispatchEvent(new Event('change')) + ReactTestUtils.Simulate.change(input); }); }); context("type=textarea", () => { it('renders textarea button', () => { - render(, document.body) + ReactTestUtils.act(() => { + ReactDOM.render( + , + container); + }); let label = document.querySelector('label'); let textarea = document.querySelector('textarea'); @@ -69,14 +96,16 @@ describe("settings/ui/Input", () => { }); it('invoke onChange', (done) => { - render( { - expect(e.target.value).to.equal('newvalue'); - done(); - }}/>, document.body); + ReactTestUtils.act(() => { + ReactDOM.render( { + expect(e.target.value).to.equal('newvalue'); + done(); + }}/>, container); + }); let input = document.querySelector('textarea'); input.value = 'newvalue' - input.dispatchEvent(new Event('change')) + ReactTestUtils.Simulate.change(input); }); }); }); -- cgit v1.2.3 From fce2434dcdef126a3ab180447e7cb48bc24ec1f9 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 30 Apr 2019 09:15:58 +0900 Subject: Specify default props --- src/settings/components/form/BlacklistForm.jsx | 5 +---- src/settings/components/form/KeymapsForm.jsx | 5 +---- src/settings/components/form/PropertiesForm.jsx | 12 +++++------- src/settings/components/form/SearchForm.jsx | 5 +---- 4 files changed, 8 insertions(+), 19 deletions(-) (limited to 'src/settings/components/form/BlacklistForm.jsx') diff --git a/src/settings/components/form/BlacklistForm.jsx b/src/settings/components/form/BlacklistForm.jsx index cee04bd..cf7cffe 100644 --- a/src/settings/components/form/BlacklistForm.jsx +++ b/src/settings/components/form/BlacklistForm.jsx @@ -25,10 +25,6 @@ class BlacklistForm extends React.Component { } bindValue(e) { - if (!this.props.onChange) { - return; - } - let name = e.target.name; let index = e.target.getAttribute('data-index'); let next = this.props.value ? this.props.value.slice() : []; @@ -52,6 +48,7 @@ BlacklistForm.propTypes = { BlacklistForm.defaultProps = { value: [], + onChange: () => {}, }; export default BlacklistForm; diff --git a/src/settings/components/form/KeymapsForm.jsx b/src/settings/components/form/KeymapsForm.jsx index 26a22d7..5bb65cb 100644 --- a/src/settings/components/form/KeymapsForm.jsx +++ b/src/settings/components/form/KeymapsForm.jsx @@ -30,10 +30,6 @@ class KeymapsForm extends React.Component { } bindValue(e) { - if (!this.props.onChange) { - return; - } - let next = { ...this.props.value }; next[e.target.name] = e.target.value; @@ -48,6 +44,7 @@ KeymapsForm.propTypes = { KeymapsForm.defaultProps = { value: {}, + onChange: () => {}, }; export default KeymapsForm; diff --git a/src/settings/components/form/PropertiesForm.jsx b/src/settings/components/form/PropertiesForm.jsx index 9143a7a..0014899 100644 --- a/src/settings/components/form/PropertiesForm.jsx +++ b/src/settings/components/form/PropertiesForm.jsx @@ -7,9 +7,6 @@ class PropertiesForm extends React.Component { render() { let types = this.props.types; let value = this.props.value; - if (!value) { - value = {}; - } return
{ @@ -40,10 +37,6 @@ class PropertiesForm extends React.Component { } bindValue(e) { - if (!this.props.onChange) { - return; - } - let name = e.target.name; let next = { ...this.props.value }; if (e.target.type.toLowerCase() === 'checkbox') { @@ -63,4 +56,9 @@ PropertiesForm.propTypes = { onChange: PropTypes.func, }; +PropertiesForm.defaultProps = { + value: {}, + onChange: () => {}, +}; + export default PropertiesForm; diff --git a/src/settings/components/form/SearchForm.jsx b/src/settings/components/form/SearchForm.jsx index 2e070fc..d2f2d48 100644 --- a/src/settings/components/form/SearchForm.jsx +++ b/src/settings/components/form/SearchForm.jsx @@ -44,10 +44,6 @@ class SearchForm extends React.Component { } bindValue(e) { - if (!this.props.onChange) { - return; - } - let value = this.props.value; let name = e.target.name; let index = e.target.getAttribute('data-index'); @@ -83,6 +79,7 @@ SearchForm.propTypes = { SearchForm.defaultProps = { value: { default: '', engines: []}, + onChange: () => {}, }; export default SearchForm; -- cgit v1.2.3 From 20f79f1da54441fe22a172009d34734af1bd3807 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Tue, 30 Apr 2019 09:49:45 +0900 Subject: Save settings by onBlur callback --- src/settings/actions/setting.js | 2 +- src/settings/components/form/BlacklistForm.jsx | 13 +++++++++++-- src/settings/components/form/KeymapsForm.jsx | 1 + src/settings/components/form/PropertiesForm.jsx | 1 + src/settings/components/form/SearchForm.jsx | 11 +++++++++-- src/settings/components/index.jsx | 11 +++++++++-- 6 files changed, 32 insertions(+), 7 deletions(-) (limited to 'src/settings/components/form/BlacklistForm.jsx') diff --git a/src/settings/actions/setting.js b/src/settings/actions/setting.js index 8844252..db63a45 100644 --- a/src/settings/actions/setting.js +++ b/src/settings/actions/setting.js @@ -60,4 +60,4 @@ const set = (settings) => { }; }; -export { load, save, switchToForm, switchToJson }; +export { load, save, set, switchToForm, switchToJson }; diff --git a/src/settings/components/form/BlacklistForm.jsx b/src/settings/components/form/BlacklistForm.jsx index cf7cffe..c470758 100644 --- a/src/settings/components/form/BlacklistForm.jsx +++ b/src/settings/components/form/BlacklistForm.jsx @@ -13,9 +13,13 @@ class BlacklistForm extends React.Component { return
+ onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + />
; }) } @@ -38,17 +42,22 @@ class BlacklistForm extends React.Component { } this.props.onChange(next); + if (name === 'delete') { + this.props.onBlur(); + } } } BlacklistForm.propTypes = { value: PropTypes.arrayOf(PropTypes.string), onChange: PropTypes.func, + onBlur: PropTypes.func, }; BlacklistForm.defaultProps = { value: [], onChange: () => {}, + onBlur: () => {}, }; export default BlacklistForm; diff --git a/src/settings/components/form/KeymapsForm.jsx b/src/settings/components/form/KeymapsForm.jsx index 5bb65cb..01acf61 100644 --- a/src/settings/components/form/KeymapsForm.jsx +++ b/src/settings/components/form/KeymapsForm.jsx @@ -20,6 +20,7 @@ class KeymapsForm extends React.Component { type='text' id={name} name={name} key={name} label={label} value={value} onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} />; }) } diff --git a/src/settings/components/form/PropertiesForm.jsx b/src/settings/components/form/PropertiesForm.jsx index 0014899..979fdd8 100644 --- a/src/settings/components/form/PropertiesForm.jsx +++ b/src/settings/components/form/PropertiesForm.jsx @@ -27,6 +27,7 @@ class PropertiesForm extends React.Component { className='column-input' value={value[name] ? value[name] : ''} onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} checked={value[name]} /> diff --git a/src/settings/components/form/SearchForm.jsx b/src/settings/components/form/SearchForm.jsx index d2f2d48..6b0bd01 100644 --- a/src/settings/components/form/SearchForm.jsx +++ b/src/settings/components/form/SearchForm.jsx @@ -23,11 +23,15 @@ class SearchForm extends React.Component { return
+ onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + />
this.bindForm('keymaps', value)} + onBlur={this.save.bind(this)} />
@@ -32,6 +33,7 @@ class SettingsComponent extends React.Component { this.bindForm('search', value)} + onBlur={this.save.bind(this)} />
@@ -39,6 +41,7 @@ class SettingsComponent extends React.Component { this.bindForm('blacklist', value)} + onBlur={this.save.bind(this)} />
@@ -47,6 +50,7 @@ class SettingsComponent extends React.Component { types={properties.types} value={form.properties} onChange={value => this.bindForm('properties', value)} + onBlur={this.save.bind(this)} />
; @@ -61,6 +65,7 @@ class SettingsComponent extends React.Component { spellCheck='false' error={error} onChange={this.bindJson.bind(this)} + onBlur={this.save.bind(this)} value={json} />
; @@ -109,7 +114,7 @@ class SettingsComponent extends React.Component { form: { ...this.props.form }, }; settings.form[name] = value; - this.props.dispatch(settingActions.save(settings)); + this.props.dispatch(settingActions.set(settings)); } bindJson(e) { @@ -118,7 +123,7 @@ class SettingsComponent extends React.Component { json: e.target.value, form: this.props.form, }; - this.props.dispatch(settingActions.save(settings)); + this.props.dispatch(settingActions.set(settings)); } bindSource(e) { @@ -135,7 +140,9 @@ class SettingsComponent extends React.Component { } this.props.dispatch(settingActions.switchToForm(this.props.json)); } + } + save() { let settings = this.props.store.getState(); this.props.dispatch(settingActions.save(settings)); } -- cgit v1.2.3