diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e1715f05..60ea55340 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ The following is a curated list of changes in the Enact agate module, newest cha ### Changed - `agate/Dropdown` to use `agate/ContextualPopup` +- `agate/Picker` and `agate/RangePicker` to use the new DrumPicker component - `agate/ThemeDecorator` to exclude `enact-fit` className when `disableFullscreen` is true - `agate/ArcPicker` and `agate/ArcSlider` to have a max-width for `slotCenter` diff --git a/DatePicker/tests/DatePicker-specs.js b/DatePicker/tests/DatePicker-specs.js index a74e630ab..599057160 100644 --- a/DatePicker/tests/DatePicker-specs.js +++ b/DatePicker/tests/DatePicker-specs.js @@ -1,13 +1,12 @@ import {mount} from 'enzyme'; -import DatePicker from '../DatePicker'; +import {DatePicker} from '../DatePicker'; import css from '../DatePicker.module.less'; // Note: Tests pass 'locale' because there's no I18nDecorator to provide a value via context and // otherwise, nothing renders in the label. describe('DatePicker', () => { - test( 'should emit an onChange event when changing a component picker', () => { diff --git a/DateTimePicker/tests/DateTimePicker-specs.js b/DateTimePicker/tests/DateTimePicker-specs.js index be388c994..78e7baf21 100644 --- a/DateTimePicker/tests/DateTimePicker-specs.js +++ b/DateTimePicker/tests/DateTimePicker-specs.js @@ -8,7 +8,6 @@ import timeCss from '../../TimePicker/TimePicker.module.less'; // otherwise, nothing renders in the label. describe('DateTimePicker', () => { - test( 'should emit an onChange event when changing a component picker', () => { diff --git a/Picker/Picker.js b/Picker/Picker.js index c78a720b7..15882d96a 100644 --- a/Picker/Picker.js +++ b/Picker/Picker.js @@ -12,6 +12,7 @@ */ import kind from '@enact/core/kind'; +import {mapAndFilterChildren} from '@enact/core/util'; import Changeable from '@enact/ui/Changeable'; import Pure from '@enact/ui/internal/Pure'; import PropTypes from 'prop-types'; @@ -19,7 +20,7 @@ import clamp from 'ramda/src/clamp'; import compose from 'ramda/src/compose'; import {Children} from 'react'; -import PickerCore, {ChangeAdapter, PickerItem} from '../internal/Picker'; +import PickerCore, {DrumPickerItem} from '../internal/DrumPicker'; /** * The base `Picker` component. @@ -134,9 +135,13 @@ const PickerBase = kind({ }, computed: { - children: ({children}) => Children.map(children, (child) => ( - {child} - )), + children: ({children, value}) => { + // send to internal/DrumPicker only 5 children. Current selected +/-2 + const childrenArray = children.filter((child, index) => index >= value - 2 && index <= value + 2); + return (mapAndFilterChildren(childrenArray, (child) => ( + {child} + ))); + }, disabled: ({children, disabled}) => Children.count(children) > 1 ? disabled : true, max: ({children}) => children && children.length ? children.length - 1 : 0, value: ({value, children}) => { @@ -172,8 +177,7 @@ const PickerBase = kind({ */ const PickerDecorator = compose( Pure, - Changeable, - ChangeAdapter + Changeable ); /** diff --git a/Picker/tests/Picker-specs.js b/Picker/tests/Picker-specs.js index e40359ed8..7be2bbea0 100644 --- a/Picker/tests/Picker-specs.js +++ b/Picker/tests/Picker-specs.js @@ -3,7 +3,7 @@ import {mount} from 'enzyme'; import {Picker, PickerBase} from '../Picker'; describe('Picker Specs', () => { - test('should render selected child wrapped with ', () => { + test('should render selected child wrapped with ', () => { const picker = mount( {[1, 2, 3, 4]} @@ -11,7 +11,7 @@ describe('Picker Specs', () => { ); const expected = '2'; - const actual = picker.find('PickerItem').at(1).text(); + const actual = picker.find('DrumPickerItem').at(1).text(); expect(actual).toBe(expected); }); @@ -25,7 +25,7 @@ describe('Picker Specs', () => { ); const expected = 3; - const actual = picker.find('Picker').last().prop('max'); + const actual = picker.find('DrumPicker').last().prop('max'); expect(actual).toBe(expected); } @@ -38,7 +38,7 @@ describe('Picker Specs', () => { ); - const actual = picker.find('Picker').last().prop('disabled'); + const actual = picker.find('DrumPicker').last().prop('disabled'); expect(actual).toBe(true); }); diff --git a/RangePicker/RangePicker.js b/RangePicker/RangePicker.js index 0221baffd..91e327553 100644 --- a/RangePicker/RangePicker.js +++ b/RangePicker/RangePicker.js @@ -11,14 +11,14 @@ */ import kind from '@enact/core/kind'; -import {clamp} from '@enact/core/util'; +import {clamp, mapAndFilterChildren} from '@enact/core/util'; import Changeable from '@enact/ui/Changeable'; import Pure from '@enact/ui/internal/Pure'; import PropTypes from 'prop-types'; import compose from 'ramda/src/compose'; -import PickerCore, {ChangeAdapter} from '../internal/Picker'; -import PickerItem from '../internal/Picker/PickerItem'; +import PickerCore from '../internal/DrumPicker'; +import DrumPickerItem from '../internal/DrumPicker/DrumPickerItem'; /** * RangePicker base component. @@ -171,17 +171,28 @@ const RangePickerBase = kind({ wrap: PropTypes.bool }, + defaultProps: { + step: 1 + }, + computed: { + children: ({min, max, step, value}) => { + // send to internal/DrumPicker only 5 children. Current selected +/-2 + const childrenArray = Array(Math.floor((max - min) / step) + 1).fill(min).map( ((x, i) => (x + i * step))).filter(child => child >= value - (step * 2) && child <= value + (step * 2)); + return (mapAndFilterChildren(childrenArray, (child) => ( + {child} + ))); + }, disabled: ({disabled, max, min}) => min >= max ? true : disabled, value: ({min, max, value}) => { return clamp(min, max, value); } }, - render: ({value, ...rest}) => { + render: ({children, value, ...rest}) => { return ( - - {value} + + {children} ); } @@ -197,8 +208,7 @@ const RangePickerBase = kind({ */ const RangePickerDecorator = compose( Pure, - Changeable, - ChangeAdapter + Changeable ); /** diff --git a/RangePicker/tests/RangePicker-specs.js b/RangePicker/tests/RangePicker-specs.js index 69e3e0962..fc26ee012 100644 --- a/RangePicker/tests/RangePicker-specs.js +++ b/RangePicker/tests/RangePicker-specs.js @@ -2,45 +2,62 @@ import {mount} from 'enzyme'; import {RangePicker, RangePickerBase} from '../RangePicker'; -import css from '../../internal/Picker/Picker.module.less'; +import css from '../../internal/DrumPicker/DrumPicker.module.less'; -const decrement = (picker) => picker.find(`.${css.itemDecrement}`).first().simulate('click'); -const increment = (picker) => picker.find(`.${css.itemIncrement}`).first().simulate('click'); +const keyDown = (keyCode) => (picker) => picker.find(`.${css.root}`).first().simulate('keydown', {keyCode}); + +const upKeyDown = keyDown(38); +const downKeyDown = keyDown(40); describe('RangePicker Specs', () => { + beforeEach(() => { + global.Element.prototype.getBoundingClientRect = jest.fn(() => { + return { + bottom: 310, + height: 84, + left: 45, + right: 1348, + top: 226, + width: 1303, + x: 45, + y: 226 + }; + }); + }); + test('should render a single child with the current value', () => { const picker = mount( ); const expected = '10'; - const actual = picker.find('.active').first().text(); + const actual = picker.find('.selectedItem').first().text(); expect(actual).toBe(expected); }); test('should increase by step amount on increment press', () => { const picker = mount( - + ); - increment(picker); + downKeyDown(picker); const expected = '11'; - const actual = picker.find('.active').first().text(); + const actual = picker.find('.selectedItem').first().text(); expect(actual).toBe(expected); }); test('should decrease by step amount on decrement press', () => { const picker = mount( - + ); - decrement(picker); + upKeyDown(picker); const expected = '9'; - const actual = picker.find('.active').first().text(); + const actual = picker.find('.selectedItem').first().text(); expect(actual).toBe(expected); }); @@ -50,7 +67,7 @@ describe('RangePicker Specs', () => { ); - const actual = picker.find('Picker').last().prop('disabled'); + const actual = picker.find('DrumPicker').last().prop('disabled'); expect(actual).toBe(true); }); }); diff --git a/TimePicker/tests/TimePicker-specs.js b/TimePicker/tests/TimePicker-specs.js index a3f2a55ab..bc24ca037 100644 --- a/TimePicker/tests/TimePicker-specs.js +++ b/TimePicker/tests/TimePicker-specs.js @@ -7,9 +7,6 @@ import css from '../TimePicker.module.less'; // otherwise, nothing renders in the label. describe('TimePicker', () => { - - // Suite-wide setup - test('should emit an onChange event when changing a component picker', () => { const handleChange = jest.fn(); diff --git a/internal/DateComponentPicker/DateComponentPicker.js b/internal/DateComponentPicker/DateComponentPicker.js index 9c84945a2..95148aac6 100644 --- a/internal/DateComponentPicker/DateComponentPicker.js +++ b/internal/DateComponentPicker/DateComponentPicker.js @@ -4,13 +4,13 @@ import Changeable from '@enact/ui/Changeable'; import PropTypes from 'prop-types'; import {Children} from 'react'; -import PickerCore, {PickerItem} from '../Picker'; +import PickerCore, {DrumPickerItem} from '../DrumPicker'; -import css from './DateComponentPicker.module.less'; +import componentCss from './DateComponentPicker.module.less'; /** * {@link agate/internal/DataComponentPicker.DateComponentPickerBase} allows the selection of one - * part of the date or time using a {@link agate/internal/Picker.Picker}. + * part of the date or time using a {@link agate/internal/DrumPicker.DrumPicker}. * * @class DateComponentPickerBase * @memberof agate/internal/DateComponentPicker @@ -66,23 +66,23 @@ const DateComponentPickerBase = kind({ }, styles: { - css, + css: componentCss, className: 'dateComponentPicker' }, computed: { children: ({children}) => mapAndFilterChildren(children, (child) => ( - {child} + {child} )), max: ({children}) => children ? Children.count(children) - 1 : 0 }, - render: ({accessibilityHint, 'aria-valuetext': ariaValuetext, children, max, value, wrap, ...rest}) => ( + render: ({accessibilityHint, 'aria-valuetext': ariaValuetext, children, className, max, value, wrap, ...rest}) => ( ( + render: ({accessibilityHint, className, max, min, value, wrap, ...rest}) => ( element.props.children === value)); + selectedValue = value; + } else { + selectedIndex = value; + selectedValue = value; //this.props.children[value].props.children; + } + + this.state = { + selectedIndex: selectedIndex, + value: selectedValue + }; + + this.scrollY = -1; + this.lastY = 0; + this.startY = 0; + this.scrollX = -1; + this.lastX = 0; + this.startX = 0; + this.isMoving = false; + } + + static getDerivedStateFromProps (props, state) { + if (props.type !== 'number' && props.value !== state.value) { + return { + value: props.value, + selectedIndex: props.value + }; + } + return null; + } + + componentDidMount () { + const {children} = this.props; + + for (let i = 0; i < children.length; i++) { + if (i === this.state.selectedIndex) { + this.scrollTo(i, false); + return; + } + } + } + + componentDidUpdate (prevProps, prevState) { + const {children, type, value} = this.props; + console.log(prevState.selectedIndex, this.state.selectedIndex, prevState.value, this.state.value); + if (prevState.selectedIndex !== this.state.selectedIndex && type === 'number') { + setTimeout( () => { + const selectedIndex = clamp(0, children.length - 1, children.findIndex((element) => element.props.children === value)); + for (let i = 0; i < children.length; i++) { + if (i === selectedIndex) { + this.scrollTo(i, false); + return; + } + } + }, 0) + } else if (prevState.selectedIndex !== this.state.selectedIndex && type !== 'number') { + const selectedIndex = clamp(0, children.length, children.findIndex((element, index) => index === this.state.selectedIndex)); + + for (let i = 0; i < children.length; i++) { + if (i === selectedIndex) { + this.scrollTo(i, false); + return; + } + } + } + } + + shouldComponentUpdate (nextProps, nextState) { + if ( nextState.selectedIndex === this.state.selectedIndex && nextState.value === this.state.value) { + return false; + } + return true; + } + + scrollTo = (val, transition) => { + const {children, orientation, type} = this.props; + if (!children || children.length === 0) return; + + const index = clamp(0, children.length, Math.min(val, children.length - 1)); + + let child; + if (type === 'number') { + child = children[index].props.children; + } else { + child = index; + } + + if (orientation === 'vertical') { + const itemHeight = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().height, 'rem').slice(0, -3)); + + if (this.scrollY !== val * itemHeight) { + this.scrollY = val * itemHeight; + + this.contentRef.style.transform = `translate(0, ${-((val + 1) * itemHeight)}rem)`; + + if (this.scrollY >= 0 && (child || child === 0)) { + setTimeout(() => { + this.changeValue(index, child); + }, transition? 300 : 0) + } + + } + } else { + const itemWidth = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().width, 'rem').slice(0, -3)); + + if (this.scrollX !== val * itemWidth) { + this.scrollX = val * itemWidth; + + this.contentRef.style.transform = `translate(${-((val + 1) * itemWidth)}rem, 0)`; + + if (this.scrollX >= 0 && (child || child === 0)) { + setTimeout(() => { + this.changeValue(index, child); + }, transition? 300 : 0) + } + } + } + }; + + changeValue = (index, value) => { + const {type, onChange} = this.props; + const oldValue = this.state.value; + if (index !== this.state.selectedIndex) { + this.setState({ + selectedIndex: index, + value: value + }, () => { + if (value !== oldValue) { + if (type === 'number') { + onChange({value}); + } else { + onChange({value: index}); + } + } + }); + + } + }; + + handleDecrement = () => { + this.handleClick(-1); + }; + + handleIncrement = () => { + this.handleClick(1); + }; + + handleClick = (direction) => { + const {orientation, wrap} = this.props; + + if (!this.props.disabled && this.props.children.length > 0) { + let itemHeight = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().height, 'rem').slice(0, -3)); + let itemWidth = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().width, 'rem').slice(0, -3)); + // this is to avoid division by 0 + if (itemHeight === 0) { + itemHeight = 1; + } + if (itemWidth === 0) { + itemWidth = 1; + } + + this.contentRef.style.transition = 'transform 300ms'; + + if (orientation === 'horizontal') { + this.scrollTo(wrap ? this.wrapRange(0, this.props.children.length - 1, this.scrollX / itemWidth + direction) : clamp(0, this.props.children.length - 1, this.scrollX / itemWidth + direction), true); + } else if (orientation === 'vertical') { + this.scrollTo(wrap ? this.wrapRange(0, this.props.children.length - 1, this.scrollY / itemHeight + direction) : clamp(0, this.props.children.length - 1, this.scrollY / itemHeight + direction), true); + } + // remove transition for further touch related changes + setTimeout(() => { + this.contentRef.style.transition = 'none'; + }, 300); + } + }; + + onStart = (position) => { + if (this.props.disabled || this.props.children.length === 0) { + return; + } + this.isMoving = true; + + if (this.props.orientation === 'vertical') { + this.startY = position.pageY / ri.unitToPixelFactors['rem']; + this.lastY = this.scrollY; + } else { + this.startX = position.pageX / ri.unitToPixelFactors['rem']; + this.lastX = this.scrollX; + } + + }; + + onMove = (position) => { + if (this.props.disabled || this.props.children.length === 0 || !this.isMoving) { + return; + } + + const unitToPixelFactor = ri.unitToPixelFactors['rem']; + + if (this.props.orientation === 'vertical') { + const itemHeight = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().height, 'rem').slice(0, -3)); + this.scrollY = (this.lastY - ( position.pageY / unitToPixelFactor) + this.startY); + this.contentRef.style.transform = `translate(0, ${-this.scrollY - itemHeight}rem)`; + } else { + const itemWidth = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().width, 'rem').slice(0, -3)); + this.scrollX = (this.lastX - (position.pageX / unitToPixelFactor) + this.startX); + this.contentRef.style.transform = `translate(${-this.scrollX - itemWidth}rem, 0)`; + } + }; + + onFinish = () => { + this.isMoving = false; + + if (this.props.orientation === 'vertical') { + const itemHeight = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().height, 'rem').slice(0, -3)); + + let targetY = this.scrollY; + const height = (this.props.children.length - 1) * itemHeight; + if (targetY % itemHeight !== 0) { + targetY = Math.round(targetY / itemHeight) * itemHeight; + } + if (targetY < 0) { + targetY = 0; + } else if (targetY > height) { + targetY = height; + } + this.scrollTo(targetY / itemHeight, false); + } else { + const itemWidth = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().width, 'rem').slice(0, -3)); + + let targetX = this.scrollX; + const height = (this.props.children.length - 1) * itemWidth; + if (targetX % itemWidth !== 0) { + targetX = Math.round(targetX / itemWidth) * itemWidth; + } + if (targetX < 0) { + targetX = 0; + } else if (targetX > height) { + targetX = height; + } + this.scrollTo(targetX / itemWidth, false); + } + }; + + + wrapRange = (min, max, value) => { + if (value > max) { + return min + (value - max - 1); + } else if (value < min) { + return max - (min - value - 1); + } else { + return value; + } + }; + + currentValueText = () => { + const {accessibilityHint, 'aria-valuetext': ariaValueText, children, value} = this.props; + if (ariaValueText != null) { + return ariaValueText; + } + + let valueText = value; + + if (children && Array.isArray(children)) { + if (children[value] && children[value].props) { + valueText = children[value].props.children; + } else { + valueText = children[value]; + } + } + + if (accessibilityHint) { + valueText = `${valueText} ${accessibilityHint}`; + } + + return valueText; + }; + + decrementAriaLabel = () => { + const {decrementAriaLabel} = this.props; + if (decrementAriaLabel != null) { + return decrementAriaLabel; + } + + if (!Array.isArray(this.props.children)) { + return `${$L('decrease the value')}`; + } else { + return `${$L('previous item')}`; + } + }; + + incrementAriaLabel= () => { + const {incrementAriaLabel} = this.props; + if (incrementAriaLabel != null) { + return incrementAriaLabel; + } + + if (!Array.isArray(this.props.children)) { + return `${$L('increase the value')}`; + } else { + return `${$L('next item')}`; + } + }; + + calcAriaLabel = () => { + const {'aria-label': ariaLabel} = this.props; + if (ariaLabel != null) { + return ariaLabel; + } + return this.currentValueText(); + }; + + handleKeyDown = (ev) => { + const {orientation, wrap} = this.props; + const {keyCode} = ev; + forwardKeyDown(ev, this.props); + + if (!this.props.disabled && this.props.children.length > 0) { + let itemHeight = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().height, 'rem').slice(0, -3)); + let itemWidth = parseFloat(ri.unit(this.indicatorRef.getBoundingClientRect().width, 'rem').slice(0, -3)); + // this is to avoid division by 0 + if (itemHeight === 0) { + itemHeight = 1; + } + if (itemWidth === 0) { + itemWidth = 1; + } + + this.contentRef.style.transition = 'transform 300ms'; + + if (orientation === 'horizontal' && isLeft(keyCode)) { + ev.stopPropagation(); + this.scrollTo(wrap ? this.wrapRange(0, this.props.children.length - 1, this.scrollX / itemWidth - 1) : clamp(0, this.props.children.length - 1, this.scrollX / itemWidth - 1), true); + } else if (orientation === 'horizontal' && isRight(keyCode) ) { + ev.stopPropagation(); + this.scrollTo(wrap ? this.wrapRange(0, this.props.children.length - 1, this.scrollX / itemWidth + 1) : clamp(0, this.props.children.length - 1, this.scrollX / itemWidth + 1), true); + } else if (orientation === 'vertical' && isUp(keyCode)) { + ev.stopPropagation(); + this.scrollTo(wrap ? this.wrapRange(0, this.props.children.length - 1, this.scrollY / itemHeight - 1) : clamp(0, this.props.children.length - 1, this.scrollY / itemHeight - 1), true); + } else if (orientation === 'vertical' && isDown(keyCode) ) { + ev.stopPropagation(); + this.scrollTo(wrap ? this.wrapRange(0, this.props.children.length - 1, this.scrollY / itemHeight + 1) : clamp(0, this.props.children.length - 1, this.scrollY / itemHeight + 1), true); + } + + // remove transition for further touch related changes + setTimeout(() => { + this.contentRef.style.transition = 'none'; + }, 300); + } + }; + + handle = handle.bind(this); + + handleFlick = this.handle( + forEventProp('direction', 'vertical'), + // ignore "slow" flicks by filtering out velocity below a threshold + oneOf( + [({velocityY}) => velocityY < 0, this.handleIncrement], + [({velocityY}) => velocityY > 0, this.handleDecrement] + ) + ); + + valueId = (id) => `${id}_value`; + + initRef (prop) { + return (ref) => { + // eslint-disable-next-line react/no-find-dom-node + this[prop] = ref && ReactDOM.findDOMNode(ref); + }; + } + + render () { + const { + className, + disabled, + id, + onSpotlightDisappear, + orientation, + spotlightDisabled, + width, + ...rest + } = this.props; + + let {children: values} = this.props; + + const currentValueText = this.currentValueText(); + const decAriaLabel = this.decrementAriaLabel(); + const incAriaLabel = this.incrementAriaLabel(); + const decrementAriaLabel = `${currentValueText} ${decAriaLabel}`; + const incrementAriaLabel = `${currentValueText} ${incAriaLabel}`; + const indicatorAriaLabel = this.calcAriaLabel(); + + let sizingPlaceholder = null; + if (typeof width === 'number' && width > 0) { + sizingPlaceholder =
{'0'.repeat(width)}
; + } + + delete rest['aria-valuetext']; + delete rest.accessibilityHint; + delete rest.decrementAriaLabel; + delete rest.incrementAriaLabel; + delete rest.index; + delete rest.max; + delete rest.min; + delete rest.noAnimation; + delete rest.onChange; + delete rest.reverseTransition; + delete rest.step; + delete rest.type; + delete rest.value; + delete rest.wrap; + + const itemDecrementProps = { + 'aria-controls': this.valueId(id), + 'aria-disabled':disabled, + 'aria-label':decrementAriaLabel, + className: classnames(css.itemDecrement, css.item) + }; + + const itemIncrementProps = { + 'aria-controls': this.valueId(id), + 'aria-disabled':disabled, + 'aria-label':incrementAriaLabel, + className: classnames(css.itemIncrement, css.item) + }; + + const selectedItemProps = { + className: classnames(css.selectedItem, css.item) + }; + + const otherItemProps = { + className: css.item + }; + + values = values.map((value, index) => { + let itemProps; + let onClickEvent; + if (this.state.selectedIndex === index + 1) { + itemProps = itemDecrementProps; + onClickEvent = this.handleDecrement; + } else if (this.state.selectedIndex === index - 1) { + itemProps = itemIncrementProps; + onClickEvent = this.handleIncrement; + } else if (this.state.selectedIndex === index) { + itemProps = selectedItemProps; + } else { + itemProps = otherItemProps; + } + return ( +
+ {sizingPlaceholder} + {value} +
+ ); + }); + + return ( +
this.onStart(evt)} + onMouseLeave={this.onFinish} + onMouseMove={(evt) => { + evt.preventDefault(); this.onMove(evt); + }} + onMouseUp={this.onFinish} + onSpotlightDisappear={onSpotlightDisappear} + onTouchCancel={this.onFinish} + onTouchEnd={this.onFinish} + onTouchMove={(evt) => { + evt.preventDefault(); this.onMove(evt.touches[0]); + }} + onTouchStart={(evt) => this.onStart(evt.touches[0])} + ref={this.initRootRef} + spotlightDisabled={spotlightDisabled} + > +
+
+ {values} +
+
+ ); + } +}; + +/** + * Applies Agate specific behaviors to [DrumPicker]{@link agate/DrumPicker.DrumPicker}. + * + * @hoc + * @memberof agate/internal/DrumPicker + * @mixes agate/Skinnable.Skinnable + * @private + */ +const DrumPickerDecorator = compose( + IdProvider({generateProp: null}), + Skinnable +); + +const DrumPicker = DrumPickerDecorator(DrumPickerBase); + +export default DrumPicker; +export { + DrumPicker, + DrumPickerBase +}; +export DrumPickerItem from './DrumPickerItem'; diff --git a/internal/DrumPicker/DrumPicker.module.less b/internal/DrumPicker/DrumPicker.module.less new file mode 100644 index 000000000..9602efbf6 --- /dev/null +++ b/internal/DrumPicker/DrumPicker.module.less @@ -0,0 +1,112 @@ +// DrumPicker.module.less +// +@import "../../styles/mixins.less"; +@import "../../styles/variables.less"; +@import "../../styles/skin.less"; + +.drumPicker { + align-items: center; + justify-content: center; + min-width: 72px; + overflow: hidden; + position: relative; + + .root { + display: flex; + flex-direction: column; + text-align: center; + z-index: 1; + } + + &.horizontal { + .root { + display: inline-flex; + flex-direction: row; + } + } + + .applySkins({ + font-weight: @agate-picker-font-weight; + font-size: @agate-picker-font-size; + border-radius: @agate-picker-border-radius; + transform: @agate-picker-transform; + height: @agate-drumPicker-height; + padding: @agate-drumPicker-padding; + + .focus({ + background-color: @agate-drumPicker-focus-bg-color; + background-image: @agate-drumPicker-focus-bg-image; + }); + + .root { + padding: @agate-drumPicker-root-padding; + } + + .sizingPlaceholder { + font-size: @agate-picker-active-font-size; + font-weight: @agate-picker-active-font-weight; + height: 0; + line-height: 0; + padding-left: .extract(@agate-picker-padding, left)[]; + padding-right: .extract(@agate-picker-padding, right)[]; + visibility: hidden; + } + + .item, + .itemDecrement, + .itemIncrement { + height: @agate-drumPicker-item-height; + line-height: @agate-drumPicker-item-height; + width: auto; + + + &.selectedItem { + color: @agate-picker-active-color; + font-size: @agate-picker-active-font-size; + font-weight: @agate-picker-active-font-weight; + } + + .focus({ + color: @agate-picker-item-focus-color; + }); + + } + + .indicator { + background-color: @agate-picker-active-bg-color; + background-image: @agate-picker-active-bg-image; + height: @agate-drumPicker-item-height; + left: 0; + margin: @agate-drumPicker-margin; + position: absolute; + right: 0; + top: @agate-drumPicker-item-height; + z-index: -1; + } + + &.horizontal { + height: @agate-drumPicker-item-height; + width: calc(3*@agate-picker-horizontal-item-width); + padding: @agate-drumPicker-horizontal-padding; + + .root { + padding: @agate-drumPicker-horizontal-root-padding; + } + + .item, + .itemDecrement, + .itemIncrement { + bottom: 0; + margin: @agate-drumPicker-horizontal-margin; + top: 0; + width: @agate-picker-horizontal-item-width; + } + + .indicator { + bottom: 0; + left: @agate-picker-horizontal-item-width; + top: 0; + } + } + }); +} diff --git a/internal/DrumPicker/DrumPickerItem.js b/internal/DrumPicker/DrumPickerItem.js new file mode 100644 index 000000000..e2c0a6654 --- /dev/null +++ b/internal/DrumPicker/DrumPickerItem.js @@ -0,0 +1,42 @@ +import kind from '@enact/core/kind'; +import Marquee from '@enact/ui/Marquee'; + +import css from './DrumPicker.module.less'; + +/** + * Renders an Agate-styled Picker Item without any behavior. + * + * @class DrumPickerItemBase + * @memberof agate/DrumPickerItem + * @extends ui/Marquee.Marquee + * @ui + * @private + */ +const DrumPickerItemBase = kind({ + name: 'DrumPickerItem', + + styles: { + css, + className: 'item', + publicClassNames: true + }, + + render: (props) => ( + + ) +}); + +/** + * An Agate styled DrumPickerItem with built-in support for marqueed text. + * + * @class DrumPickerItem + * @memberof agate/DrumPickerItem + * @extends agate/DrumPickerItem.DrumPickerItemBase + * @ui + * @private + */ +export default DrumPickerItemBase; +export { + DrumPickerItemBase as DrumPickerItem, + DrumPickerItemBase +}; diff --git a/internal/DrumPicker/package.json b/internal/DrumPicker/package.json new file mode 100644 index 000000000..7e895c7a8 --- /dev/null +++ b/internal/DrumPicker/package.json @@ -0,0 +1,3 @@ +{ + "main": "DrumPicker.js" +} diff --git a/internal/DrumPicker/tests/DrumPicker-specs.js b/internal/DrumPicker/tests/DrumPicker-specs.js new file mode 100644 index 000000000..2b73a946c --- /dev/null +++ b/internal/DrumPicker/tests/DrumPicker-specs.js @@ -0,0 +1,140 @@ +import {mount} from 'enzyme'; + +import DrumPicker from '../DrumPicker'; +import DrumPickerItem from '../DrumPickerItem'; + +import css from '../DrumPicker.module.less'; + +const keyDown = (keyCode) => (picker) => picker.find(`.${css.root}`).first().simulate('keydown', {keyCode}); + +const upKeyDown = keyDown(38); +const downKeyDown = keyDown(40); + +describe('Picker Specs', () => { + beforeEach(() => { + global.Element.prototype.getBoundingClientRect = jest.fn(() => { + return { + bottom: 310, + height: 84, + left: 45, + right: 1348, + top: 226, + width: 1303, + x: 45, + y: 226 + }; + }); + }); + + test('should have a default \'value\' of 0', () => { + const picker = mount( + + ); + + const expected = 0; + const actual = picker.find('DrumPicker').prop('value'); + + expect(actual).toBe(expected); + }); + + test('should return an object {value: Number} that represents the next value of the Picker component when pressing the increment
', + () => { + const handleChange = jest.fn(); + const picker = mount( + + {0} + + ); + downKeyDown(picker); + + const expected = 1; + const actual = handleChange.mock.calls[0][0].value; + + expect(actual).toBe(expected); + } + ); + + test('should return an object {value: Number} that represents the next value of the Picker component when pressing the decrement
', + () => { + const handleChange = jest.fn(); + const picker = mount( + + ); + + upKeyDown(picker); + + const expected = -1; + const actual = handleChange.mock.calls[0][0].value; + + expect(actual).toBe(expected); + } + ); + + test('should not run the onChange handler when disabled', () => { + const handleChange = jest.fn(); + const picker = mount( + + ); + + downKeyDown(picker); + + const expected = 0; + const actual = handleChange.mock.calls.length; + + expect(actual).toBe(expected); + }); + + test('should increment by \'step\' value', () => { + const handleChange = jest.fn(); + const picker = mount( + + ); + + downKeyDown(picker); + + const expected = 3; + const actual = handleChange.mock.calls[0][0].value; + + expect(actual).toBe(expected); + }); + + test('should decrement by \'step\' value', () => { + const handleChange = jest.fn(); + const picker = mount( + + ); + + upKeyDown(picker); + + const expected = 0; + const actual = handleChange.mock.calls[0][0].value; + + expect(actual).toBe(expected); + }); + + test('should have no increment button when there is no value to increment', + () => { + const picker = mount( + + ); + + const expected = false; + const actual = picker.find(`.${css.itemIncrement}`).exists(); + + expect(actual).toBe(expected); + } + ); + + test('should have no decrement button when there is no value to decrement', + () => { + const picker = mount( + + ); + + const expected = false; + const actual = picker.find(`.${css.itemDecrement}`).exists(); + + expect(actual).toBe(expected); + } + ); +}); diff --git a/samples/sampler/stories/default/Picker.js b/samples/sampler/stories/default/Picker.js index cbdab6ae7..24a8763bc 100644 --- a/samples/sampler/stories/default/Picker.js +++ b/samples/sampler/stories/default/Picker.js @@ -1,11 +1,11 @@ import {mergeComponentMetadata} from '@enact/storybook-utils'; import {action} from '@enact/storybook-utils/addons/actions'; import {boolean, select, text} from '@enact/storybook-utils/addons/knobs'; -import {PickerBase} from '@enact/agate/internal/Picker'; +import {DrumPickerBase} from '@enact/agate/internal/DrumPicker'; import Picker from '@enact/agate/Picker'; Picker.displayName = 'Picker'; -const Config = mergeComponentMetadata('Picker', Picker, PickerBase); +const Config = mergeComponentMetadata('Picker', Picker, DrumPickerBase); export default { title: 'Agate/Picker', diff --git a/samples/sampler/stories/default/RangePicker.js b/samples/sampler/stories/default/RangePicker.js index 14dc9488c..cad897463 100644 --- a/samples/sampler/stories/default/RangePicker.js +++ b/samples/sampler/stories/default/RangePicker.js @@ -1,11 +1,11 @@ import {mergeComponentMetadata} from '@enact/storybook-utils'; import {action} from '@enact/storybook-utils/addons/actions'; import {boolean, number, select} from '@enact/storybook-utils/addons/knobs'; -import {PickerBase} from '@enact/agate/internal/Picker'; +import {DrumPickerBase} from '@enact/agate/internal/DrumPicker'; import RangePicker from '@enact/agate/RangePicker'; RangePicker.displayName = 'RangePicker'; -const Config = mergeComponentMetadata('RangePicker', RangePicker, PickerBase); +const Config = mergeComponentMetadata('RangePicker', RangePicker, DrumPickerBase); export default { title: 'Agate/RangePicker', diff --git a/styles/colors-base.less b/styles/colors-base.less index 651c6f062..87a9951a3 100644 --- a/styles/colors-base.less +++ b/styles/colors-base.less @@ -190,6 +190,11 @@ @agate-drawer-border-color: @agate-popup-border-color; @agate-drawer-shadow: inherit; +// DrumPicker +// --------------------------------------- +@agate-drumPicker-focus-bg-color: @agate-accent; +@agate-drumPicker-focus-bg-image : inherit; + // FanSpeedControl // --------------------------------------- @agate-fanspeedcontrol-color: @agate-text-color; diff --git a/styles/colors-silicon-day.less b/styles/colors-silicon-day.less index f4b958aed..af6077b17 100644 --- a/styles/colors-silicon-day.less +++ b/styles/colors-silicon-day.less @@ -172,6 +172,11 @@ @agate-drawer-bg-image: @agate-popup-bg-image; @agate-drawer-shadow: @agate-popup-shadow; +// DrumPicker +// --------------------------------------- +@agate-drumPicker-focus-bg-color: transparent; +@agate-drumPicker-focus-bg-image : @silicon-gradient; + // FullscreenPopup // --------------------------------------- @agate-fullscreenpopup-bg-image: @agate-bg-image; diff --git a/styles/variables-base.less b/styles/variables-base.less index 7e1bd813f..dc8f0ffbe 100644 --- a/styles/variables-base.less +++ b/styles/variables-base.less @@ -257,6 +257,18 @@ @agate-drawer-border: @agate-popup-border; @agate-drawer-padding: @agate-popup-padding; +// DrumPicker +// --------------------------------------- +@agate-drumPicker-item-height: @agate-button-height; +@agate-drumPicker-itemIncrement-top: (@agate-drumPicker-item-height * 2); +@agate-drumPicker-height: (@agate-drumPicker-item-height * 3); +@agate-drumPicker-padding: 0 6px; +@agate-drumPicker-margin: @agate-drumPicker-padding; +@agate-drumPicker-root-padding: (@agate-drumPicker-item-height * 2) 0; +@agate-drumPicker-horizontal-root-padding: 0 (@agate-picker-horizontal-item-width * 2); +@agate-drumPicker-horizontal-padding: 0; +@agate-drumPicker-horizontal-margin: @agate-drumPicker-horizontal-padding; + // FanSpeedControl // --------------------------------------- @agate-fanspeedcontrol-icon-font-size: 120px; diff --git a/styles/variables-electro.less b/styles/variables-electro.less index 7bb76f1f6..2664558d5 100644 --- a/styles/variables-electro.less +++ b/styles/variables-electro.less @@ -100,6 +100,10 @@ @agate-panels-vertical-tab-margin: 0 30px 0 0; @agate-panels-vertical-tab-width: 110%; +// DrumPicker +// --------------------------------------- +@agate-drumPicker-padding: 0; + // Picker // --------------------------------------- @agate-picker-border-radius: @electro-border-radius; diff --git a/tests/ui/apps/Picker/Picker-View.js b/tests/ui/apps/Picker/Picker-View.js index 84b57cefe..76d0d9782 100644 --- a/tests/ui/apps/Picker/Picker-View.js +++ b/tests/ui/apps/Picker/Picker-View.js @@ -9,10 +9,14 @@ const pickerList = [ ]; const app = (props) =>
-
- {pickerList} - {pickerList} - {pickerList} +
+ {pickerList} +
+
+ {pickerList} +
+
+ {pickerList}
; diff --git a/tests/ui/apps/RangePicker/RangePicker-View.js b/tests/ui/apps/RangePicker/RangePicker-View.js index 7bb3e5419..47374e258 100644 --- a/tests/ui/apps/RangePicker/RangePicker-View.js +++ b/tests/ui/apps/RangePicker/RangePicker-View.js @@ -2,10 +2,14 @@ import RangePicker from '../../../../RangePicker'; import ThemeDecorator from '../../../../ThemeDecorator'; const app = (props) =>
-
- - - +
+ +
+
+ +
+
+
; diff --git a/tests/ui/specs/DatePicker/DatePicker-specs.js b/tests/ui/specs/DatePicker/DatePicker-specs.js index 9962bacf3..3b57968a6 100644 --- a/tests/ui/specs/DatePicker/DatePicker-specs.js +++ b/tests/ui/specs/DatePicker/DatePicker-specs.js @@ -12,19 +12,19 @@ describe('DatePicker', function () { const datePicker = Page.components.datePickerDefault; it('should have month-day-year order', function () { - expect(datePicker.decrementer(datePicker.month).isFocused(), 'Month').to.be.true(); + Page.spotlightDown(); + expect(datePicker.month.isFocused(), 'Month').to.be.true(); Page.spotlightRight(); - expect(datePicker.decrementer(datePicker.day).isFocused(), 'Day').to.be.true(); + expect(datePicker.day.isFocused(), 'Day').to.be.true(); Page.spotlightRight(); - expect(datePicker.decrementer(datePicker.year).isFocused(), 'Year').to.be.true(); + expect(datePicker.year.isFocused(), 'Year').to.be.true(); }); describe('5-way', function () { it('should increase the month when incrementing the picker', function () { const {month} = extractValues(datePicker); - expect(datePicker.decrementer(datePicker.month).isFocused()).to.be.true(); + expect(datePicker.month.isFocused()).to.be.true(); Page.spotlightDown(); - Page.spotlightSelect(); const {month: value} = extractValues(datePicker); const expected = month < 12 ? month + 1 : 1; expect(value).to.equal(expected); @@ -32,8 +32,8 @@ describe('DatePicker', function () { it('should decrease the month when decrementing the picker', function () { const {month} = extractValues(datePicker); - expect(datePicker.decrementer(datePicker.month).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(datePicker.month.isFocused()).to.be.true(); + Page.spotlightUp(); const {month: value} = extractValues(datePicker); const expected = month > 1 ? month - 1 : 12; expect(value).to.equal(expected); @@ -43,9 +43,8 @@ describe('DatePicker', function () { const {day, month, year} = extractValues(datePicker); const numDays = daysInMonth({month, year}); Page.spotlightRight(); - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); + expect(datePicker.day.isFocused()).to.be.true(); Page.spotlightDown(); - Page.spotlightSelect(); const {day: value} = extractValues(datePicker); const expected = day !== numDays ? day + 1 : 1; expect(value).to.equal(expected); @@ -55,8 +54,8 @@ describe('DatePicker', function () { const {day, month, year} = extractValues(datePicker); const numDays = daysInMonth({month, year}); Page.spotlightRight(); - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(datePicker.day.isFocused()).to.be.true(); + Page.spotlightUp(); const {day: value} = extractValues(datePicker); const expected = day !== 1 ? day - 1 : numDays; expect(value).to.equal(expected); @@ -66,9 +65,8 @@ describe('DatePicker', function () { const {year} = extractValues(datePicker); Page.spotlightRight(); Page.spotlightRight(); - expect(datePicker.decrementer(datePicker.year).isFocused()).to.be.true(); + expect(datePicker.year.isFocused()).to.be.true(); Page.spotlightDown(); - Page.spotlightSelect(); const {year: value} = extractValues(datePicker); const expected = year + 1; expect(value).to.equal(expected); @@ -78,8 +76,8 @@ describe('DatePicker', function () { const {year} = extractValues(datePicker); Page.spotlightRight(); Page.spotlightRight(); - expect(datePicker.decrementer(datePicker.year).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(datePicker.year.isFocused()).to.be.true(); + Page.spotlightUp(); const {year: value} = extractValues(datePicker); const expected = year - 1; expect(value).to.equal(expected); @@ -90,7 +88,7 @@ describe('DatePicker', function () { it('should increase the month when incrementing the picker', function () { const {month} = extractValues(datePicker); datePicker.incrementer(datePicker.month).click(); - expect(datePicker.incrementer(datePicker.month).isFocused()).to.be.true(); + expect(datePicker.month.isFocused()).to.be.true(); const {month: value} = extractValues(datePicker); const expected = month < 12 ? month + 1 : 1; expect(value).to.equal(expected); @@ -99,7 +97,7 @@ describe('DatePicker', function () { it('should decrease the month when decrementing the picker', function () { const {month} = extractValues(datePicker); datePicker.decrementer(datePicker.month).click(); - expect(datePicker.decrementer(datePicker.month).isFocused()).to.be.true(); + expect(datePicker.month.isFocused()).to.be.true(); const {month: value} = extractValues(datePicker); const expected = month > 1 ? month - 1 : 12; expect(value).to.equal(expected); @@ -109,7 +107,7 @@ describe('DatePicker', function () { const {day, month, year} = extractValues(datePicker); const numDays = daysInMonth({month, year}); datePicker.incrementer(datePicker.day).click(); - expect(datePicker.incrementer(datePicker.day).isFocused()).to.be.true(); + expect(datePicker.day.isFocused()).to.be.true(); const {day: value} = extractValues(datePicker); const expected = day !== numDays ? day + 1 : 1; expect(value).to.equal(expected); @@ -119,7 +117,7 @@ describe('DatePicker', function () { const {day, month, year} = extractValues(datePicker); const numDays = daysInMonth({month, year}); datePicker.decrementer(datePicker.day).click(); - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); + expect(datePicker.day.isFocused()).to.be.true(); const {day: value} = extractValues(datePicker); const expected = day !== 1 ? day - 1 : numDays; expect(value).to.equal(expected); @@ -128,7 +126,7 @@ describe('DatePicker', function () { it('should increase the year when incrementing the picker', function () { const {year} = extractValues(datePicker); datePicker.incrementer(datePicker.year).click(); - expect(datePicker.incrementer(datePicker.year).isFocused()).to.be.true(); + expect(datePicker.year.isFocused()).to.be.true(); const {year: value} = extractValues(datePicker); const expected = year + 1; expect(value).to.equal(expected); @@ -137,7 +135,7 @@ describe('DatePicker', function () { it('should decrease the year when decrementing the picker', function () { const {year} = extractValues(datePicker); datePicker.decrementer(datePicker.year).click(); - expect(datePicker.decrementer(datePicker.year).isFocused()).to.be.true(); + expect(datePicker.year.isFocused()).to.be.true(); const {year: value} = extractValues(datePicker); const expected = year - 1; expect(value).to.equal(expected); @@ -150,9 +148,22 @@ describe('DatePicker', function () { const datePicker = Page.components.datePickerWithDefaultValue; describe('5-way', function () { - it('should not update on select', function () { + it('should not update when incrementing the picker', function () { datePicker.focus(); - Page.spotlightSelect(); + Page.spotlightRight(); + Page.spotlightDown(); + + const {day, month, year} = extractValues(datePicker); + + expect(day).to.equal(6); + expect(month).to.equal(6); // `Date` uses 0-indexed months, picker displays 1-indexed month values + expect(year).to.equal(2020); + }); + + it('should not update when decrementing the picker', function () { + datePicker.focus(); + Page.spotlightRight(); + Page.spotlightUp(); const {day, month, year} = extractValues(datePicker); @@ -168,21 +179,21 @@ describe('DatePicker', function () { const datePicker = Page.components.datePickerDisabled; it('should focus the disabled month picker', function () { - datePicker.decrementer(datePicker.month).click(); - expect(datePicker.decrementer(datePicker.month).isFocused()).to.be.true(); + datePicker.month.click(); + expect(datePicker.month.isFocused()).to.be.true(); }); it('should not increase the day when incrementing disabled picker', function () { - datePicker.incrementer(datePicker.day).click(); - expect(datePicker.incrementer(datePicker.day).isFocused()).to.be.true(); + datePicker.focus(); + Page.spotlightDown(); browser.pause(500); const {day: value} = extractValues(datePicker); expect(value).to.equal(1); }); it('should not decrease the day when decrementing disabled picker', function () { - datePicker.decrementer(datePicker.day).click(); - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); + datePicker.focus(); + Page.spotlightUp(); browser.pause(500); const {day: value} = extractValues(datePicker); expect(value).to.equal(1); @@ -203,14 +214,12 @@ describe('DatePicker', function () { it('should not update \'defaultValue\' on decrementing disabled picker', function () { const {day, month, year} = extractValues(datePicker); - datePicker.decrementer(datePicker.month).click(); - expect(datePicker.decrementer(datePicker.month).isFocused()).to.be.true(); - - datePicker.decrementer(datePicker.day).click(); - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); - - datePicker.decrementer(datePicker.year).click(); - expect(datePicker.decrementer(datePicker.year).isFocused()).to.be.true(); + datePicker.focus(); + Page.spotlightUp(); + Page.spotlightRight(); + Page.spotlightUp(); + Page.spotlightRight(); + Page.spotlightUp(); browser.pause(500); @@ -221,15 +230,12 @@ describe('DatePicker', function () { it('should not update \'defaultValue\' on incrementing disabled picker', function () { const {day, month, year} = extractValues(datePicker); - - datePicker.incrementer(datePicker.month).click(); - expect(datePicker.incrementer(datePicker.month).isFocused()).to.be.true(); - - datePicker.incrementer(datePicker.day).click(); - expect(datePicker.incrementer(datePicker.day).isFocused()).to.be.true(); - - datePicker.incrementer(datePicker.year).click(); - expect(datePicker.incrementer(datePicker.year).isFocused()).to.be.true(); + datePicker.focus(); + Page.spotlightDown(); + Page.spotlightRight(); + Page.spotlightDown(); + Page.spotlightRight(); + Page.spotlightDown(); browser.pause(500); @@ -247,16 +253,16 @@ describe('DatePicker', function () { Page.open('?locale=ar-SA'); }); - it('should focus rightmost picker (day) when selected', function () { - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); - }); - it('should have day-month-year order', function () { - expect(datePicker.decrementer(datePicker.day).isFocused()).to.be.true(); + datePicker.focus(); + Page.spotlightRight(); + Page.spotlightRight(); + + expect(datePicker.day.isFocused()).to.be.true(); Page.spotlightLeft(); - expect(datePicker.decrementer(datePicker.month).isFocused()).to.be.true(); + expect(datePicker.month.isFocused()).to.be.true(); Page.spotlightLeft(); - expect(datePicker.decrementer(datePicker.year).isFocused()).to.be.true(); + expect(datePicker.year.isFocused()).to.be.true(); }); }); }); diff --git a/tests/ui/specs/DatePicker/DatePicker-utils.js b/tests/ui/specs/DatePicker/DatePicker-utils.js index 186218a9d..1cb527ca0 100644 --- a/tests/ui/specs/DatePicker/DatePicker-utils.js +++ b/tests/ui/specs/DatePicker/DatePicker-utils.js @@ -4,9 +4,9 @@ const daysInMonth = ({month, year}) => new Date(year, month, 0).getDate(); const extractValues = (picker) => { - const day = parseInt(picker.active(picker.day).getText()); - const month = parseInt(picker.active(picker.month).getText()); - const year = parseInt(picker.active(picker.year).getText()); + const day = parseInt(picker.selectedItem(picker.day).getText()); + const month = parseInt(picker.selectedItem(picker.month).getText()); + const year = parseInt(picker.selectedItem(picker.year).getText()); return {day, month, year}; }; diff --git a/tests/ui/specs/DatePicker/DatePickerPage.js b/tests/ui/specs/DatePicker/DatePickerPage.js index aa7ade08b..aaa0ff738 100644 --- a/tests/ui/specs/DatePicker/DatePickerPage.js +++ b/tests/ui/specs/DatePicker/DatePickerPage.js @@ -27,15 +27,15 @@ class PickerInterface { } decrementer (picker) { - return element('.internal_Picker_Picker_itemDecrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemDecrement', picker); } incrementer (picker) { - return element('.internal_Picker_Picker_itemIncrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemIncrement', picker); } - active (picker) { - return element('.internal_Picker_Picker_active', picker); + selectedItem (picker) { + return element('.internal_DrumPicker_DrumPicker_selectedItem', picker); } } diff --git a/tests/ui/specs/DateTimePicker/DateTimePicker-specs.js b/tests/ui/specs/DateTimePicker/DateTimePicker-specs.js index 890ab7c32..8eab35717 100644 --- a/tests/ui/specs/DateTimePicker/DateTimePicker-specs.js +++ b/tests/ui/specs/DateTimePicker/DateTimePicker-specs.js @@ -12,33 +12,17 @@ describe('DateTimePicker', function () { const dateTimePicker = Page.components.dateTimePickerDefault; it('should have hour-minute-meridiem-month-day-year order', function () { - const {meridiem} = extractValues(dateTimePicker); - if (meridiem === 'AM') { - Page.spotlightDown(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour focused'}); - Page.spotlightRight(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute focused'}); - Page.spotlightRight(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem focused'}); - Page.spotlightRight(); - expect(dateTimePicker.incrementer(dateTimePicker.month).isFocused(), 'Month').to.be.true(); - Page.spotlightRight(); - expect(dateTimePicker.incrementer(dateTimePicker.day).isFocused(), 'Day').to.be.true(); - Page.spotlightRight(); - expect(dateTimePicker.incrementer(dateTimePicker.year).isFocused(), 'Year').to.be.true(); - } else { - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour focused'}); - Page.spotlightRight(); - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute focused'}); - Page.spotlightRight(); - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem focused'}); - Page.spotlightRight(); - expect(dateTimePicker.decrementer(dateTimePicker.month).isFocused(), 'Month').to.be.true(); - Page.spotlightRight(); - expect(dateTimePicker.decrementer(dateTimePicker.day).isFocused(), 'Day').to.be.true(); - Page.spotlightRight(); - expect(dateTimePicker.decrementer(dateTimePicker.year).isFocused(), 'Year').to.be.true(); - } + browser.waitUntil(() => dateTimePicker.hour.isFocused(), {timeout: 1500, timeoutMsg: 'hour focused'}); + Page.spotlightRight(); + browser.waitUntil(() => dateTimePicker.minute.isFocused(), {timeout: 1500, timeoutMsg: 'minute focused'}); + Page.spotlightRight(); + browser.waitUntil(() => dateTimePicker.meridiem.isFocused(), {timeout: 1500, timeoutMsg: 'meridiem focused'}); + Page.spotlightRight(); + expect(dateTimePicker.month.isFocused(), 'Month').to.be.true(); + Page.spotlightRight(); + expect(dateTimePicker.day.isFocused(), 'Day').to.be.true(); + Page.spotlightRight(); + expect(dateTimePicker.year.isFocused(), 'Year').to.be.true(); }); describe('pointer', function () { @@ -61,7 +45,7 @@ describe('DateTimePicker', function () { it('should increase the minute when incrementing the picker', function () { const {minute} = extractValues(dateTimePicker); dateTimePicker.incrementer(dateTimePicker.minute).click(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.minute).isFocused(), {timeout: 1500, interval: 100}); + browser.waitUntil(() => dateTimePicker.minute.isFocused(), {timeout: 1500, interval: 100}); const {minute: value} = extractValues(dateTimePicker); const expected = minute !== 59 ? minute + 1 : 0; expect(value).to.equal(expected); @@ -70,7 +54,7 @@ describe('DateTimePicker', function () { it('should decrease the minute when decrementing the picker', function () { const {minute} = extractValues(dateTimePicker); dateTimePicker.decrementer(dateTimePicker.minute).click(); - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.minute).isFocused(), {timeout: 1500, interval: 100}); + browser.waitUntil(() => dateTimePicker.minute.isFocused(), {timeout: 1500, interval: 100}); const {minute: value} = extractValues(dateTimePicker); const expected = minute !== 0 ? minute - 1 : 59; expect(value).to.equal(expected); @@ -97,7 +81,7 @@ describe('DateTimePicker', function () { it('should increase the month when incrementing the picker', function () { const {month} = extractValues(dateTimePicker); dateTimePicker.incrementer(dateTimePicker.month).click(); - expect(dateTimePicker.incrementer(dateTimePicker.month).isFocused()).to.be.true(); + expect(dateTimePicker.month.isFocused()).to.be.true(); const {month: value} = extractValues(dateTimePicker); const expected = month < 12 ? month + 1 : 1; expect(value).to.equal(expected); @@ -106,7 +90,7 @@ describe('DateTimePicker', function () { it('should decrease the month when decrementing the picker', function () { const {month} = extractValues(dateTimePicker); dateTimePicker.decrementer(dateTimePicker.month).click(); - expect(dateTimePicker.decrementer(dateTimePicker.month).isFocused()).to.be.true(); + expect(dateTimePicker.month.isFocused()).to.be.true(); const {month: value} = extractValues(dateTimePicker); const expected = month > 1 ? month - 1 : 12; expect(value).to.equal(expected); @@ -116,7 +100,7 @@ describe('DateTimePicker', function () { const {day, month, year} = extractValues(dateTimePicker); const numDays = daysInMonth({month, year}); dateTimePicker.incrementer(dateTimePicker.day).click(); - expect(dateTimePicker.incrementer(dateTimePicker.day).isFocused()).to.be.true(); + expect(dateTimePicker.day.isFocused()).to.be.true(); const {day: value} = extractValues(dateTimePicker); const expected = day !== numDays ? day + 1 : 1; expect(value).to.equal(expected); @@ -126,7 +110,7 @@ describe('DateTimePicker', function () { const {day, month, year} = extractValues(dateTimePicker); const numDays = daysInMonth({month, year}); dateTimePicker.decrementer(dateTimePicker.day).click(); - expect(dateTimePicker.decrementer(dateTimePicker.day).isFocused()).to.be.true(); + expect(dateTimePicker.day.isFocused()).to.be.true(); const {day: value} = extractValues(dateTimePicker); const expected = day !== 1 ? day - 1 : numDays; expect(value).to.equal(expected); @@ -135,7 +119,7 @@ describe('DateTimePicker', function () { it('should increase the year when incrementing the picker', function () { const {year} = extractValues(dateTimePicker); dateTimePicker.incrementer(dateTimePicker.year).click(); - expect(dateTimePicker.incrementer(dateTimePicker.year).isFocused()).to.be.true(); + expect(dateTimePicker.year.isFocused()).to.be.true(); const {year: value} = extractValues(dateTimePicker); const expected = year + 1; expect(value).to.equal(expected); @@ -144,7 +128,7 @@ describe('DateTimePicker', function () { it('should decrease the year when decrementing the picker', function () { const {year} = extractValues(dateTimePicker); dateTimePicker.decrementer(dateTimePicker.year).click(); - expect(dateTimePicker.decrementer(dateTimePicker.year).isFocused()).to.be.true(); + expect(dateTimePicker.year.isFocused()).to.be.true(); const {year: value} = extractValues(dateTimePicker); const expected = year - 1; expect(value).to.equal(expected); @@ -159,7 +143,7 @@ describe('DateTimePicker', function () { describe('5-way', function () { it('should not update on select', function () { dateTimePicker.focus(); - Page.spotlightSelect(); + Page.spotlightDown(); const {day, hour, minute, meridiem, month, year} = extractValues(dateTimePicker); @@ -173,30 +157,33 @@ describe('DateTimePicker', function () { }); }); - describe('disabled', function () { const dateTimePicker = Page.components.dateTimePickerDisabled; it('should not increase the day when incrementing disabled picker', function () { - dateTimePicker.incrementer(dateTimePicker.day).click(); - expect(dateTimePicker.incrementer(dateTimePicker.day).isFocused()).to.be.true(); + dateTimePicker.day.click(); + expect(dateTimePicker.day.isFocused()).to.be.true(); + Page.spotlightDown(); + browser.pause(500); const {day: value} = extractValues(dateTimePicker); expect(value).to.equal(1); }); it('should not decrease the day when decrementing disabled picker', function () { - dateTimePicker.decrementer(dateTimePicker.day).click(); - expect(dateTimePicker.decrementer(dateTimePicker.day).isFocused()).to.be.true(); + dateTimePicker.day.click(); + expect(dateTimePicker.day.isFocused()).to.be.true(); + Page.spotlightUp(); browser.pause(500); const {day: value} = extractValues(dateTimePicker); expect(value).to.equal(1); }); - it('should not update hour on click', function () { + it('should not update hour when decrementing disabled picker', function () { const {hour} = extractValues(dateTimePicker); - dateTimePicker.decrementer(dateTimePicker.hour).click(); - expect(dateTimePicker.decrementer(dateTimePicker.hour).isFocused()).to.be.true(); + dateTimePicker.hour.click(); + expect(dateTimePicker.hour.isFocused()).to.be.true(); + Page.spotlightUp(); browser.pause(500); const {hour: value} = extractValues(dateTimePicker); expect(value).to.equal(hour); @@ -218,29 +205,34 @@ describe('DateTimePicker', function () { }); - it('should not update \'defaultValue\' on on click', function () { + it('should not update \'defaultValue\' on decrement', function () { const {day, hour, meridiem, minute, month, year} = extractValues(dateTimePicker); - dateTimePicker.decrementer(dateTimePicker.month).click(); - expect(dateTimePicker.decrementer(dateTimePicker.month).isFocused()).to.be.true(); + dateTimePicker.month.click(); + expect(dateTimePicker.month.isFocused()).to.be.true(); + Page.spotlightUp(); - dateTimePicker.decrementer(dateTimePicker.day).click(); - expect(dateTimePicker.decrementer(dateTimePicker.day).isFocused()).to.be.true(); + dateTimePicker.day.click(); + expect(dateTimePicker.day.isFocused()).to.be.true(); + Page.spotlightUp(); - dateTimePicker.decrementer(dateTimePicker.year).click(); - expect(dateTimePicker.decrementer(dateTimePicker.year).isFocused()).to.be.true(); + dateTimePicker.year.click(); + expect(dateTimePicker.year.isFocused()).to.be.true(); + Page.spotlightUp(); - dateTimePicker.decrementer(dateTimePicker.minute).click(); - expect(dateTimePicker.decrementer(dateTimePicker.minute).isFocused()).to.be.true(); + dateTimePicker.minute.click(); + expect(dateTimePicker.minute.isFocused()).to.be.true(); + Page.spotlightUp(); - dateTimePicker.decrementer(dateTimePicker.hour).click(); - expect(dateTimePicker.decrementer(dateTimePicker.hour).isFocused()).to.be.true(); + dateTimePicker.hour.click(); + expect(dateTimePicker.hour.isFocused()).to.be.true(); + Page.spotlightUp(); + dateTimePicker.meridiem.click(); + expect(dateTimePicker.meridiem.isFocused()).to.be.true(); if (meridiem === 'AM') { - dateTimePicker.incrementer(dateTimePicker.meridiem).click(); - expect(dateTimePicker.incrementer(dateTimePicker.meridiem).isFocused()).to.be.true(); + Page.spotlightDown(); } else { - dateTimePicker.decrementer(dateTimePicker.meridiem).click(); - expect(dateTimePicker.decrementer(dateTimePicker.meridiem).isFocused()).to.be.true(); + Page.spotlightUp(); } browser.pause(500); @@ -263,41 +255,23 @@ describe('DateTimePicker', function () { }); it('should focus hour picker when selected', function () { - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, interval: 100}); + expect(dateTimePicker.hour.isFocused()).to.be.true(); }); it('should have minute-hour-meridiem-day-month-year order', function () { - const {meridiem} = extractValues(dateTimePicker); - if (meridiem === 'ص') { - Page.spotlightDown(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'initial', interval: 100}); - Page.spotlightRight(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => dateTimePicker.incrementer(dateTimePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem', interval: 100}); - Page.spotlightLeft(); - expect(dateTimePicker.incrementer(dateTimePicker.day).isFocused()).to.be.true(); - Page.spotlightLeft(); - expect(dateTimePicker.incrementer(dateTimePicker.month).isFocused()).to.be.true(); - Page.spotlightLeft(); - expect(dateTimePicker.incrementer(dateTimePicker.year).isFocused()).to.be.true(); - } else { - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'initial', interval: 100}); - Page.spotlightRight(); - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => dateTimePicker.decrementer(dateTimePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem', interval: 100}); - Page.spotlightLeft(); - expect(dateTimePicker.decrementer(dateTimePicker.day).isFocused()).to.be.true(); - Page.spotlightLeft(); - expect(dateTimePicker.decrementer(dateTimePicker.month).isFocused()).to.be.true(); - Page.spotlightLeft(); - expect(dateTimePicker.decrementer(dateTimePicker.year).isFocused()).to.be.true(); - } + browser.waitUntil(() => dateTimePicker.hour.isFocused(), {timeout: 1500, timeoutMsg: 'initial', interval: 100}); + Page.spotlightRight(); + browser.waitUntil(() => dateTimePicker.minute.isFocused(), {timeout: 1500, timeoutMsg: 'minute', interval: 100}); + Page.spotlightLeft(); + browser.waitUntil(() => dateTimePicker.hour.isFocused(), {timeout: 1500, timeoutMsg: 'hour', interval: 100}); + Page.spotlightLeft(); + browser.waitUntil(() => dateTimePicker.meridiem.isFocused(), {timeout: 1500, timeoutMsg: 'meridiem', interval: 100}); + Page.spotlightLeft(); + expect(dateTimePicker.day.isFocused()).to.be.true(); + Page.spotlightLeft(); + expect(dateTimePicker.month.isFocused()).to.be.true(); + Page.spotlightLeft(); + expect(dateTimePicker.year.isFocused()).to.be.true(); }); }); @@ -313,28 +287,33 @@ describe('DateTimePicker', function () { }); it('should display hours in 24-hour format', function () { - dateTimePicker.incrementer(dateTimePicker.hour).click(); + dateTimePicker.hour.click(); + Page.spotlightDown(); expect(extractValues(dateTimePicker).hour).to.equal(13); }); it('should increment hours from 23 to 0', function () { + dateTimePicker.hour.click(); // go to 23 first for (let i = 11; i; i -= 1) { - dateTimePicker.incrementer(dateTimePicker.hour).click(); + Page.spotlightDown(); } + browser.pause(1000); expect(extractValues(dateTimePicker).hour).to.equal(23); // now increment - dateTimePicker.incrementer(dateTimePicker.hour).click(); + Page.spotlightDown(); expect(extractValues(dateTimePicker).hour).to.equal(0); + }); it('should decrement hours from 0 to 23', function () { + dateTimePicker.hour.click(); // go to 0 first for (let i = 12; i; i -= 1) { - dateTimePicker.decrementer(dateTimePicker.hour).click(); + Page.spotlightUp(); } expect(extractValues(dateTimePicker).hour).to.equal(0); - dateTimePicker.decrementer(dateTimePicker.hour).click(); + Page.spotlightUp(); expect(extractValues(dateTimePicker).hour).to.equal(23); }); }); diff --git a/tests/ui/specs/DateTimePicker/DateTimePicker-utils.js b/tests/ui/specs/DateTimePicker/DateTimePicker-utils.js index 895033402..cd876a643 100644 --- a/tests/ui/specs/DateTimePicker/DateTimePicker-utils.js +++ b/tests/ui/specs/DateTimePicker/DateTimePicker-utils.js @@ -4,12 +4,12 @@ const daysInMonth = ({month, year}) => new Date(year, month, 0).getDate(); const extractValues = (picker) => { - const day = parseInt(picker.active(picker.day).getText()); - const month = parseInt(picker.active(picker.month).getText()); - const year = parseInt(picker.active(picker.year).getText()); - const hour = parseInt(picker.active(picker.hour).getText()); - const minute = parseInt(picker.active(picker.minute).getText()); - const meridiem = picker.meridiem.isExisting() ? picker.active(picker.meridiem).getText() : null; + const day = parseInt(picker.selectedItem(picker.day).getText()); + const month = parseInt(picker.selectedItem(picker.month).getText()); + const year = parseInt(picker.selectedItem(picker.year).getText()); + const hour = parseInt(picker.selectedItem(picker.hour).getText()); + const minute = parseInt(picker.selectedItem(picker.minute).getText()); + const meridiem = picker.meridiem.isExisting() ? picker.selectedItem(picker.meridiem).getText() : null; return {day, month, year, hour, minute, meridiem}; }; diff --git a/tests/ui/specs/DateTimePicker/DateTimePickerPage.js b/tests/ui/specs/DateTimePicker/DateTimePickerPage.js index 2dadce9d9..cb35765ef 100644 --- a/tests/ui/specs/DateTimePicker/DateTimePickerPage.js +++ b/tests/ui/specs/DateTimePicker/DateTimePickerPage.js @@ -37,15 +37,15 @@ class DateTimePickerInterface { } decrementer (picker) { - return element('.internal_Picker_Picker_itemDecrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemDecrement', picker); } incrementer (picker) { - return element('.internal_Picker_Picker_itemIncrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemIncrement', picker); } - active (picker) { - return element('.internal_Picker_Picker_active', picker); + selectedItem (picker) { + return element('.internal_DrumPicker_DrumPicker_selectedItem', picker); } } diff --git a/tests/ui/specs/Picker/Picker-specs.js b/tests/ui/specs/Picker/Picker-specs.js index 386ca22e4..894e4f871 100644 --- a/tests/ui/specs/Picker/Picker-specs.js +++ b/tests/ui/specs/Picker/Picker-specs.js @@ -13,19 +13,16 @@ describe('Picker', function () { describe('5-way', function () { it('should change the value forward when incrementing the picker', function () { - expect(picker.incrementer(picker.self).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(picker.self.isFocused()).to.be.true(); + Page.spotlightDown(); browser.pause(500); const newValue = extractValue(picker); expect(newValue).to.equal('Banana'); }); it('should change the value backward when decrementing the picker', function () { - expect(picker.incrementer(picker.self).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(picker.self.isFocused()).to.be.true(); Page.spotlightUp(); - expect(picker.decrementer(picker.self).isFocused()).to.be.true(); - Page.spotlightSelect(); browser.pause(500); const newValue = extractValue(picker); expect(newValue).to.equal('Apple'); @@ -35,15 +32,18 @@ describe('Picker', function () { describe('pointer', function () { it('should increase the value when incrementing the picker', function () { picker.incrementer(picker.self).click(); + expect(picker.self.isFocused()).to.be.true(); browser.pause(500); const newValue = extractValue(picker); expect(newValue).to.equal('Banana'); }); it('should decrease the value when decrementing the picker', function () { + // first increment to second option the decrement back to first option picker.incrementer(picker.self).click(); - expect(picker.incrementer(picker.self).isFocused()).to.be.true(); picker.decrementer(picker.self).click(); + expect(picker.self.isFocused()).to.be.true(); + picker.self.click(); browser.pause(500); const newValue = extractValue(picker); expect(newValue).to.equal('Apple'); @@ -65,9 +65,20 @@ describe('Picker', function () { const picker = Page.components.pickerDisabled; describe('5-way', function () { - it('should not update on select', function () { + it('should not update when incrementing the picker', function () { const oldValue = extractValue(picker); - Page.spotlightSelect(); + Page.spotlightLeft(); + Page.spotlightDown(); + picker.focus(); + browser.pause(500); + const newValue = extractValue(picker); + expect(newValue).to.equal(oldValue); + }); + + it('should not update when decrementing the picker', function () { + const oldValue = extractValue(picker); + Page.spotlightLeft(); + Page.spotlightUp(); picker.focus(); browser.pause(500); const newValue = extractValue(picker); diff --git a/tests/ui/specs/Picker/Picker-utils.js b/tests/ui/specs/Picker/Picker-utils.js index b322c6ac9..72a2beebe 100644 --- a/tests/ui/specs/Picker/Picker-utils.js +++ b/tests/ui/specs/Picker/Picker-utils.js @@ -1,7 +1,7 @@ // Utility methods for testing const extractValue = (picker) => { - return picker.active(picker.self).getText(); + return picker.selectedItem(picker.self).getText(); }; module.exports = { diff --git a/tests/ui/specs/Picker/PickerPage.js b/tests/ui/specs/Picker/PickerPage.js index 3806244c8..7556b6b3e 100644 --- a/tests/ui/specs/Picker/PickerPage.js +++ b/tests/ui/specs/Picker/PickerPage.js @@ -3,32 +3,33 @@ const {Page} = require('@enact/ui-test-utils/utils'); const {element} = require('@enact/ui-test-utils/utils'); class PickerInterface { - constructor (id) { - this.id = id; + constructor (className) { + this.className = className; + this.selector = `.${this.className}`; } focus () { - return browser.execute((el) => el.focus(), $(`#${this.id}>div`)); + return browser.execute((el) => el.focus(), $(`.${this.className}>div`)); } get self () { - return $(`#${this.id}`, browser); + return $(this.selector); } get picker () { - return element('.internal_Picker_Picker_picker', this.self); + return element('.internal_DrumPicker_DrumPicker_drumPicker', this.self); } decrementer (picker) { - return element('.internal_Picker_Picker_itemDecrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemDecrement', picker); } incrementer (picker) { - return element('.internal_Picker_Picker_itemIncrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemIncrement', picker); } - active (picker) { - return element('.internal_Picker_Picker_active', picker); + selectedItem (picker) { + return element('.internal_DrumPicker_DrumPicker_selectedItem', picker); } } diff --git a/tests/ui/specs/RangePicker/RangePicker-specs.js b/tests/ui/specs/RangePicker/RangePicker-specs.js index 106995b78..21eef4e6b 100644 --- a/tests/ui/specs/RangePicker/RangePicker-specs.js +++ b/tests/ui/specs/RangePicker/RangePicker-specs.js @@ -13,19 +13,16 @@ describe('RangePicker', function () { describe('5-way', function () { it('should change the value forward when incrementing the rangePicker', function () { - expect(rangePicker.incrementer(rangePicker.self).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(rangePicker.self.isFocused()).to.be.true(); + Page.spotlightDown(); browser.pause(500); const newValue = extractValue(rangePicker); - expect(newValue).to.equal(5); + expect(newValue).to.equal(10); }); it('should change the value backward when decrementing the rangePicker', function () { - expect(rangePicker.incrementer(rangePicker.self).isFocused()).to.be.true(); - Page.spotlightSelect(); + expect(rangePicker.self.isFocused()).to.be.true(); Page.spotlightUp(); - expect(rangePicker.decrementer(rangePicker.self).isFocused()).to.be.true(); - Page.spotlightSelect(); browser.pause(500); const newValue = extractValue(rangePicker); expect(newValue).to.equal(0); @@ -35,15 +32,15 @@ describe('RangePicker', function () { describe('pointer', function () { it('should increase the value when incrementing the rangePicker', function () { rangePicker.incrementer(rangePicker.self).click(); + expect(rangePicker.self.isFocused()).to.be.true(); browser.pause(500); const newValue = extractValue(rangePicker); - expect(newValue).to.equal(5); + expect(newValue).to.equal(10); }); it('should decrease the value when decrementing the rangePicker', function () { - rangePicker.incrementer(rangePicker.self).click(); - expect(rangePicker.incrementer(rangePicker.self).isFocused()).to.be.true(); rangePicker.decrementer(rangePicker.self).click(); + expect(rangePicker.self.isFocused()).to.be.true(); browser.pause(500); const newValue = extractValue(rangePicker); expect(newValue).to.equal(0); @@ -55,9 +52,20 @@ describe('RangePicker', function () { const rangePicker = Page.components.rangePickerDisabled; describe('5-way', function () { - it('should not update on select', function () { + it('should not change the value forward when incrementing the rangePicker', function () { const oldValue = extractValue(rangePicker); - Page.spotlightSelect(); + Page.spotlightLeft(); + Page.spotlightDown(); + rangePicker.focus(); + browser.pause(500); + const newValue = extractValue(rangePicker); + expect(newValue).to.equal(oldValue); + }); + + it('should not change the value backward when decrementing the rangePicker', function () { + const oldValue = extractValue(rangePicker); + Page.spotlightLeft(); + Page.spotlightUp(); rangePicker.focus(); browser.pause(500); const newValue = extractValue(rangePicker); @@ -93,7 +101,10 @@ describe('RangePicker', function () { }); it('should decrement to negative number', function () { - rangePicker.decrementer(rangePicker.self).click(); + Page.spotlightRight(); + Page.spotlightRight(); + expect(rangePicker.self.isFocused()).to.be.true(); + Page.spotlightUp(); browser.pause(500); const newValue = extractValue(rangePicker); expect(newValue).to.equal(-1); diff --git a/tests/ui/specs/RangePicker/RangePicker-utils.js b/tests/ui/specs/RangePicker/RangePicker-utils.js index 8d24937fd..08f3426f2 100644 --- a/tests/ui/specs/RangePicker/RangePicker-utils.js +++ b/tests/ui/specs/RangePicker/RangePicker-utils.js @@ -1,7 +1,7 @@ // Utility methods for testing const extractValue = (rangePicker) => { - return parseInt(rangePicker.active(rangePicker.self).getText()); + return parseInt(rangePicker.selectedItem(rangePicker.self).getText()); }; module.exports = { diff --git a/tests/ui/specs/RangePicker/RangePickerPage.js b/tests/ui/specs/RangePicker/RangePickerPage.js index 0e4630eb6..74cd375ce 100644 --- a/tests/ui/specs/RangePicker/RangePickerPage.js +++ b/tests/ui/specs/RangePicker/RangePickerPage.js @@ -3,32 +3,33 @@ const {Page} = require('@enact/ui-test-utils/utils'); const {element} = require('@enact/ui-test-utils/utils'); class RangePickerInterface { - constructor (id) { - this.id = id; + constructor (className) { + this.className = className; + this.selector = `.${this.className}`; } focus () { - return browser.execute((el) => el.focus(), $(`#${this.id}>div`)); + return browser.execute((el) => el.focus(), $(`.${this.className}>div`)); } get self () { - return $(`#${this.id}`, browser); + return $(this.selector); } get rangePicker () { - return element('.internal_Picker_Picker_picker', this.self); + return element('.internal_DrumPicker_DrumPicker_drumPicker', this.self); } decrementer (rangePicker) { - return element('.internal_Picker_Picker_itemDecrement', rangePicker); + return element('.internal_DrumPicker_DrumPicker_itemDecrement', rangePicker); } incrementer (rangePicker) { - return element('.internal_Picker_Picker_itemIncrement', rangePicker); + return element('.internal_DrumPicker_DrumPicker_itemIncrement', rangePicker); } - active (rangePicker) { - return element('.internal_Picker_Picker_active', rangePicker); + selectedItem (rangePicker) { + return element('.internal_DrumPicker_DrumPicker_selectedItem', rangePicker); } } diff --git a/tests/ui/specs/TimePicker/TimePicker-specs.js b/tests/ui/specs/TimePicker/TimePicker-specs.js index 91c1dec87..16589b860 100644 --- a/tests/ui/specs/TimePicker/TimePicker-specs.js +++ b/tests/ui/specs/TimePicker/TimePicker-specs.js @@ -12,28 +12,17 @@ describe('TimePicker', function () { const timePicker = Page.components.timePickerDefault; it('should have hour-minute-meridiem order', function () { - const {meridiem} = extractValues(timePicker); - if (meridiem === 'AM') { - Page.spotlightDown(); - browser.waitUntil(() => timePicker.incrementer(timePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour focused'}); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.incrementer(timePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute focused'}); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.incrementer(timePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem focused'}); - } else { - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour focused'}); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.decrementer(timePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute focused'}); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.decrementer(timePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem focused'}); - } + browser.waitUntil(() => timePicker.hour.isFocused(), {timeout: 1500, timeoutMsg: 'hour focused'}); + Page.spotlightRight(); + browser.waitUntil(() => timePicker.minute.isFocused(), {timeout: 1500, timeoutMsg: 'minute focused'}); + Page.spotlightRight(); + browser.waitUntil(() => timePicker.meridiem.isFocused(), {timeout: 1500, timeoutMsg: 'meridiem focused'}); }); describe('5-way', function () { it('should decrease the hour when decrementing the picker', function () { const {hour} = extractValues(timePicker); - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, interval: 100}); - Page.spotlightSelect(); + Page.spotlightUp(); const {hour: value} = extractValues(timePicker); const expected = hour > 1 ? hour - 1 : 12; expect(value).to.equal(expected); @@ -42,8 +31,7 @@ describe('TimePicker', function () { it('should increase the hour when incrementing the picker', function () { const {hour} = extractValues(timePicker); Page.spotlightDown(); - browser.waitUntil(() => timePicker.incrementer(timePicker.hour).isFocused(), {timeout: 1500, interval: 100}); - Page.spotlightSelect(); + browser.pause(500); const {hour: value} = extractValues(timePicker); const expected = hour < 12 ? hour + 1 : 1; expect(value).to.equal(expected); @@ -52,8 +40,9 @@ describe('TimePicker', function () { it('should decrease the minute when decrementing the picker', function () { const {minute} = extractValues(timePicker); Page.spotlightRight(); - browser.waitUntil(() => timePicker.decrementer(timePicker.minute).isFocused(), {timeout: 1500, interval: 100}); - Page.spotlightSelect(); + browser.waitUntil(() => timePicker.minute.isFocused(), {timeout: 1500, interval: 100}); + Page.spotlightUp(); + browser.pause(500); const {minute: value} = extractValues(timePicker); const expected = minute !== 0 ? minute - 1 : 59; expect(value).to.equal(expected); @@ -62,10 +51,9 @@ describe('TimePicker', function () { it('should increase the minute when incrementing the picker', function () { const {minute} = extractValues(timePicker); Page.spotlightRight(); - browser.waitUntil(() => timePicker.decrementer(timePicker.minute).isFocused(), {timeout: 1500, interval: 100}); + browser.waitUntil(() => timePicker.minute.isFocused(), {timeout: 1500, interval: 100}); Page.spotlightDown(); - browser.waitUntil(() => timePicker.incrementer(timePicker.minute).isFocused(), {timeout: 1500, interval: 100}); - Page.spotlightSelect(); + browser.pause(500); const {minute: value} = extractValues(timePicker); const expected = minute !== 59 ? minute + 1 : 0; expect(value).to.equal(expected); @@ -73,35 +61,33 @@ describe('TimePicker', function () { it('should not change displayed hour when changing the meridiem picker', function () { const {hour, meridiem} = extractValues(timePicker); + Page.spotlightRight(); + Page.spotlightRight(); + browser.waitUntil(() => timePicker.meridiem.isFocused(), {timeout: 1500, interval: 100}); if (meridiem === 'AM') { - // change to PM Page.spotlightDown(); - Page.spotlightRight(); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.incrementer(timePicker.meridiem).isFocused(), {timeout: 1500, interval: 100}); } else { - // change to AM - Page.spotlightRight(); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.decrementer(timePicker.meridiem).isFocused(), {timeout: 1500, interval: 100}); + Page.spotlightUp(); } - Page.spotlightSelect(); - + browser.pause(500); const {hour: value} = extractValues(timePicker); expect(value).to.equal(hour); }); it('should change the meridiem on hour boundaries', function () { const {meridiem} = extractValues(timePicker); + Page.spotlightDown(); + browser.waitUntil(() => timePicker.hour.isFocused(), {timeout: 1500, interval: 100}); if (meridiem === 'AM') { - Page.spotlightDown(); - browser.waitUntil(() => timePicker.incrementer(timePicker.hour).isFocused(), {timeout: 1500, interval: 100}); + for (let i = 12; i; i -= 1) { + // 12 hours ought to change the value text if meridiem changes + Page.spotlightDown(); + } } else { - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, interval: 100}); - } - // 12 hours ought to change the value text if meridiem changes - for (let i = 12; i; i -= 1) { - Page.spotlightSelect(); + for (let i = 12; i; i -= 1) { + // 12 hours ought to change the value text if meridiem changes + Page.spotlightUp(); + } } const {meridiem: value} = extractValues(timePicker); @@ -112,7 +98,7 @@ describe('TimePicker', function () { describe('pointer', function () { it('should select hour when opened', function () { timePicker.decrementer(timePicker.hour).click(); - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, interval: 100}); + browser.waitUntil(() => timePicker.hour.isFocused(), {timeout: 1500, interval: 100}); }); @@ -135,7 +121,7 @@ describe('TimePicker', function () { it('should increase the minute when incrementing the picker', function () { const {minute} = extractValues(timePicker); timePicker.incrementer(timePicker.minute).click(); - browser.waitUntil(() => timePicker.incrementer(timePicker.minute).isFocused(), {timeout: 1500, interval: 100}); + browser.waitUntil(() => timePicker.minute.isFocused(), {timeout: 1500, interval: 100}); const {minute: value} = extractValues(timePicker); const expected = minute !== 59 ? minute + 1 : 0; expect(value).to.equal(expected); @@ -144,7 +130,7 @@ describe('TimePicker', function () { it('should decrease the minute when decrementing the picker', function () { const {minute} = extractValues(timePicker); timePicker.decrementer(timePicker.minute).click(); - browser.waitUntil(() => timePicker.decrementer(timePicker.minute).isFocused(), {timeout: 1500, interval: 100}); + browser.waitUntil(() => timePicker.minute.isFocused(), {timeout: 1500, interval: 100}); const {minute: value} = extractValues(timePicker); const expected = minute !== 0 ? minute - 1 : 59; expect(value).to.equal(expected); @@ -175,9 +161,24 @@ describe('TimePicker', function () { const timePicker = Page.components.timePickerWithDefaultValue; describe('5-way', function () { - it('should not update on select', function () { + it('should not update when incrementing the picker', function () { timePicker.focus(); - Page.spotlightSelect(); + Page.spotlightDown(); + Page.spotlightRight(); + Page.spotlightDown(); + + const {hour, minute, meridiem} = extractValues(timePicker); + + expect(hour).to.equal(12); + expect(minute).to.equal(0); + expect(meridiem).to.equal('AM'); + }); + + it('should not update when decrementing the picker', function () { + timePicker.focus(); + Page.spotlightDown(); + Page.spotlightRight(); + Page.spotlightUp(); const {hour, minute, meridiem} = extractValues(timePicker); @@ -202,7 +203,7 @@ describe('TimePicker', function () { it('should not update hour on click', function () { const {hour} = extractValues(timePicker); timePicker.decrementer(timePicker.hour).click(); - expect(timePicker.decrementer(timePicker.hour).isFocused()).to.be.true(); + expect(timePicker.hour.isFocused()).to.be.true(); browser.pause(500); const {hour: value} = extractValues(timePicker); expect(value).to.equal(hour); @@ -212,24 +213,34 @@ describe('TimePicker', function () { describe('disabled with \'defaultValue\'', function () { const timePicker = Page.components.timePickerDisabledWithDefaultValue; - it('should not update \'defaultValue\' on click', function () { + + it('should not update \'defaultValue\' on decrementing disabled picker', function () { const {hour, minute, meridiem} = extractValues(timePicker); + timePicker.focus(); + Page.spotlightUp(); + Page.spotlightRight(); + Page.spotlightUp(); + Page.spotlightRight(); + Page.spotlightUp(); - timePicker.decrementer(timePicker.minute).click(); - expect(timePicker.decrementer(timePicker.minute).isFocused()).to.be.true(); + browser.pause(500); - timePicker.decrementer(timePicker.hour).click(); - expect(timePicker.decrementer(timePicker.hour).isFocused()).to.be.true(); + expect(hour).to.equal(12); + expect(minute).to.equal(0); + expect(meridiem).to.equal('AM'); + }); - if (meridiem === 'AM') { - timePicker.incrementer(timePicker.meridiem).click(); - expect(timePicker.incrementer(timePicker.meridiem).isFocused()).to.be.true(); - } else { - timePicker.decrementer(timePicker.meridiem).click(); - expect(timePicker.decrementer(timePicker.meridiem).isFocused()).to.be.true(); - } + it('should not update \'defaultValue\' on incrementing disabled picker', function () { + const {hour, minute, meridiem} = extractValues(timePicker); + timePicker.focus(); + Page.spotlightDown(); + Page.spotlightRight(); + Page.spotlightDown(); + Page.spotlightRight(); + Page.spotlightDown(); browser.pause(500); + expect(hour).to.equal(12); expect(minute).to.equal(0); expect(meridiem).to.equal('AM'); @@ -245,32 +256,16 @@ describe('TimePicker', function () { Page.open('?locale=ar-SA'); }); - it('should focus middle picker (hour) when selected', function () { - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, interval: 100}); - }); - it('should have minute-hour-meridiem order', function () { - const {meridiem} = extractValues(timePicker); - if (meridiem === 'ص') { - Page.spotlightDown(); - browser.waitUntil(() => timePicker.incrementer(timePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'initial', interval: 100}); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.incrementer(timePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => timePicker.incrementer(timePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => timePicker.incrementer(timePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem', interval: 100}); - } else { - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'initial', interval: 100}); - Page.spotlightRight(); - browser.waitUntil(() => timePicker.decrementer(timePicker.minute).isFocused(), {timeout: 1500, timeoutMsg: 'minute', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => timePicker.decrementer(timePicker.hour).isFocused(), {timeout: 1500, timeoutMsg: 'hour', interval: 100}); - Page.spotlightLeft(); - browser.waitUntil(() => timePicker.decrementer(timePicker.meridiem).isFocused(), {timeout: 1500, timeoutMsg: 'meridiem', interval: 100}); - } - - + timePicker.focus(); + Page.spotlightRight(); + Page.spotlightRight(); + + expect(timePicker.minute.isFocused()).to.be.true(); + Page.spotlightLeft(); + expect(timePicker.hour.isFocused()).to.be.true(); + Page.spotlightLeft(); + expect(timePicker.meridiem.isFocused()).to.be.true(); }); }); @@ -290,16 +285,23 @@ describe('TimePicker', function () { }); it('should increment hours from 23 to 0', function () { + Page.spotlightRight(); + Page.spotlightRight(); // go to 23 first - timePicker.decrementer(timePicker.hour).click(); + Page.spotlightUp(); + browser.pause(1000); expect(extractValues(timePicker).hour).to.equal(23); // now increment - timePicker.incrementer(timePicker.hour).click(); + Page.spotlightDown(); + browser.pause(1000); expect(extractValues(timePicker).hour).to.equal(0); }); it('should decrement hours from 0 to 23', function () { - timePicker.decrementer(timePicker.hour).click(); + Page.spotlightRight(); + Page.spotlightRight(); + Page.spotlightUp(); + browser.pause(1000); expect(extractValues(timePicker).hour).to.equal(23); }); }); diff --git a/tests/ui/specs/TimePicker/TimePicker-utils.js b/tests/ui/specs/TimePicker/TimePicker-utils.js index 9c83354a6..80d64b603 100644 --- a/tests/ui/specs/TimePicker/TimePicker-utils.js +++ b/tests/ui/specs/TimePicker/TimePicker-utils.js @@ -1,8 +1,8 @@ // Utility methods for testing const extractValues = (picker) => { - const hour = parseInt(picker.active(picker.hour).getText()); - const minute = parseInt(picker.active(picker.minute).getText()); - const meridiem = picker.meridiem.isExisting() ? picker.active(picker.meridiem).getText() : null; + const hour = parseInt(picker.selectedItem(picker.hour).getText()); + const minute = parseInt(picker.selectedItem(picker.minute).getText()); + const meridiem = picker.meridiem.isExisting() ? picker.selectedItem(picker.meridiem).getText() : null; return {hour, minute, meridiem}; }; diff --git a/tests/ui/specs/TimePicker/TimePickerPage.js b/tests/ui/specs/TimePicker/TimePickerPage.js index f368e40cb..1c25024a7 100644 --- a/tests/ui/specs/TimePicker/TimePickerPage.js +++ b/tests/ui/specs/TimePicker/TimePickerPage.js @@ -25,13 +25,15 @@ class PickerInterface { } decrementer (picker) { - return element('.internal_Picker_Picker_itemDecrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemDecrement', picker); } + incrementer (picker) { - return element('.internal_Picker_Picker_itemIncrement', picker); + return element('.internal_DrumPicker_DrumPicker_itemIncrement', picker); } - active (picker) { - return element('.internal_Picker_Picker_active', picker); + + selectedItem (picker) { + return element('.internal_DrumPicker_DrumPicker_selectedItem', picker); } }