mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-26 09:14:15 +08:00
TextInput: props and tests
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
[![npm version][npm-image]][npm-url]
|
||||
|
||||
The core [React Native][react-native-url] components adapted and expanded upon
|
||||
for the web, backed by a precomputed CSS library. ~19KB minified and gzipped.
|
||||
for the web, backed by a precomputed CSS library. ~21KB minified and gzipped.
|
||||
|
||||
* [Slack: reactiflux channel #react-native-web][slack-url]
|
||||
* [Gitter: react-native-web][gitter-url]
|
||||
|
||||
@@ -5,7 +5,7 @@ var webpackConfig = require('./webpack.config.base')
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: constants.ROOT_DIRECTORY,
|
||||
browsers: [ process.env.TRAVIS ? 'Firefox' : 'Chrome' ],
|
||||
browsers: process.env.TRAVIS ? [ 'Firefox' ] : [ 'Chrome' ],
|
||||
browserNoActivityTimeout: 60000,
|
||||
client: {
|
||||
captureConsole: true,
|
||||
|
||||
@@ -5,67 +5,130 @@ such as auto-complete, auto-focus, placeholder text, and event callbacks.
|
||||
|
||||
Note: some props are exclusive to or excluded from `multiline`.
|
||||
|
||||
Unsupported React Native props:
|
||||
`autoCapitalize`,
|
||||
`autoCorrect`,
|
||||
`onEndEditing`,
|
||||
`onSubmitEditing`,
|
||||
`clearButtonMode` (ios),
|
||||
`enablesReturnKeyAutomatically` (ios),
|
||||
`returnKeyType` (ios),
|
||||
`selectionState` (ios),
|
||||
`textAlign` (android),
|
||||
`textAlignVertical` (android),
|
||||
`underlineColorAndroid` (android)
|
||||
|
||||
## Props
|
||||
|
||||
**autoComplete** bool
|
||||
(web) **accessibilityLabel**: string
|
||||
|
||||
Defines the text label available to assistive technologies upon interaction
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
(web) **autoComplete**: bool = false
|
||||
|
||||
Indicates whether the value of the control can be automatically completed by the browser.
|
||||
|
||||
**autoFocus** bool
|
||||
**autoFocus**: bool = false
|
||||
|
||||
If true, focuses the input on `componentDidMount`. Only the first form element
|
||||
in a document with `autofocus` is focused. Default: `false`.
|
||||
in a document with `autofocus` is focused.
|
||||
|
||||
**defaultValue** string
|
||||
**clearTextOnFocus**: bool = false
|
||||
|
||||
If `true`, clears the text field automatically when focused.
|
||||
|
||||
**defaultValue**: string
|
||||
|
||||
Provides an initial value that will change when the user starts typing. Useful
|
||||
for simple use-cases where you don't want to deal with listening to events and
|
||||
updating the `value` prop to keep the controlled state in sync.
|
||||
|
||||
**editable** bool
|
||||
**editable**: bool = true
|
||||
|
||||
If false, text is not editable. Default: `true`.
|
||||
If `false`, text is not editable (i.e., read-only).
|
||||
|
||||
**keyboardType** oneOf('default', 'email', 'numeric', 'search', 'tel', 'url')
|
||||
**keyboardType**: oneOf('default', 'email-address', 'numeric', 'phone-pad', 'url') = 'default'
|
||||
|
||||
Determines which keyboard to open, e.g. `email`. Default: `default`. (Not
|
||||
available when `multiline` is `true`.)
|
||||
Determines which keyboard to open.
|
||||
|
||||
**multiline** bool
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
If true, the text input can be multiple lines. Default: `false`.
|
||||
**maxLength**: number
|
||||
|
||||
**onBlur** function
|
||||
Limits the maximum number of characters that can be entered.
|
||||
|
||||
(web) **maxNumberOfLines**: number = numberOfLines
|
||||
|
||||
Limits the maximum number of lines for a multiline `TextInput`.
|
||||
|
||||
(Requires `multiline` to be `true`.)
|
||||
|
||||
**multiline**: bool = false
|
||||
|
||||
If true, the text input can be multiple lines.
|
||||
|
||||
**numberOfLines**: number = 2
|
||||
|
||||
Sets the initial number of lines for a multiline `TextInput`.
|
||||
|
||||
(Requires `multiline` to be `true`.)
|
||||
|
||||
**onBlur**: function
|
||||
|
||||
Callback that is called when the text input is blurred.
|
||||
|
||||
**onChange** function
|
||||
**onChange**: function
|
||||
|
||||
Callback that is called when the text input's text changes.
|
||||
|
||||
**onChangeText** function
|
||||
**onChangeText**: function
|
||||
|
||||
Callback that is called when the text input's text changes. Changed text is
|
||||
passed as an argument to the callback handler.
|
||||
Callback that is called when the text input's text changes. The text is passed
|
||||
as an argument to the callback handler.
|
||||
|
||||
**onFocus** function
|
||||
**onFocus**: function
|
||||
|
||||
Callback that is called when the text input is focused.
|
||||
|
||||
**placeholder** string
|
||||
**onLayout**: function
|
||||
|
||||
TODO
|
||||
|
||||
(web) **onSelectionChange**: function
|
||||
|
||||
Callback that is called when the text input's selection changes. The following
|
||||
object is passed as an argument to the callback handler.
|
||||
|
||||
```js
|
||||
{
|
||||
selectionDirection,
|
||||
selectionEnd,
|
||||
selectionStart,
|
||||
nativeEvent
|
||||
}
|
||||
```
|
||||
|
||||
**placeholder**: string
|
||||
|
||||
The string that will be rendered before text input has been entered.
|
||||
|
||||
**placeholderTextColor** string
|
||||
**placeholderTextColor**: string
|
||||
|
||||
The text color of the placeholder string.
|
||||
TODO. The text color of the placeholder string.
|
||||
|
||||
**secureTextEntry** bool
|
||||
**secureTextEntry**: bool = false
|
||||
|
||||
If true, the text input obscures the text entered so that sensitive text like
|
||||
passwords stay secure. Default: `false`. (Not available when `multiline` is `true`.)
|
||||
passwords stay secure.
|
||||
|
||||
**style** style
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**selectTextOnFocus**: bool = false
|
||||
|
||||
If `true`, all text will automatically be selected on focus.
|
||||
|
||||
**style**: style
|
||||
|
||||
[View](View.md) style
|
||||
|
||||
@@ -81,31 +144,60 @@ passwords stay secure. Default: `false`. (Not available when `multiline` is `tru
|
||||
+ `textDecoration`
|
||||
+ `textTransform`
|
||||
|
||||
**testID** string
|
||||
**testID**: string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
**value**: string
|
||||
|
||||
The value to show for the text input. `TextInput` is a controlled component,
|
||||
which means the native `value` will be forced to match this prop if provided.
|
||||
Read about how [React form
|
||||
components](https://facebook.github.io/react/docs/forms.html) work. To prevent
|
||||
user edits to the value set `editable={false}`.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { TextInput } from 'react-native-web'
|
||||
|
||||
const { Component, PropTypes } = React
|
||||
const { Component } = React
|
||||
|
||||
class AppTextInput extends Component {
|
||||
static propTypes = {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { isFocused: false }
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
_onFocus(e) {
|
||||
this.setState({ isFocused: true })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput />
|
||||
<TextInput
|
||||
accessibilityLabel='Write a status update'
|
||||
maxNumberOfLines={5}
|
||||
multiline
|
||||
numberOfLines={2}
|
||||
onFocus={this._onFocus.bind(this)}
|
||||
placeholder={`What's happening?`}
|
||||
style={
|
||||
...styles.default
|
||||
...(this.state.isFocused && styles.focused)
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
default: {
|
||||
borderColor: 'gray',
|
||||
borderWidth: '0 0 2px 0'
|
||||
},
|
||||
focused: {
|
||||
borderColor: 'blue'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"dependencies": {
|
||||
"react": ">=0.13.3",
|
||||
"react-swipeable": "^3.0.2",
|
||||
"react-tappable": "^0.6.0"
|
||||
"react-tappable": "^0.6.0",
|
||||
"react-textarea-autosize": "^2.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer-loader": "^3.1.0",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { pickProps } from '../../modules/filterObjectProps'
|
||||
import CoreComponent from '../CoreComponent'
|
||||
import React, { PropTypes } from 'react'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import TextInputStylePropTypes from './TextInputStylePropTypes'
|
||||
|
||||
const textInputStyleKeys = Object.keys(TextInputStylePropTypes)
|
||||
@@ -9,90 +10,166 @@ const styles = {
|
||||
initial: {
|
||||
appearance: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: 'black',
|
||||
borderWidth: '1px',
|
||||
boxSizing: 'border-box',
|
||||
color: 'inherit',
|
||||
font: 'inherit'
|
||||
font: 'inherit',
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
|
||||
class TextInput extends React.Component {
|
||||
static propTypes = {
|
||||
accessibilityLabel: PropTypes.string,
|
||||
autoComplete: PropTypes.bool,
|
||||
autoFocus: PropTypes.bool,
|
||||
clearTextOnFocus: PropTypes.bool,
|
||||
defaultValue: PropTypes.string,
|
||||
editable: PropTypes.bool,
|
||||
keyboardType: PropTypes.oneOf(['default', 'email', 'numeric', 'search', 'tel', 'url']),
|
||||
keyboardType: PropTypes.oneOf(['default', 'email-address', 'numeric', 'phone-pad', 'url']),
|
||||
maxLength: PropTypes.number,
|
||||
maxNumberOfLines: PropTypes.number,
|
||||
multiline: PropTypes.bool,
|
||||
numberOfLines: PropTypes.number,
|
||||
onBlur: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
onChangeText: PropTypes.func,
|
||||
onFocus: PropTypes.func,
|
||||
onSelectionChange: PropTypes.func,
|
||||
placeholder: PropTypes.string,
|
||||
placeholderTextColor: PropTypes.string,
|
||||
secureTextEntry: PropTypes.bool,
|
||||
selectTextOnFocus: PropTypes.bool,
|
||||
style: PropTypes.shape(TextInputStylePropTypes),
|
||||
testID: CoreComponent.propTypes.testID
|
||||
testID: CoreComponent.propTypes.testID,
|
||||
value: PropTypes.string
|
||||
}
|
||||
|
||||
static stylePropTypes = TextInputStylePropTypes
|
||||
|
||||
static defaultProps = {
|
||||
autoComplete: false,
|
||||
autoFocus: false,
|
||||
editable: true,
|
||||
keyboardType: 'default',
|
||||
multiline: false,
|
||||
numberOfLines: 2,
|
||||
secureTextEntry: false,
|
||||
style: styles.initial
|
||||
}
|
||||
|
||||
_onBlur(e) {
|
||||
if (this.props.onBlur) this.props.onBlur(e)
|
||||
const { onBlur } = this.props
|
||||
if (onBlur) onBlur(e)
|
||||
}
|
||||
|
||||
_onChange(e) {
|
||||
if (this.props.onChangeText) this.props.onChangeText(e.target.value)
|
||||
if (this.props.onChange) this.props.onChange(e)
|
||||
const { onChange, onChangeText } = this.props
|
||||
if (onChangeText) onChangeText(e.target.value)
|
||||
if (onChange) onChange(e)
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
if (this.props.onFocus) this.props.onFocus(e)
|
||||
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props
|
||||
const node = React.findDOMNode(this)
|
||||
if (clearTextOnFocus) node.value = ''
|
||||
if (selectTextOnFocus) node.select()
|
||||
if (onFocus) onFocus(e)
|
||||
}
|
||||
|
||||
_onSelectionChange(e) {
|
||||
const { onSelectionChange } = this.props
|
||||
const { selectionDirection, selectionEnd, selectionStart } = e.target
|
||||
const event = {
|
||||
selectionDirection,
|
||||
selectionEnd,
|
||||
selectionStart,
|
||||
nativeEvent: e.nativeEvent
|
||||
}
|
||||
if (onSelectionChange) onSelectionChange(event)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
accessibilityLabel,
|
||||
autoComplete,
|
||||
autoFocus,
|
||||
defaultValue,
|
||||
editable,
|
||||
keyboardType,
|
||||
maxLength,
|
||||
maxNumberOfLines,
|
||||
multiline,
|
||||
numberOfLines,
|
||||
onBlur,
|
||||
onChange,
|
||||
onChangeText,
|
||||
onSelectionChange,
|
||||
placeholder,
|
||||
secureTextEntry,
|
||||
style,
|
||||
testID
|
||||
testID,
|
||||
value
|
||||
} = this.props
|
||||
|
||||
const resolvedStyle = pickProps(style, textInputStyleKeys)
|
||||
const type = secureTextEntry && 'password' || (keyboardType === 'default' ? '' : keyboardType)
|
||||
let type
|
||||
|
||||
return (
|
||||
<CoreComponent
|
||||
autoComplete={autoComplete}
|
||||
autoFocus={autoFocus}
|
||||
className={'TextInput'}
|
||||
component={multiline ? 'textarea' : 'input'}
|
||||
defaultValue={defaultValue || placeholder}
|
||||
onBlur={this._onBlur.bind(this)}
|
||||
onChange={this._onChange.bind(this)}
|
||||
onFocus={this._onFocus.bind(this)}
|
||||
readOnly={!editable}
|
||||
style={{
|
||||
...(styles.initial),
|
||||
...resolvedStyle
|
||||
}}
|
||||
testID={testID}
|
||||
type={multiline ? type : undefined}
|
||||
/>
|
||||
switch (keyboardType) {
|
||||
case 'email-address':
|
||||
type = 'email'
|
||||
break
|
||||
case 'numeric':
|
||||
type = 'number'
|
||||
break
|
||||
case 'phone-pad':
|
||||
type = 'tel'
|
||||
break
|
||||
case 'url':
|
||||
type = 'url'
|
||||
break
|
||||
}
|
||||
|
||||
if (secureTextEntry) {
|
||||
type = 'password'
|
||||
}
|
||||
|
||||
const propsCommon = {
|
||||
'aria-label': accessibilityLabel,
|
||||
autoComplete: autoComplete && 'on',
|
||||
autoFocus,
|
||||
className: 'TextInput',
|
||||
defaultValue,
|
||||
maxLength,
|
||||
onBlur: onBlur && this._onBlur.bind(this),
|
||||
onChange: (onChange || onChangeText) && this._onChange.bind(this),
|
||||
onFocus: this._onFocus.bind(this),
|
||||
onSelect: onSelectionChange && this._onSelectionChange.bind(this),
|
||||
placeholder,
|
||||
readOnly: !editable,
|
||||
style: {
|
||||
...styles.initial,
|
||||
...resolvedStyle
|
||||
},
|
||||
testID,
|
||||
value
|
||||
}
|
||||
|
||||
const propsMultiline = {
|
||||
...propsCommon,
|
||||
component: TextareaAutosize,
|
||||
maxRows: maxNumberOfLines || numberOfLines,
|
||||
minRows: numberOfLines
|
||||
}
|
||||
|
||||
const propsSingleline = {
|
||||
...propsCommon,
|
||||
component: 'input',
|
||||
type
|
||||
}
|
||||
|
||||
return (multiline
|
||||
? <CoreComponent {...propsMultiline} />
|
||||
: <CoreComponent {...propsSingleline} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/*
|
||||
import { assertProps, renderToDOM, shallowRender } from '../../modules/specHelpers'
|
||||
import * as utils from '../../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from 'react/addons'
|
||||
|
||||
@@ -7,7 +6,217 @@ import TextInput from '.'
|
||||
|
||||
const ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
suite.skip('TextInput', () => {
|
||||
test('prop "children"', () => {})
|
||||
suite('TextInput', () => {
|
||||
test('prop "accessibilityLabel"', () => {
|
||||
utils.assertProps.accessibilityLabel(TextInput)
|
||||
})
|
||||
|
||||
test('prop "autoComplete"', () => {
|
||||
// off
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('autocomplete'), undefined)
|
||||
// on
|
||||
dom = utils.renderToDOM(<TextInput autoComplete />)
|
||||
assert.equal(dom.getAttribute('autocomplete'), 'on')
|
||||
})
|
||||
|
||||
test('prop "autoFocus"', () => {
|
||||
// false
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.deepEqual(document.activeElement, document.body)
|
||||
// true
|
||||
dom = utils.renderToDOM(<TextInput autoFocus />)
|
||||
assert.deepEqual(document.activeElement, dom)
|
||||
})
|
||||
|
||||
test('prop "clearTextOnFocus"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
utils.requiresFocus(() => {
|
||||
// false
|
||||
let dom = utils.renderAndInject(<TextInput defaultValue={defaultValue} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.value, defaultValue)
|
||||
// true
|
||||
dom = utils.renderAndInject(<TextInput clearTextOnFocus defaultValue={defaultValue} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.value, '')
|
||||
})
|
||||
})
|
||||
|
||||
test('prop "defaultValue"', () => {
|
||||
const defaultValue = 'defaultValue'
|
||||
const result = utils.shallowRender(<TextInput defaultValue={defaultValue} />)
|
||||
assert.equal(result.props.defaultValue, defaultValue)
|
||||
})
|
||||
|
||||
test('prop "editable"', () => {
|
||||
// true
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('readonly'), undefined)
|
||||
// false
|
||||
dom = utils.renderToDOM(<TextInput editable={false} />)
|
||||
assert.equal(dom.getAttribute('readonly'), '')
|
||||
})
|
||||
|
||||
test('prop "keyboardType"', () => {
|
||||
// default
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='default' />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
// email-address
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='email-address' />)
|
||||
assert.equal(dom.getAttribute('type'), 'email')
|
||||
// numeric
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='numeric' />)
|
||||
assert.equal(dom.getAttribute('type'), 'number')
|
||||
// phone-pad
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='phone-pad' />)
|
||||
assert.equal(dom.getAttribute('type'), 'tel')
|
||||
// url
|
||||
dom = utils.renderToDOM(<TextInput keyboardType='url' />)
|
||||
assert.equal(dom.getAttribute('type'), 'url')
|
||||
})
|
||||
|
||||
test('prop "maxLength"', () => {
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.getAttribute('maxlength'), undefined)
|
||||
dom = utils.renderToDOM(<TextInput maxLength={10} />)
|
||||
assert.equal(dom.getAttribute('maxlength'), '10')
|
||||
})
|
||||
|
||||
test('prop "maxNumberOfLines"', () => {
|
||||
const style = { borderWidth: 0, fontSize: 20, lineHeight: 1 }
|
||||
const value = (() => {
|
||||
let str = ''
|
||||
while (str.length < 100) str += 'x'
|
||||
return str
|
||||
}())
|
||||
let dom = utils.renderAndInject(
|
||||
<TextInput
|
||||
maxNumberOfLines={3}
|
||||
multiline
|
||||
style={style}
|
||||
value={value}
|
||||
/>
|
||||
)
|
||||
const height = dom.getBoundingClientRect().height
|
||||
// need a range because of cross-browser differences
|
||||
assert.ok(height >= 60)
|
||||
assert.ok(height <= 65)
|
||||
})
|
||||
|
||||
test('prop "multiline"', () => {
|
||||
// false
|
||||
let dom = utils.renderToDOM(<TextInput />)
|
||||
assert.equal(dom.tagName, 'INPUT')
|
||||
// true
|
||||
dom = utils.renderToDOM(<TextInput multiline />)
|
||||
assert.equal(dom.tagName, 'TEXTAREA')
|
||||
})
|
||||
|
||||
test('prop "numberOfLines"', () => {
|
||||
const style = { borderWidth: 0, fontSize: 20, lineHeight: 1 }
|
||||
// missing multiline
|
||||
let dom = utils.renderToDOM(<TextInput numberOfLines={2} />)
|
||||
assert.equal(dom.tagName, 'INPUT')
|
||||
// with multiline
|
||||
dom = utils.renderAndInject(<TextInput multiline numberOfLines={2} style={style} />)
|
||||
assert.equal(dom.tagName, 'TEXTAREA')
|
||||
const height = dom.getBoundingClientRect().height
|
||||
// need a range because of cross-browser differences
|
||||
assert.ok(height >= 40)
|
||||
assert.ok(height <= 45)
|
||||
})
|
||||
|
||||
test('prop "onBlur"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onBlur={onBlur} />)
|
||||
ReactTestUtils.Simulate.blur(input)
|
||||
function onBlur(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "onChange"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onChange={onChange} />)
|
||||
ReactTestUtils.Simulate.change(input)
|
||||
function onChange(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "onChangeText"', (done) => {
|
||||
const newText = 'newText'
|
||||
const input = utils.renderToDOM(<TextInput onChangeText={onChangeText} />)
|
||||
ReactTestUtils.Simulate.change(input, { target: { value: newText } })
|
||||
function onChangeText(text) {
|
||||
assert.equal(text, newText)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test('prop "onFocus"', (done) => {
|
||||
const input = utils.renderToDOM(<TextInput onFocus={onFocus} />)
|
||||
ReactTestUtils.Simulate.focus(input)
|
||||
function onFocus(e) {
|
||||
assert.ok(e)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test.skip('prop "onLayout"', () => {})
|
||||
|
||||
test('prop "onSelectionChange"', (done) => {
|
||||
const input = utils.renderAndInject(<TextInput defaultValue='12345' onSelectionChange={onSelectionChange} />)
|
||||
ReactTestUtils.Simulate.select(input, { target: { selectionStart: 0, selectionEnd: 3 } })
|
||||
function onSelectionChange(e) {
|
||||
assert.equal(e.selectionEnd, 3)
|
||||
assert.equal(e.selectionStart, 0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
test.skip('prop "placeholder"', () => {})
|
||||
|
||||
test.skip('prop "placeholderTextColor"', () => {})
|
||||
|
||||
test('prop "secureTextEntry"', () => {
|
||||
let dom = utils.renderToDOM(<TextInput secureTextEntry />)
|
||||
assert.equal(dom.getAttribute('type'), 'password')
|
||||
// ignored for multiline
|
||||
dom = utils.renderToDOM(<TextInput multiline secureTextEntry />)
|
||||
assert.equal(dom.getAttribute('type'), undefined)
|
||||
})
|
||||
|
||||
test('prop "selectTextOnFocus"', () => {
|
||||
const text = 'Text'
|
||||
utils.requiresFocus(() => {
|
||||
// false
|
||||
let dom = utils.renderAndInject(<TextInput defaultValue={text} />)
|
||||
dom.focus()
|
||||
assert.equal(dom.selectionEnd, 0)
|
||||
assert.equal(dom.selectionStart, 0)
|
||||
// true
|
||||
dom = utils.renderAndInject(<TextInput defaultValue={text} selectTextOnFocus />)
|
||||
dom.focus()
|
||||
assert.equal(dom.selectionEnd, 4)
|
||||
assert.equal(dom.selectionStart, 0)
|
||||
})
|
||||
})
|
||||
|
||||
test('prop "style"', () => {
|
||||
utils.assertProps.style(TextInput)
|
||||
})
|
||||
|
||||
test('prop "testID"', () => {
|
||||
utils.assertProps.testID(TextInput)
|
||||
})
|
||||
|
||||
test('prop "value"', () => {
|
||||
const value = 'value'
|
||||
const result = utils.shallowRender(<TextInput value={value} />)
|
||||
assert.equal(result.props.value, value)
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
@@ -132,13 +132,20 @@ class Example extends Component {
|
||||
onChange={(e) => { console.log('TextInput.onChange', e) }}
|
||||
onChangeText={(e) => { console.log('TextInput.onChangeText', e) }}
|
||||
onFocus={(e) => { console.log('TextInput.onFocus', e) }}
|
||||
onSelectionChange={(e) => { console.log('TextInput.onSelectionChange', e) }}
|
||||
/>
|
||||
<TextInput secureTextEntry />
|
||||
<TextInput defaultValue='read only' editable={false} />
|
||||
<TextInput keyboardType='email-address' />
|
||||
<TextInput keyboardType='numeric' />
|
||||
<TextInput keyboardType='tel' />
|
||||
<TextInput keyboardType='phone-pad' />
|
||||
<TextInput keyboardType='url' />
|
||||
<TextInput keyboardType='search' />
|
||||
<TextInput defaultValue='default value' multiline />
|
||||
<TextInput
|
||||
defaultValue='default value'
|
||||
maxNumberOfLines={10}
|
||||
multiline
|
||||
numberOfLines={5}
|
||||
/>
|
||||
|
||||
<Heading level='2' size='large'>Touchable</Heading>
|
||||
<Touchable
|
||||
|
||||
@@ -59,8 +59,8 @@ export const assertProps = {
|
||||
const styleToMerge = { margin: '10' }
|
||||
shallow = shallowRender(<Component {...props} style={styleToMerge} />)
|
||||
assert.deepEqual(
|
||||
shallow.props.style.margin,
|
||||
styleToMerge.margin,
|
||||
shallow.props.style,
|
||||
{ ...Component.defaultProps.style, ...styleToMerge }
|
||||
)
|
||||
},
|
||||
|
||||
@@ -86,6 +86,33 @@ export function renderToDOM(element, container) {
|
||||
return React.findDOMNode(result)
|
||||
}
|
||||
|
||||
export function renderAndInject(element) {
|
||||
const id = '_renderAndInject'
|
||||
let div = document.getElementById(id)
|
||||
|
||||
if (!div) {
|
||||
div = document.createElement('div')
|
||||
div.id = id
|
||||
document.body.appendChild(div)
|
||||
} else {
|
||||
div.innerHTML = ''
|
||||
}
|
||||
|
||||
const result = render(element, div)
|
||||
return React.findDOMNode(result)
|
||||
}
|
||||
|
||||
export function requiresFocus(test, fallback) {
|
||||
if (document.hasFocus && document.hasFocus()) {
|
||||
test()
|
||||
} else {
|
||||
console.warn('Test was skipped as the document is not focused')
|
||||
if (fallback) {
|
||||
fallback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function shallowRender(component, context = {}) {
|
||||
const shallowRenderer = React.addons.TestUtils.createRenderer()
|
||||
shallowRenderer.render(component, context)
|
||||
|
||||
Reference in New Issue
Block a user