Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into clee/resolve-regressions
Browse files Browse the repository at this point in the history
  • Loading branch information
gwyneplaine committed Jan 4, 2018
2 parents c98fdd0 + c01031f commit 802048b
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 70 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,13 @@ class App extends React.Component {
console.log(`Selected: ${selectedOption.label}`);
}
render() {
const { selectedOption } = this.state;
const value = selectedOption && selectedOption.value;

return (
<Select
name="form-field-name"
value={this.state.selectedOption.value}
value={value}
onChange={this.handleChange}
options={[
{ value: 'one', label: 'One' },
Expand Down
3 changes: 2 additions & 1 deletion examples/src/components/GithubUsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const GithubUsers = createClass({
getInitialState () {
return {
backspaceRemoves: true,
multi: true
multi: true,
creatable: false,
};
},
onChange (value) {
Expand Down
22 changes: 4 additions & 18 deletions src/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,9 @@ class Select extends React.Component {
this.setState({ required: false });
}

// Here we only want to clear the input value under the following conditions.
// 1. There currently actually is an inputValue in state
// 2. The new value is different to the old value OR the new value is == null
// 3. The new value is not the same as the last set value OR onSelectResetsInput has been enabled
// (this is to ensure that the value prop change is not a result of selecting a value)
if (this.state.inputValue) {
this.clearInputValue(nextProps);
if (this.state.inputValue && this.props.value !== nextProps.value && nextProps.onSelectResetsInput) {
this.setState({ inputValue: this.handleInputValueChange('') });
}

delete this._lastSetValue;
}

componentDidUpdate (prevProps, prevState) {
Expand Down Expand Up @@ -190,15 +183,6 @@ class Select extends React.Component {
this.toggleTouchOutsideEvent(false);
}

clearInputValue (nextProps) {
if ((this.props.value !== nextProps.value || !nextProps.value)
&& (nextProps.value !== this._lastSetValue || nextProps.onSelectResetsInput)) {
this.setState({
inputValue: this.handleInputValueChange(''),
});
}
}

toggleTouchOutsideEvent (enabled) {
if (enabled) {
if (!document.addEventListener && document.attachEvent) {
Expand Down Expand Up @@ -425,6 +409,8 @@ class Select extends React.Component {
newInputValue = this.handleInputValueChange(newInputValue);
}

this.previousInputValue = this.state.inputValue;

this.setState({
isOpen: true,
isPseudoFocused: false,
Expand Down
26 changes: 24 additions & 2 deletions test/Async-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use strict';
/* global describe, it, beforeEach */
/* eslint react/jsx-boolean-value: 0 */

// Emulating the DOM here, only so that if this test file gets
Expand Down Expand Up @@ -502,8 +503,7 @@ describe('Async', () => {

describe('props sync test', () => {
it('should update options on componentWillReceiveProps', () => {
createControl({
});
createControl({});
asyncInstance.componentWillReceiveProps({
options: [{
label: 'bar',
Expand All @@ -513,5 +513,27 @@ describe('Async', () => {
expect(asyncNode.querySelectorAll('[role=option]').length, 'to equal', 1);
expect(asyncNode.querySelector('[role=option]').textContent, 'to equal', 'bar');
});

it('should not update options on componentWillReceiveProps', () => {
const props = {options: []};
createControl(props);

const setStateStub = sinon.stub(asyncInstance, 'setState');
asyncInstance.componentWillReceiveProps(props);

expect(setStateStub, 'was not called');

setStateStub.restore();
});
});

describe('componentWillUnmount', () => {
it('should set _callback to null', () => {
createControl({});
expect(asyncInstance._callback, 'not to equal', null);

asyncInstance.componentWillUnmount();
expect(asyncInstance._callback, 'to equal', null);
});
});
});
3 changes: 1 addition & 2 deletions test/AsyncCreatable-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ var sinon = require('sinon');
var Select = require('../src');

describe('AsyncCreatable', () => {
let creatableInstance, creatableNode, filterInputNode, loadOptions, renderer;
let creatableInstance, creatableNode, filterInputNode, loadOptions;

beforeEach(() => {
loadOptions = sinon.stub();
renderer = TestUtils.createRenderer();
});

function createControl (props = {}) {
Expand Down
6 changes: 2 additions & 4 deletions test/Creatable-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ var TestUtils = require('react-dom/test-utils');
var Select = require('../src');

describe('Creatable', () => {
let creatableInstance, creatableNode, filterInputNode, innerSelectInstance, renderer;

beforeEach(() => renderer = TestUtils.createRenderer());
let creatableInstance, creatableNode, filterInputNode, innerSelectInstance;

const defaultOptions = [
{ value: 'one', label: 'One' },
Expand Down Expand Up @@ -221,7 +219,7 @@ describe('Creatable', () => {
expect(test(newOption('qux', 4)), 'to be', true);
expect(test(newOption('Foo', 11)), 'to be', true);
});

it('default: isOptionUnique function should always return true if given options are empty', () => {
const options = [];

Expand Down
163 changes: 125 additions & 38 deletions test/Option-test.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
'use strict';
/* global describe, it, beforeEach */

var helper = require('../testHelpers/jsdomHelper');
helper();
import helper from '../testHelpers/jsdomHelper';
import React from 'react';
import ReactDOM from 'react-dom';
import sinon from 'sinon';
import TestUtils from 'react-dom/test-utils';
import unexpected from 'unexpected';
import unexpectedDom from 'unexpected-dom';
import unexpectedSinon from 'unexpected-sinon';

var unexpected = require('unexpected');
var unexpectedDom = require('unexpected-dom');
var unexpectedSinon = require('unexpected-sinon');
var sinon = require('sinon');
import Option from '../src/Option';

var expect = unexpected
helper();
const expect = unexpected
.clone()
.installPlugin(unexpectedSinon)
.installPlugin(unexpectedDom);

var React = require('react');
var ReactDOM = require('react-dom');
var TestUtils = require('react-dom/test-utils');

var Option = require('../src/Option').default;


describe('Option component', function() {
var onFocus, onSelect, onUnfocus, instance;
var createOption = (props) => {
describe('Option component', () => {
let onFocus, onSelect, onUnfocus, instance, node;
const createOption = props => {
onFocus = sinon.spy();
onSelect = sinon.spy();
onUnfocus = sinon.spy();
Expand All @@ -36,12 +32,12 @@ describe('Option component', function() {
{...props}
/>
);
return instance;

return instance;
};

it('renders the given option', function() {
var props = {
beforeEach(() => {
const props = {
instancePrefix: 'test',
className: 'Wrapper-Class',
children: 'Test Label',
Expand All @@ -52,7 +48,10 @@ describe('Option component', function() {
}
};
instance = createOption(props);
var node = ReactDOM.findDOMNode(instance);
node = ReactDOM.findDOMNode(instance);
});

it('renders the given option', () => {
expect(node.textContent, 'to equal', 'Test Label');
expect(onSelect, 'was not called');
TestUtils.Simulate.mouseDown(node);
Expand All @@ -63,8 +62,9 @@ describe('Option component', function() {
TestUtils.Simulate.mouseMove(node);
expect(onFocus, 'was called');
});
it('does not focus if Option isFocused already', function() {
var props = {

it('does not focus if Option isFocused already', () => {
const props = {
isFocused: true,
instancePrefix: 'test',
className: 'Wrapper-Class',
Expand All @@ -76,24 +76,13 @@ describe('Option component', function() {
}
};
instance = createOption(props);
var node = ReactDOM.findDOMNode(instance);
node = ReactDOM.findDOMNode(instance);
expect(onFocus, 'was not called');
TestUtils.Simulate.mouseEnter(node);
expect(onFocus, 'was not called');
});
it('simulates touch events', function() {
var props = {
instancePrefix: 'test',
className: 'Wrapper-Class',
children: 'Test Label',
option: {
title: 'testitem',
label: 'testitem',
className: 'Option-Class'
}
};
instance = createOption(props);
var node = ReactDOM.findDOMNode(instance);

it('simulates touch events', () => {
expect(instance.dragging, 'to equal', undefined);
// simulate scrolling event
TestUtils.Simulate.touchStart(node);
Expand All @@ -110,4 +99,102 @@ describe('Option component', function() {
expect(onSelect, 'was called');
expect(instance.dragging, 'to equal', false);
});

describe('blockEvent', () => {
let preventDefault, stopPropagation, openStub;
beforeEach(() =>{
preventDefault = sinon.spy();
stopPropagation = sinon.spy();
openStub = sinon.stub(window, 'open');
});

afterEach(() => {
openStub.restore();
});

it('should call window.open', () => {
const event = {
target: {
href: 'http://go.com',
tagName: 'A',
target: 'yes',
},
preventDefault,
stopPropagation,
};

instance.blockEvent(event);

expect(openStub, 'was called once');
expect(openStub, 'was called with', event.target.href, event.target.target);
});

it('should set window.location.href and not call window.open', () => {
const event = {
target: {
href: 'http://go.com',
tagName: 'A',
},
preventDefault,
stopPropagation,
};

Object.defineProperty(window.location, 'href', {
writable: true,
value: 'url'
});

expect(window.location.href, 'not to equal', event.target.href);

instance.blockEvent(event);

expect(window.location.href, 'to equal', event.target.href);
expect(openStub, 'was not called');
});

it('should return and not call window.open when tagName !=A', () => {
const event = {
target: {
href: 'http://go.com',
tagName: '',
},
preventDefault,
stopPropagation,
};

Object.defineProperty(window.location, 'href', {
writable: true,
value: 'url'
});

expect(window.location.href, 'to equal', 'url');

instance.blockEvent(event);

expect(window.location.href, 'to equal', 'url');
expect(openStub, 'was not called');
});

it('should return and not call window.open when no href', () => {
const event = {
target: {
tagName: 'A',
},
preventDefault,
stopPropagation,
};

Object.defineProperty(window.location, 'href', {
writable: true,
value: 'url'
});

expect(window.location.href, 'to equal', 'url');

instance.blockEvent(event);

expect(window.location.href, 'to equal', 'url');
expect(openStub, 'was not called');
});
});
});
Loading

0 comments on commit 802048b

Please sign in to comment.