commit
457d954e08
42 changed files with 1706 additions and 1488 deletions
|
@ -29,6 +29,7 @@ module.exports = function (config) {
|
|||
singleRun: true,
|
||||
|
||||
webpack: {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
resolve: webpackConfig.resolve,
|
||||
module: webpackConfig.module
|
||||
|
|
1590
package-lock.json
generated
1590
package-lock.json
generated
File diff suppressed because it is too large
Load diff
14
package.json
14
package.json
|
@ -20,11 +20,11 @@
|
|||
},
|
||||
"homepage": "https://github.com/ueokande/vim-vixen",
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"@babel/cli": "^7.4.4",
|
||||
"@babel/core": "^7.4.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-preset-preact": "^1.1.0",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"babel-loader": "^8.0.5",
|
||||
"chai": "^4.2.0",
|
||||
"css-loader": "^2.1.1",
|
||||
"eslint": "^5.16.0",
|
||||
|
@ -42,8 +42,10 @@
|
|||
"lanthan": "git+https://github.com/ueokande/lanthan.git#master",
|
||||
"mocha": "^6.1.4",
|
||||
"node-sass": "^4.12.0",
|
||||
"preact": "^8.4.2",
|
||||
"preact-redux": "^2.0.3",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-redux": "^7.0.3",
|
||||
"react-test-renderer": "^16.8.6",
|
||||
"redux": "^4.0.1",
|
||||
"redux-promise": "^0.6.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
|
|
|
@ -19,9 +19,9 @@ export default class Completions {
|
|||
}));
|
||||
}
|
||||
|
||||
static EMPTY_COMPLETIONS = new Completions([]);
|
||||
|
||||
static empty() {
|
||||
return Completions.EMPTY_COMPLETIONS;
|
||||
return EMPTY_COMPLETIONS;
|
||||
}
|
||||
}
|
||||
|
||||
let EMPTY_COMPLETIONS = new Completions([]);
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import './console.scss';
|
||||
import { connect } from 'preact-redux';
|
||||
import { Component, h } from 'preact';
|
||||
import Input from './console/input';
|
||||
import Completion from './console/completion';
|
||||
import Message from './console/message';
|
||||
import { connect } from 'react-redux';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Input from './console/Input';
|
||||
import Completion from './console/Completion';
|
||||
import Message from './console/Message';
|
||||
import * as consoleActions from '../../console/actions/console';
|
||||
|
||||
const COMPLETION_MAX_ITEMS = 33;
|
||||
|
||||
class ConsoleComponent extends Component {
|
||||
class Console extends React.Component {
|
||||
onBlur() {
|
||||
if (this.props.mode === 'command' || this.props.mode === 'find') {
|
||||
return this.context.store.dispatch(consoleActions.hideCommand());
|
||||
return this.props.dispatch(consoleActions.hideCommand());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,45 +22,45 @@ class ConsoleComponent extends Component {
|
|||
|
||||
let value = e.target.value;
|
||||
if (this.props.mode === 'command') {
|
||||
return this.context.store.dispatch(consoleActions.enterCommand(value));
|
||||
return this.props.dispatch(consoleActions.enterCommand(value));
|
||||
} else if (this.props.mode === 'find') {
|
||||
return this.context.store.dispatch(consoleActions.enterFind(value));
|
||||
return this.props.dispatch(consoleActions.enterFind(value));
|
||||
}
|
||||
}
|
||||
|
||||
selectNext(e) {
|
||||
this.context.store.dispatch(consoleActions.completionNext());
|
||||
this.props.dispatch(consoleActions.completionNext());
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
selectPrev(e) {
|
||||
this.context.store.dispatch(consoleActions.completionPrev());
|
||||
this.props.dispatch(consoleActions.completionPrev());
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
onKeyDown(e) {
|
||||
if (e.keyCode === KeyboardEvent.DOM_VK_ESCAPE && e.ctrlKey) {
|
||||
this.context.store.dispatch(consoleActions.hideCommand());
|
||||
this.props.dispatch(consoleActions.hideCommand());
|
||||
}
|
||||
switch (e.keyCode) {
|
||||
case KeyboardEvent.DOM_VK_ESCAPE:
|
||||
return this.context.store.dispatch(consoleActions.hideCommand());
|
||||
return this.props.dispatch(consoleActions.hideCommand());
|
||||
case KeyboardEvent.DOM_VK_RETURN:
|
||||
return this.doEnter(e);
|
||||
case KeyboardEvent.DOM_VK_TAB:
|
||||
if (e.shiftKey) {
|
||||
this.context.store.dispatch(consoleActions.completionPrev());
|
||||
this.props.dispatch(consoleActions.completionPrev());
|
||||
} else {
|
||||
this.context.store.dispatch(consoleActions.completionNext());
|
||||
this.props.dispatch(consoleActions.completionNext());
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case KeyboardEvent.DOM_VK_OPEN_BRACKET:
|
||||
if (e.ctrlKey) {
|
||||
return this.context.store.dispatch(consoleActions.hideCommand());
|
||||
return this.props.dispatch(consoleActions.hideCommand());
|
||||
}
|
||||
break;
|
||||
case KeyboardEvent.DOM_VK_M:
|
||||
|
@ -80,11 +81,11 @@ class ConsoleComponent extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
onInput(e) {
|
||||
onChange(e) {
|
||||
let text = e.target.value;
|
||||
this.context.store.dispatch(consoleActions.setConsoleText(text));
|
||||
this.props.dispatch(consoleActions.setConsoleText(text));
|
||||
if (this.props.mode === 'command') {
|
||||
this.context.store.dispatch(consoleActions.getCompletions(text));
|
||||
this.props.dispatch(consoleActions.getCompletions(text));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +95,7 @@ class ConsoleComponent extends Component {
|
|||
return;
|
||||
}
|
||||
if (prevProps.mode !== 'command' && this.props.mode === 'command') {
|
||||
this.context.store.dispatch(
|
||||
this.props.dispatch(
|
||||
consoleActions.getCompletions(this.props.consoleText));
|
||||
this.focus();
|
||||
} else if (prevProps.mode !== 'find' && this.props.mode === 'find') {
|
||||
|
@ -117,7 +118,7 @@ class ConsoleComponent extends Component {
|
|||
mode={this.props.mode}
|
||||
onBlur={this.onBlur.bind(this)}
|
||||
onKeyDown={this.onKeyDown.bind(this)}
|
||||
onInput={this.onInput.bind(this)}
|
||||
onChange={this.onChange.bind(this)}
|
||||
value={this.props.consoleText}
|
||||
/>
|
||||
</div>;
|
||||
|
@ -126,6 +127,8 @@ class ConsoleComponent extends Component {
|
|||
return <Message mode={ this.props.mode } >
|
||||
{ this.props.messageText }
|
||||
</Message>;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,5 +138,12 @@ class ConsoleComponent extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Console.propTypes = {
|
||||
mode: PropTypes.string,
|
||||
consoleText: PropTypes.string,
|
||||
messageText: PropTypes.string,
|
||||
children: PropTypes.string,
|
||||
};
|
||||
|
||||
const mapStateToProps = state => state;
|
||||
export default connect(mapStateToProps)(ConsoleComponent);
|
||||
export default connect(mapStateToProps)(Console);
|
|
@ -1,29 +1,9 @@
|
|||
import { Component, h } from 'preact';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import CompletionItem from './CompletionItem';
|
||||
import CompletionTitle from './CompletionTitle';
|
||||
|
||||
const CompletionTitle = (props) => {
|
||||
return <li className='vimvixen-console-completion-title' >{props.title}</li>;
|
||||
};
|
||||
|
||||
const CompletionItem = (props) => {
|
||||
let className = 'vimvixen-console-completion-item';
|
||||
if (props.highlight) {
|
||||
className += ' vimvixen-completion-selected';
|
||||
}
|
||||
return <li
|
||||
className={className}
|
||||
style={{ backgroundImage: 'url(' + props.icon + ')' }}
|
||||
>
|
||||
<span
|
||||
className='vimvixen-console-completion-item-caption'
|
||||
>{props.caption}</span>
|
||||
<span
|
||||
className='vimvixen-console-completion-item-url'
|
||||
>{props.url}</span>
|
||||
</li>;
|
||||
};
|
||||
|
||||
|
||||
class CompletionComponent extends Component {
|
||||
class Completion extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { viewOffset: 0, select: -1 };
|
||||
|
@ -63,9 +43,13 @@ class CompletionComponent extends Component {
|
|||
let index = 0;
|
||||
|
||||
for (let group of this.props.completions) {
|
||||
eles.push(<CompletionTitle title={ group.name }/>);
|
||||
eles.push(<CompletionTitle
|
||||
key={`group-${index}`}
|
||||
title={ group.name }
|
||||
/>);
|
||||
for (let item of group.items) {
|
||||
eles.push(<CompletionItem
|
||||
key={`item-${index}`}
|
||||
icon={item.icon}
|
||||
caption={item.caption}
|
||||
url={item.url}
|
||||
|
@ -86,4 +70,17 @@ class CompletionComponent extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default CompletionComponent;
|
||||
Completion.propTypes = {
|
||||
select: PropTypes.number,
|
||||
size: PropTypes.number,
|
||||
completions: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
items: PropTypes.arrayOf(PropTypes.shape({
|
||||
icon: PropTypes.string,
|
||||
caption: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
})),
|
||||
})),
|
||||
};
|
||||
|
||||
export default Completion;
|
28
src/console/components/console/CompletionItem.jsx
Normal file
28
src/console/components/console/CompletionItem.jsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const CompletionItem = (props) => {
|
||||
let className = 'vimvixen-console-completion-item';
|
||||
if (props.highlight) {
|
||||
className += ' vimvixen-completion-selected';
|
||||
}
|
||||
return <li
|
||||
className={className}
|
||||
style={{ backgroundImage: 'url(' + props.icon + ')' }}
|
||||
>
|
||||
<span
|
||||
className='vimvixen-console-completion-item-caption'
|
||||
>{props.caption}</span>
|
||||
<span
|
||||
className='vimvixen-console-completion-item-url'
|
||||
>{props.url}</span>
|
||||
</li>;
|
||||
};
|
||||
|
||||
CompletionItem.propTypes = {
|
||||
highlight: PropTypes.bool,
|
||||
caption: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
};
|
||||
|
||||
export default CompletionItem;
|
14
src/console/components/console/CompletionTitle.jsx
Normal file
14
src/console/components/console/CompletionTitle.jsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const CompletionTitle = (props) => {
|
||||
return <li className='vimvixen-console-completion-title'>
|
||||
{props.title}
|
||||
</li>;
|
||||
};
|
||||
|
||||
CompletionTitle.propTypes = {
|
||||
title: PropTypes.string,
|
||||
};
|
||||
|
||||
export default CompletionTitle;
|
|
@ -1,6 +1,7 @@
|
|||
import { Component, h } from 'preact';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class InputComponent extends Component {
|
||||
class Input extends React.Component {
|
||||
focus() {
|
||||
this.input.focus();
|
||||
}
|
||||
|
@ -23,10 +24,20 @@ export default class InputComponent extends Component {
|
|||
ref={(c) => { this.input = c; }}
|
||||
onBlur={this.props.onBlur}
|
||||
onKeyDown={this.props.onKeyDown}
|
||||
onInput={this.props.onInput}
|
||||
onChange={this.props.onChange}
|
||||
value={this.props.value}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Input.propTypes = {
|
||||
mode: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
onBlur: PropTypes.func,
|
||||
onKeyDown: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default Input;
|
|
@ -1,6 +1,7 @@
|
|||
import { h } from 'preact';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function Message(props) {
|
||||
const Message = (props) => {
|
||||
switch (props.mode) {
|
||||
case 'error':
|
||||
return (
|
||||
|
@ -15,4 +16,10 @@ export default function Message(props) {
|
|||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Message.propTypes = {
|
||||
children: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Message;
|
|
@ -5,5 +5,7 @@
|
|||
<title>VimVixen console</title>
|
||||
<script src='console.js'></script>
|
||||
</head>
|
||||
<body class='vimvixen-console'></body>
|
||||
<body>
|
||||
<div id='vimvixen-console' class='vimvixen-console'></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,11 +3,10 @@ import reducers from 'console/reducers';
|
|||
import { createStore, applyMiddleware } from 'redux';
|
||||
import promise from 'redux-promise';
|
||||
import * as consoleActions from 'console/actions/console';
|
||||
|
||||
import { Provider } from 'preact-redux';
|
||||
import Console from './components/console';
|
||||
|
||||
import { render, h } from 'preact';
|
||||
import { Provider } from 'react-redux';
|
||||
import Console from './components/Console';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const store = createStore(
|
||||
reducers,
|
||||
|
@ -15,11 +14,12 @@ const store = createStore(
|
|||
);
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
render(
|
||||
let wrapper = document.getElementById('vimvixen-console');
|
||||
ReactDOM.render(
|
||||
<Provider store={store} >
|
||||
<Console></Console>
|
||||
</Provider>,
|
||||
document.body);
|
||||
wrapper);
|
||||
});
|
||||
|
||||
const onMessage = (message) => {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import actions from 'settings/actions';
|
||||
import * as validator from 'shared/settings/validator';
|
||||
import KeymapsForm from '../components/form/keymaps-form';
|
||||
import * as settingsValues from 'shared/settings/values';
|
||||
import * as settingsStorage from 'shared/settings/storage';
|
||||
import keymaps from '../keymaps';
|
||||
|
||||
const load = async() => {
|
||||
let settings = await settingsStorage.loadRaw();
|
||||
|
@ -29,8 +29,7 @@ const save = async(settings) => {
|
|||
const switchToForm = (json) => {
|
||||
try {
|
||||
validator.validate(JSON.parse(json));
|
||||
// AllowdOps filters operations, this is dirty dependency
|
||||
let form = settingsValues.formFromJson(json, KeymapsForm.AllowdOps);
|
||||
let form = settingsValues.formFromJson(json, keymaps.allowedOps);
|
||||
return {
|
||||
type: actions.SETTING_SWITCH_TO_FORM,
|
||||
form,
|
||||
|
@ -61,4 +60,4 @@ const set = (settings) => {
|
|||
};
|
||||
};
|
||||
|
||||
export { load, save, switchToForm, switchToJson };
|
||||
export { load, save, set, switchToForm, switchToJson };
|
||||
|
|
|
@ -1,38 +1,34 @@
|
|||
import './blacklist-form.scss';
|
||||
import AddButton from '../ui/add-button';
|
||||
import DeleteButton from '../ui/delete-button';
|
||||
import { h, Component } from 'preact';
|
||||
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 Component {
|
||||
class BlacklistForm extends React.Component {
|
||||
|
||||
render() {
|
||||
let value = this.props.value;
|
||||
if (!value) {
|
||||
value = [];
|
||||
}
|
||||
|
||||
return <div className='form-blacklist-form'>
|
||||
{
|
||||
value.map((url, index) => {
|
||||
this.props.value.map((url, index) => {
|
||||
return <div key={index} className='form-blacklist-form-row'>
|
||||
<input data-index={index} type='text' name='url'
|
||||
className='column-url' value={url}
|
||||
onChange={this.bindValue.bind(this)} />
|
||||
onChange={this.bindValue.bind(this)}
|
||||
onBlur={this.props.onBlur}
|
||||
/>
|
||||
<DeleteButton data-index={index} name='delete'
|
||||
onClick={this.bindValue.bind(this)} />
|
||||
onClick={this.bindValue.bind(this)}
|
||||
onBlur={this.props.onBlur}
|
||||
/>
|
||||
</div>;
|
||||
})
|
||||
}
|
||||
<AddButton name='add' style='float:right'
|
||||
<AddButton name='add' style={{ float: 'right' }}
|
||||
onClick={this.bindValue.bind(this)} />
|
||||
</div>;
|
||||
}
|
||||
|
||||
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() : [];
|
||||
|
@ -46,7 +42,22 @@ class BlacklistForm extends 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;
|
51
src/settings/components/form/KeymapsForm.jsx
Normal file
51
src/settings/components/form/KeymapsForm.jsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import './KeymapsForm.scss';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Input from '../ui/Input';
|
||||
import keymaps from '../../keymaps';
|
||||
|
||||
class KeymapsForm extends React.Component {
|
||||
|
||||
render() {
|
||||
return <div className='form-keymaps-form'>
|
||||
{
|
||||
keymaps.fields.map((group, index) => {
|
||||
return <div key={index} className='form-keymaps-form-field-group'>
|
||||
{
|
||||
group.map((field) => {
|
||||
let name = field[0];
|
||||
let label = field[1];
|
||||
let value = this.props.value[name] || '';
|
||||
return <Input
|
||||
type='text' id={name} name={name} key={name}
|
||||
label={label} value={value}
|
||||
onChange={this.bindValue.bind(this)}
|
||||
onBlur={this.props.onBlur}
|
||||
/>;
|
||||
})
|
||||
}
|
||||
</div>;
|
||||
})
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
|
||||
bindValue(e) {
|
||||
let next = { ...this.props.value };
|
||||
next[e.target.name] = e.target.value;
|
||||
|
||||
this.props.onChange(next);
|
||||
}
|
||||
}
|
||||
|
||||
KeymapsForm.propTypes = {
|
||||
value: PropTypes.objectOf(PropTypes.string),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
KeymapsForm.defaultProps = {
|
||||
value: {},
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
export default KeymapsForm;
|
|
@ -1,14 +1,12 @@
|
|||
import './properties-form.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import './PropertiesForm.scss';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class PropertiesForm extends Component {
|
||||
class PropertiesForm extends React.Component {
|
||||
|
||||
render() {
|
||||
let types = this.props.types;
|
||||
let value = this.props.value;
|
||||
if (!value) {
|
||||
value = {};
|
||||
}
|
||||
|
||||
return <div className='form-properties-form'>
|
||||
{
|
||||
|
@ -29,6 +27,7 @@ class PropertiesForm extends Component {
|
|||
className='column-input'
|
||||
value={value[name] ? value[name] : ''}
|
||||
onChange={this.bindValue.bind(this)}
|
||||
onBlur={this.props.onBlur}
|
||||
checked={value[name]}
|
||||
/>
|
||||
</label>
|
||||
|
@ -39,10 +38,6 @@ class PropertiesForm extends Component {
|
|||
}
|
||||
|
||||
bindValue(e) {
|
||||
if (!this.props.onChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = e.target.name;
|
||||
let next = { ...this.props.value };
|
||||
if (e.target.type.toLowerCase() === 'checkbox') {
|
||||
|
@ -57,4 +52,14 @@ class PropertiesForm extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
PropertiesForm.propTypes = {
|
||||
value: PropTypes.objectOf(PropTypes.any),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
PropertiesForm.defaultProps = {
|
||||
value: {},
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
export default PropertiesForm;
|
|
@ -1,15 +1,13 @@
|
|||
import './search-form.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import AddButton from '../ui/add-button';
|
||||
import DeleteButton from '../ui/delete-button';
|
||||
import './SearchForm.scss';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import AddButton from '../ui/AddButton';
|
||||
import DeleteButton from '../ui/DeleteButton';
|
||||
|
||||
class SearchForm extends Component {
|
||||
class SearchForm extends React.Component {
|
||||
|
||||
render() {
|
||||
let value = this.props.value;
|
||||
if (!value) {
|
||||
value = { default: '', engines: []};
|
||||
}
|
||||
if (!value.engines) {
|
||||
value.engines = [];
|
||||
}
|
||||
|
@ -25,11 +23,15 @@ class SearchForm extends Component {
|
|||
return <div key={index} className='form-search-form-row'>
|
||||
<input data-index={index} type='text' name='name'
|
||||
className='column-name' value={engine[0]}
|
||||
onChange={this.bindValue.bind(this)} />
|
||||
onChange={this.bindValue.bind(this)}
|
||||
onBlur={this.props.onBlur}
|
||||
/>
|
||||
<input data-index={index} type='text' name='url'
|
||||
placeholder='http://example.com/?q={}'
|
||||
className='column-url' value={engine[1]}
|
||||
onChange={this.bindValue.bind(this)} />
|
||||
onChange={this.bindValue.bind(this)}
|
||||
onBlur={this.props.onBlur}
|
||||
/>
|
||||
<div className='column-option'>
|
||||
<input data-index={index} type='radio' name='default'
|
||||
checked={value.default === engine[0]}
|
||||
|
@ -40,16 +42,12 @@ class SearchForm extends Component {
|
|||
</div>;
|
||||
})
|
||||
}
|
||||
<AddButton name='add' style='float:right'
|
||||
<AddButton name='add' style={{ float: 'right' }}
|
||||
onClick={this.bindValue.bind(this)} />
|
||||
</div>;
|
||||
}
|
||||
|
||||
bindValue(e) {
|
||||
if (!this.props.onChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value = this.props.value;
|
||||
let name = e.target.name;
|
||||
let index = e.target.getAttribute('data-index');
|
||||
|
@ -72,7 +70,23 @@ class SearchForm extends Component {
|
|||
}
|
||||
|
||||
this.props.onChange(next);
|
||||
if (name === 'delete' || name === 'default') {
|
||||
this.props.onBlur();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchForm.propTypes = {
|
||||
value: PropTypes.shape({
|
||||
default: PropTypes.string,
|
||||
engines: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.string)),
|
||||
}),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
SearchForm.defaultProps = {
|
||||
value: { default: '', engines: []},
|
||||
onChange: () => {},
|
||||
};
|
||||
|
||||
export default SearchForm;
|
|
@ -1,11 +1,11 @@
|
|||
import './site.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import { connect } from 'preact-redux';
|
||||
import Input from './ui/input';
|
||||
import SearchForm from './form/search-form';
|
||||
import KeymapsForm from './form/keymaps-form';
|
||||
import BlacklistForm from './form/blacklist-form';
|
||||
import PropertiesForm from './form/properties-form';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Input from './ui/Input';
|
||||
import SearchForm from './form/SearchForm';
|
||||
import KeymapsForm from './form/KeymapsForm';
|
||||
import BlacklistForm from './form/BlacklistForm';
|
||||
import PropertiesForm from './form/PropertiesForm';
|
||||
import * as properties from 'shared/settings/properties';
|
||||
import * as settingActions from 'settings/actions/setting';
|
||||
|
||||
|
@ -13,7 +13,7 @@ const DO_YOU_WANT_TO_CONTINUE =
|
|||
'Some settings in JSON can be lost when migrating. ' +
|
||||
'Do you want to continue?';
|
||||
|
||||
class SettingsComponent extends Component {
|
||||
class SettingsComponent extends React.Component {
|
||||
componentDidMount() {
|
||||
this.props.dispatch(settingActions.load());
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ class SettingsComponent extends Component {
|
|||
<KeymapsForm
|
||||
value={form.keymaps}
|
||||
onChange={value => this.bindForm('keymaps', value)}
|
||||
onBlur={this.save.bind(this)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
@ -32,6 +33,7 @@ class SettingsComponent extends Component {
|
|||
<SearchForm
|
||||
value={form.search}
|
||||
onChange={value => this.bindForm('search', value)}
|
||||
onBlur={this.save.bind(this)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
@ -39,6 +41,7 @@ class SettingsComponent extends Component {
|
|||
<BlacklistForm
|
||||
value={form.blacklist}
|
||||
onChange={value => this.bindForm('blacklist', value)}
|
||||
onBlur={this.save.bind(this)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
|
@ -47,6 +50,7 @@ class SettingsComponent extends Component {
|
|||
types={properties.types}
|
||||
value={form.properties}
|
||||
onChange={value => this.bindForm('properties', value)}
|
||||
onBlur={this.save.bind(this)}
|
||||
/>
|
||||
</fieldset>
|
||||
</div>;
|
||||
|
@ -61,6 +65,7 @@ class SettingsComponent extends Component {
|
|||
spellCheck='false'
|
||||
error={error}
|
||||
onChange={this.bindJson.bind(this)}
|
||||
onBlur={this.save.bind(this)}
|
||||
value={json}
|
||||
/>
|
||||
</div>;
|
||||
|
@ -109,7 +114,7 @@ class SettingsComponent extends 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 Component {
|
|||
json: e.target.value,
|
||||
form: this.props.form,
|
||||
};
|
||||
this.props.dispatch(settingActions.save(settings));
|
||||
this.props.dispatch(settingActions.set(settings));
|
||||
}
|
||||
|
||||
bindSource(e) {
|
||||
|
@ -135,8 +140,10 @@ class SettingsComponent extends Component {
|
|||
}
|
||||
this.props.dispatch(settingActions.switchToForm(this.props.json));
|
||||
}
|
||||
}
|
||||
|
||||
let settings = this.context.store.getState();
|
||||
save() {
|
||||
let settings = this.props.store.getState();
|
||||
this.props.dispatch(settingActions.save(settings));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import './add-button.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import './AddButton.scss';
|
||||
import React from 'react';
|
||||
|
||||
class AddButton extends Component {
|
||||
class AddButton extends React.Component {
|
||||
render() {
|
||||
return <input
|
||||
className='ui-add-button' type='button' value='✚'
|
|
@ -1,7 +1,7 @@
|
|||
import './delete-button.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import './DeleteButton.scss';
|
||||
import React from 'react';
|
||||
|
||||
class DeleteButton extends Component {
|
||||
class DeleteButton extends React.Component {
|
||||
render() {
|
||||
return <input
|
||||
className='ui-delete-button' type='button' value='✖'
|
|
@ -1,7 +1,8 @@
|
|||
import { h, Component } from 'preact';
|
||||
import './input.scss';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './Input.scss';
|
||||
|
||||
class Input extends Component {
|
||||
class Input extends React.Component {
|
||||
|
||||
renderText(props) {
|
||||
let inputClassName = props.error ? 'input-error' : '';
|
||||
|
@ -49,4 +50,11 @@ class Input extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Input.propTypes = {
|
||||
type: PropTypes.string,
|
||||
error: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Input;
|
|
@ -1,7 +1,8 @@
|
|||
import { h, render } from 'preact';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import SettingsComponent from './components';
|
||||
import reducer from './reducers/setting';
|
||||
import { Provider } from 'preact-redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import promise from 'redux-promise';
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
|
||||
|
@ -12,9 +13,9 @@ const store = createStore(
|
|||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
let wrapper = document.getElementById('vimvixen-settings');
|
||||
render(
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<SettingsComponent />
|
||||
<SettingsComponent store={store} />
|
||||
</Provider>,
|
||||
wrapper
|
||||
);
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import './keymaps-form.scss';
|
||||
import { h, Component } from 'preact';
|
||||
import Input from '../ui/input';
|
||||
|
||||
const KeyMapFields = [
|
||||
const fields = [
|
||||
[
|
||||
['scroll.vertically?{"count":1}', 'Scroll down'],
|
||||
['scroll.vertically?{"count":-1}', 'Scroll up'],
|
||||
|
@ -70,49 +66,9 @@ const KeyMapFields = [
|
|||
]
|
||||
];
|
||||
|
||||
const AllowdOps = [].concat(...KeyMapFields.map(group => group.map(e => e[0])));
|
||||
const allowedOps = [].concat(...fields.map(group => group.map(e => e[0])));
|
||||
|
||||
class KeymapsForm extends Component {
|
||||
|
||||
render() {
|
||||
let values = this.props.value;
|
||||
if (!values) {
|
||||
values = {};
|
||||
}
|
||||
return <div className='form-keymaps-form'>
|
||||
{
|
||||
KeyMapFields.map((group, index) => {
|
||||
return <div key={index} className='form-keymaps-form-field-group'>
|
||||
{
|
||||
group.map((field) => {
|
||||
let name = field[0];
|
||||
let label = field[1];
|
||||
let value = values[name];
|
||||
return <Input
|
||||
type='text' id={name} name={name} key={name}
|
||||
label={label} value={value}
|
||||
onChange={this.bindValue.bind(this)}
|
||||
/>;
|
||||
})
|
||||
}
|
||||
</div>;
|
||||
})
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
|
||||
bindValue(e) {
|
||||
if (!this.props.onChange) {
|
||||
return;
|
||||
}
|
||||
|
||||
let next = { ...this.props.value };
|
||||
next[e.target.name] = e.target.value;
|
||||
|
||||
this.props.onChange(next);
|
||||
}
|
||||
}
|
||||
|
||||
KeymapsForm.AllowdOps = AllowdOps;
|
||||
|
||||
export default KeymapsForm;
|
||||
export default {
|
||||
fields,
|
||||
allowedOps,
|
||||
};
|
168
test/console/components/console/Completion.test.jsx
Normal file
168
test/console/components/console/Completion.test.jsx
Normal file
|
@ -0,0 +1,168 @@
|
|||
import React from 'react';
|
||||
import Completion from 'console/components/console/Completion'
|
||||
import ReactTestRenderer from 'react-test-renderer';
|
||||
|
||||
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" }],
|
||||
}];
|
||||
|
||||
it('renders Completion component', () => {
|
||||
let root = ReactTestRenderer.create(<Completion
|
||||
completions={completions}
|
||||
size={30}
|
||||
/>).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(<Completion
|
||||
completions={completions}
|
||||
size={30}
|
||||
select={3}
|
||||
/>).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(<Completion
|
||||
completions={completions}
|
||||
size={30}
|
||||
select={-1}
|
||||
/>).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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={-1}
|
||||
/>).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(<Completion
|
||||
completions={completions}
|
||||
size={3} select={0}
|
||||
/>).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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={1}
|
||||
/>);
|
||||
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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={2}
|
||||
/>);
|
||||
|
||||
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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={3}
|
||||
/>);
|
||||
|
||||
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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={5}
|
||||
/>);
|
||||
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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={4}
|
||||
/>);
|
||||
|
||||
children = root.children[0].children;
|
||||
expect(children[1].props.highlight).to.be.true;
|
||||
|
||||
component.update(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={3}
|
||||
/>);
|
||||
|
||||
children = root.children[0].children;
|
||||
expect(children[0].props.highlight).to.be.true;
|
||||
|
||||
component.update(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={2}
|
||||
/>);
|
||||
|
||||
children = root.children[0].children;
|
||||
expect(children[0].props.caption).to.equal('cherry');
|
||||
expect(children[1].props.title).to.equal('Element');
|
||||
expect(children[2].props.caption).to.equal('argon');
|
||||
expect(children[0].props.highlight).to.be.true;
|
||||
});
|
||||
});
|
|
@ -1,138 +0,0 @@
|
|||
import { h, render } from 'preact';
|
||||
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(<Completion
|
||||
completions={completions}
|
||||
size={30}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={30}
|
||||
select={3}
|
||||
/>, document.body);
|
||||
expect(ul.children[5].className.split(' ')).to.include('vimvixen-completion-selected');
|
||||
});
|
||||
|
||||
it('does not highlight any items', () => {
|
||||
let ul = render(<Completion
|
||||
completions={completions}
|
||||
size={30}
|
||||
select={-1}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={-1}
|
||||
/>, document.body);
|
||||
expect(Array.from(ul.children).map(e => e.textContent)).to.deep.equal(['Fruit', 'apple', 'banana']);
|
||||
|
||||
ul = render(<Completion
|
||||
completions={completions}
|
||||
size={3} select={0}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={1}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={2}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={3}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={5}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={4}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={3}
|
||||
/>, 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(<Completion
|
||||
completions={completions}
|
||||
size={3}
|
||||
select={2}
|
||||
/>, 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');
|
||||
});
|
||||
});
|
92
test/settings/components/form/BlacklistForm.test.jsx
Normal file
92
test/settings/components/form/BlacklistForm.test.jsx
Normal file
|
@ -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(
|
||||
<BlacklistForm value={['*.slack.com', 'www.google.com/maps']} />,
|
||||
).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(<BlacklistForm />).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(<BlacklistForm
|
||||
value={['*.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*']);
|
||||
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(<BlacklistForm
|
||||
value={['*.slack.com', 'www.google.com/maps*']}
|
||||
onChange={value => {
|
||||
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(<BlacklistForm
|
||||
value={['*.slack.com']}
|
||||
onChange={value => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
64
test/settings/components/form/KeymapsForm.test.jsx
Normal file
64
test/settings/components/form/KeymapsForm.test.jsx
Normal file
|
@ -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(<KeymapsForm value={{
|
||||
'scroll.vertically?{"count":1}': 'j',
|
||||
'scroll.vertically?{"count":-1}': 'k',
|
||||
}} />).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(<KeymapsForm />).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(<KeymapsForm
|
||||
value={{
|
||||
'scroll.vertically?{"count":1}': 'j',
|
||||
'scroll.vertically?{"count":-1}': 'k',
|
||||
}}
|
||||
onChange={value => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
104
test/settings/components/form/PropertiesForm.test.jsx
Normal file
104
test/settings/components/form/PropertiesForm.test.jsx
Normal file
|
@ -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(
|
||||
<PropertiesForm types={types} value={value} />,
|
||||
).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(<PropertiesForm
|
||||
types={{ 'myvalue': 'string' }}
|
||||
value={{ 'myvalue': 'abc' }}
|
||||
onChange={value => {
|
||||
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(<PropertiesForm
|
||||
types={{ 'myvalue': 'number' }}
|
||||
value={{ '': 123 }}
|
||||
onChange={value => {
|
||||
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(<PropertiesForm
|
||||
types={{ 'myvalue': 'boolean' }}
|
||||
value={{ 'myvalue': false }}
|
||||
onChange={value => {
|
||||
expect(value).to.have.property('myvalue', true);
|
||||
done();
|
||||
}}
|
||||
/>, container);
|
||||
});
|
||||
|
||||
let input = document.querySelector('input[name=myvalue]');
|
||||
input.checked = true;
|
||||
ReactTestUtils.Simulate.change(input);
|
||||
});
|
||||
});
|
||||
});
|
128
test/settings/components/form/SearchEngineForm.test.jsx
Normal file
128
test/settings/components/form/SearchEngineForm.test.jsx
Normal file
|
@ -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(<SearchForm value={{
|
||||
default: 'google',
|
||||
engines: [['google', 'google.com'], ['yahoo', 'yahoo.com']],
|
||||
}} />).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(<SearchForm />).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(
|
||||
<SearchForm value={{ default: 'google' }} />,
|
||||
).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(<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)
|
||||
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(<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)
|
||||
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(<SearchForm value={{
|
||||
default: 'yahoo',
|
||||
engines: [['google', 'google.com']]
|
||||
}}
|
||||
onChange={value => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,81 +0,0 @@
|
|||
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();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,52 +0,0 @@
|
|||
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'))
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,85 +0,0 @@
|
|||
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();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,103 +0,0 @@
|
|||
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();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,14 +1,28 @@
|
|||
import { h, render } from 'preact';
|
||||
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(<Input type='text' name='myname' label='myfield' value='myvalue'/>, document.body)
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(
|
||||
<Input type='text' name='myname' label='myfield' value='myvalue'/>,
|
||||
container);
|
||||
});
|
||||
|
||||
let label = document.querySelector('label');
|
||||
let input = document.querySelector('input');
|
||||
|
@ -19,20 +33,26 @@ describe("settings/ui/Input", () => {
|
|||
});
|
||||
|
||||
it('invoke onChange', (done) => {
|
||||
render(<Input type='text' name='myname' label='myfield' value='myvalue' onChange={(e) => {
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(<Input type='text' name='myname' label='myfield' value='myvalue' onChange={(e) => {
|
||||
expect(e.target.value).to.equal('newvalue');
|
||||
done();
|
||||
}}/>, document.body);
|
||||
}}/>, 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(<Input type='radio' name='myname' label='myfield' value='myvalue'/>, document.body)
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(
|
||||
<Input type='radio' name='myname' label='myfield' value='myvalue'/>,
|
||||
container);
|
||||
});
|
||||
|
||||
let label = document.querySelector('label');
|
||||
let input = document.querySelector('input');
|
||||
|
@ -43,20 +63,27 @@ describe("settings/ui/Input", () => {
|
|||
});
|
||||
|
||||
it('invoke onChange', (done) => {
|
||||
render(<Input type='text' name='radio' label='myfield' value='myvalue' onChange={(e) => {
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(<Input type='text' name='radio' label='myfield' value='myvalue' onChange={(e) => {
|
||||
expect(e.target.checked).to.be.true;
|
||||
done();
|
||||
}}/>, document.body);
|
||||
}}/>,
|
||||
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(<Input type='textarea' name='myname' label='myfield' value='myvalue' error='myerror' />, document.body)
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(
|
||||
<Input type='textarea' name='myname' label='myfield' value='myvalue' error='myerror' />,
|
||||
container);
|
||||
});
|
||||
|
||||
let label = document.querySelector('label');
|
||||
let textarea = document.querySelector('textarea');
|
||||
|
@ -69,14 +96,16 @@ describe("settings/ui/Input", () => {
|
|||
});
|
||||
|
||||
it('invoke onChange', (done) => {
|
||||
render(<Input type='textarea' name='myname' label='myfield' value='myvalue' onChange={(e) => {
|
||||
ReactTestUtils.act(() => {
|
||||
ReactDOM.render(<Input type='textarea' name='myname' label='myfield' value='myvalue' onChange={(e) => {
|
||||
expect(e.target.value).to.equal('newvalue');
|
||||
done();
|
||||
}}/>, document.body);
|
||||
}}/>, container);
|
||||
});
|
||||
|
||||
let input = document.querySelector('textarea');
|
||||
input.value = 'newvalue'
|
||||
input.dispatchEvent(new Event('change'))
|
||||
ReactTestUtils.Simulate.change(input);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ config = {
|
|||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: {
|
||||
presets: ['preact', 'stage-2']
|
||||
presets: ['@babel/react']
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Reference in a new issue