mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-10 00:27:41 +08:00
test(select/segment): adds unit test for select and segment
This commit is contained in:
@ -58,13 +58,13 @@ export class PageOne {
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
handler: (data: any) => {
|
||||
handler: (data) => {
|
||||
console.log('Cancel clicked');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: 'Save',
|
||||
handler: (data: any) => {
|
||||
handler: (data) => {
|
||||
console.log('Saved clicked');
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,5 +28,5 @@ export interface AlertButton {
|
||||
text?: string;
|
||||
role?: string;
|
||||
cssClass?: string;
|
||||
handler?: Function;
|
||||
handler?: (value: any) => boolean|void;
|
||||
};
|
||||
|
||||
@ -11,9 +11,7 @@ import { PageOneModule } from '../pages/page-one/page-one.module';
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(AppComponent, {
|
||||
mode: 'ios'
|
||||
}),
|
||||
IonicModule.forRoot(AppComponent, {}),
|
||||
PageOneModule
|
||||
],
|
||||
bootstrap: [IonicApp]
|
||||
|
||||
@ -94,8 +94,7 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, After
|
||||
renderer: Renderer,
|
||||
private _cd: ChangeDetectorRef
|
||||
) {
|
||||
super(config, elementRef, renderer, 'checkbox', form, item, null);
|
||||
this._value = false;
|
||||
super(config, elementRef, renderer, 'checkbox', false, form, item, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,7 +109,6 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, After
|
||||
*/
|
||||
@HostListener('click', ['$event'])
|
||||
_click(ev: UIEvent) {
|
||||
console.debug('checkbox, checked');
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.value = !this.value;
|
||||
@ -122,6 +120,7 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, After
|
||||
_inputNormalize(val: any): boolean {
|
||||
return isTrueProperty(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@ -129,11 +128,4 @@ export class Checkbox extends BaseInput<boolean> implements IonicTapInput, After
|
||||
this._item && this._item.setElementClass('item-checkbox-checked', val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
_inputUpdated() {
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -273,12 +273,11 @@ export const DATETIME_VALUE_ACCESSOR: any = {
|
||||
providers: [DATETIME_VALUE_ACCESSOR],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class DateTime extends BaseInput<any> implements AfterContentInit, ControlValueAccessor, OnDestroy {
|
||||
export class DateTime extends BaseInput<DateTimeData> implements AfterContentInit, ControlValueAccessor, OnDestroy {
|
||||
|
||||
_text: string = '';
|
||||
_min: DateTimeData;
|
||||
_max: DateTimeData;
|
||||
_timeValue: DateTimeData = {};
|
||||
_locale: LocaleData = {};
|
||||
_picker: Picker;
|
||||
|
||||
@ -426,7 +425,7 @@ export class DateTime extends BaseInput<any> implements AfterContentInit, Contro
|
||||
@Optional() item: Item,
|
||||
@Optional() private _pickerCtrl: PickerController
|
||||
) {
|
||||
super(config, elementRef, renderer, 'datetime', form, item, null);
|
||||
super(config, elementRef, renderer, 'datetime', {}, form, item, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -448,10 +447,17 @@ export class DateTime extends BaseInput<any> implements AfterContentInit, Contro
|
||||
* @hidden
|
||||
*/
|
||||
_inputUpdated() {
|
||||
updateDate(this._timeValue, this.value);
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
_inputNormalize(val: any): DateTimeData {
|
||||
updateDate(this._value, val);
|
||||
return this._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
@ -743,7 +749,7 @@ export class DateTime extends BaseInput<any> implements AfterContentInit, Contro
|
||||
* @hidden
|
||||
*/
|
||||
getValue(): DateTimeData {
|
||||
return this._timeValue;
|
||||
return this._value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -604,10 +604,6 @@ describe('DateTime', () => {
|
||||
datetime.setValue(null);
|
||||
expect(datetime.getValue()).toEqual({});
|
||||
|
||||
datetime.setValue('1994-12-15T13:47:20.789Z');
|
||||
datetime.setValue(undefined);
|
||||
expect(datetime.getValue()).toEqual({});
|
||||
|
||||
datetime.setValue('1994-12-15T13:47:20.789Z');
|
||||
datetime.setValue('');
|
||||
expect(datetime.getValue()).toEqual({});
|
||||
|
||||
@ -132,7 +132,7 @@ export class TextInput extends BaseInput<string> implements IonicFormInput {
|
||||
@Optional() public ngControl: NgControl,
|
||||
private _dom: DomController
|
||||
) {
|
||||
super(config, elementRef, renderer, 'input', form, item, ngControl);
|
||||
super(config, elementRef, renderer, 'input', '', form, item, ngControl);
|
||||
|
||||
this._nav = <NavControllerBase>nav;
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import { BaseInput } from '../../util/base-input';
|
||||
import { Item } from '../item/item';
|
||||
import { Platform } from '../../platform/platform';
|
||||
import { PointerCoordinates, pointerCoord } from '../../util/dom';
|
||||
import { TimeoutDebouncer } from '../../util/debouncer';
|
||||
import { UIEventManager } from '../../gestures/ui-event-manager';
|
||||
|
||||
|
||||
@ -139,7 +138,6 @@ export class Range extends BaseInput<any> implements AfterViewInit, ControlValue
|
||||
_barL: string;
|
||||
_barR: string;
|
||||
|
||||
_debouncer: TimeoutDebouncer = new TimeoutDebouncer(0);
|
||||
_events: UIEventManager;
|
||||
|
||||
@ViewChild('slider') public _slider: ElementRef;
|
||||
@ -268,9 +266,8 @@ export class Range extends BaseInput<any> implements AfterViewInit, ControlValue
|
||||
private _dom: DomController,
|
||||
private _cd: ChangeDetectorRef
|
||||
) {
|
||||
super(config, elementRef, renderer, 'range', form, item, null);
|
||||
super(config, elementRef, renderer, 'range', 0, form, item, null);
|
||||
this._events = new UIEventManager(_plt);
|
||||
this._value = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -7,6 +7,7 @@ import { commonInputTest, NUMBER_CORPUS } from '../../../util/input-tester';
|
||||
describe('Range', () => {
|
||||
|
||||
it('should pass common test', () => {
|
||||
// TODO, validate range inside bounds
|
||||
const range = createRange();
|
||||
range._slider = mockElementRef();
|
||||
commonInputTest(range, {
|
||||
|
||||
@ -62,7 +62,6 @@ export class Searchbar extends BaseInput<string> {
|
||||
_autocomplete: string = 'off';
|
||||
_autocorrect: string = 'off';
|
||||
_isActive: boolean = false;
|
||||
_debouncer: TimeoutDebouncer = new TimeoutDebouncer(250);
|
||||
_showCancelButton: boolean = false;
|
||||
_animated: boolean = false;
|
||||
|
||||
@ -165,7 +164,8 @@ export class Searchbar extends BaseInput<string> {
|
||||
renderer: Renderer,
|
||||
@Optional() ngControl: NgControl
|
||||
) {
|
||||
super(config, elementRef, renderer, 'searchbar', null, null, ngControl);
|
||||
super(config, elementRef, renderer, 'searchbar', '', null, null, ngControl);
|
||||
this.debounce = 250;
|
||||
}
|
||||
|
||||
@ViewChild('searchbarInput') _searchbarInput: ElementRef;
|
||||
|
||||
@ -77,7 +77,7 @@ export class Segment extends BaseInput<string> {
|
||||
renderer: Renderer,
|
||||
@Optional() ngControl: NgControl
|
||||
) {
|
||||
super(config, elementRef, renderer, 'segment', null, null, ngControl);
|
||||
super(config, elementRef, renderer, 'segment', null, null, null, ngControl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
31
src/components/segment/test/segment.spec.ts
Normal file
31
src/components/segment/test/segment.spec.ts
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
import { QueryList } from '@angular/core';
|
||||
import { Segment } from '../segment';
|
||||
import { SegmentButton } from '../segment-button';
|
||||
import { mockConfig, mockElementRef, mockRenderer } from '../../../util/mock-providers';
|
||||
import { commonInputTest } from '../../../util/input-tester';
|
||||
|
||||
describe('Segment', () => {
|
||||
|
||||
it('should pass common test', () => {
|
||||
|
||||
const config = mockConfig();
|
||||
const elementRef = mockElementRef();
|
||||
const renderer = mockRenderer();
|
||||
const segment = new Segment(config, elementRef, renderer, null);
|
||||
segment._buttons = new QueryList<SegmentButton>();
|
||||
|
||||
commonInputTest(segment, {
|
||||
defaultValue: null,
|
||||
corpus: [
|
||||
['option1', 'option1'],
|
||||
['option2', 'option2'],
|
||||
['option3', 'option3'],
|
||||
['option4', 'option4'],
|
||||
['', ''],
|
||||
]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@ -7,7 +7,7 @@ import { App } from '../app/app';
|
||||
import { Config } from '../../config/config';
|
||||
import { Form } from '../../util/form';
|
||||
import { BaseInput } from '../../util/base-input';
|
||||
import { isCheckedProperty, isTrueProperty, isBlank, deepCopy } from '../../util/util';
|
||||
import { isCheckedProperty, isTrueProperty, isBlank, deepCopy, deepEqual } from '../../util/util';
|
||||
import { Item } from '../item/item';
|
||||
import { NavController } from '../../navigation/nav-controller';
|
||||
import { Option } from '../option/option';
|
||||
@ -195,8 +195,7 @@ export class Select extends BaseInput<string[]> implements AfterViewInit, OnDest
|
||||
@Optional() item: Item,
|
||||
@Optional() private _nav: NavController
|
||||
) {
|
||||
super(config, elementRef, renderer, 'select', form, item, null);
|
||||
this._value = [];
|
||||
super(config, elementRef, renderer, 'select', [], form, item, null);
|
||||
}
|
||||
|
||||
|
||||
@ -259,7 +258,7 @@ export class Select extends BaseInput<string[]> implements AfterViewInit, OnDest
|
||||
this.interface = 'alert';
|
||||
}
|
||||
|
||||
let overlay: any;
|
||||
let overlay: ActionSheet | Alert;
|
||||
if (this.interface === 'action-sheet') {
|
||||
selectOptions.buttons = selectOptions.buttons.concat(options.map(input => {
|
||||
return {
|
||||
@ -321,7 +320,7 @@ export class Select extends BaseInput<string[]> implements AfterViewInit, OnDest
|
||||
|
||||
overlay.addButton({
|
||||
text: this.okText,
|
||||
handler: (selectedValues: any) => this.value = selectedValues
|
||||
handler: (selectedValues) => this.value = selectedValues
|
||||
});
|
||||
|
||||
}
|
||||
@ -373,20 +372,17 @@ export class Select extends BaseInput<string[]> implements AfterViewInit, OnDest
|
||||
}
|
||||
|
||||
_inputNormalize(val: any): string[] {
|
||||
if (val === null) {
|
||||
if (isBlank(val)) {
|
||||
return [];
|
||||
}
|
||||
if (Array.isArray(val)) {
|
||||
return val;
|
||||
}
|
||||
return isBlank(val) ? [] : [val];
|
||||
return [val + ''];
|
||||
}
|
||||
|
||||
_inputShouldChange(val: string[]): boolean {
|
||||
if (val.length === 0 && this._value.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return super._inputShouldChange(val);
|
||||
return !deepEqual(this._value, val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
import { Select } from '../select';
|
||||
import { mockApp, mockConfig, mockElementRef, mockRenderer, mockItem, mockForm } from '../../../util/mock-providers';
|
||||
import { commonInputTest, BOOLEAN_CORPUS } from '../../../util/input-tester';
|
||||
import { commonInputTest } from '../../../util/input-tester';
|
||||
|
||||
describe('Select', () => {
|
||||
|
||||
@ -16,8 +16,13 @@ describe('Select', () => {
|
||||
const select = new Select(app, form, config, elementRef, renderer, item, null);
|
||||
|
||||
commonInputTest(select, {
|
||||
defaultValue: false,
|
||||
corpus: BOOLEAN_CORPUS
|
||||
defaultValue: [],
|
||||
corpus: [
|
||||
[['hola'], ['hola']],
|
||||
[null, []],
|
||||
['hola', ['hola']],
|
||||
[['hola', 'adios'], ['hola', 'adios']]
|
||||
]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -20,7 +20,7 @@ describe('Toggle', () => {
|
||||
|
||||
commonInputTest(toggle, {
|
||||
defaultValue: false,
|
||||
corpus: BOOLEAN_CORPUS
|
||||
corpus: BOOLEAN_CORPUS,
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -109,8 +109,7 @@ export class Toggle extends BaseInput<boolean> implements IonicTapInput, AfterVi
|
||||
private _domCtrl: DomController,
|
||||
private _cd: ChangeDetectorRef
|
||||
) {
|
||||
super(config, elementRef, renderer, 'toggle', form, item, null);
|
||||
this._value = false;
|
||||
super(config, elementRef, renderer, 'toggle', false, form, item, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -2,7 +2,7 @@ import { ElementRef, EventEmitter, Input, Output, Renderer } from '@angular/core
|
||||
import { ControlValueAccessor } from '@angular/forms';
|
||||
import { NgControl } from '@angular/forms';
|
||||
|
||||
import { isPresent, isArray, isTrueProperty, assert } from './util';
|
||||
import { isPresent, isUndefined, isArray, isTrueProperty, deepCopy, assert } from './util';
|
||||
import { Ion } from '../components/ion';
|
||||
import { Config } from '../config/config';
|
||||
import { Item } from '../components/item/item';
|
||||
@ -30,13 +30,13 @@ export interface CommonInput<T> extends ControlValueAccessor {
|
||||
|
||||
export class BaseInput<T> extends Ion implements CommonInput<T> {
|
||||
|
||||
_value: T = null;
|
||||
_value: T;
|
||||
_onChanged: Function;
|
||||
_onTouched: Function;
|
||||
_isFocus: boolean = false;
|
||||
_labelId: string;
|
||||
_disabled: boolean = false;
|
||||
_debouncer: TimeoutDebouncer;
|
||||
_debouncer: TimeoutDebouncer = new TimeoutDebouncer(0);
|
||||
_init: boolean = false;
|
||||
id: string;
|
||||
|
||||
@ -66,18 +66,19 @@ export class BaseInput<T> extends Ion implements CommonInput<T> {
|
||||
this.setDisabledState(val);
|
||||
}
|
||||
|
||||
|
||||
constructor(
|
||||
config: Config,
|
||||
elementRef: ElementRef,
|
||||
renderer: Renderer,
|
||||
name: string,
|
||||
private _defaultValue: T,
|
||||
public _form: Form,
|
||||
public _item: Item,
|
||||
ngControl: NgControl
|
||||
) {
|
||||
super(config, elementRef, renderer, name);
|
||||
_form && _form.register(this);
|
||||
this._value = deepCopy(this._defaultValue);
|
||||
|
||||
if (_item) {
|
||||
this.id = name + '-' + _item.registerInput(name);
|
||||
@ -103,7 +104,7 @@ export class BaseInput<T> extends Ion implements CommonInput<T> {
|
||||
// 1. Updates the value
|
||||
// 2. Calls _inputUpdated()
|
||||
// 3. Dispatch onChange events
|
||||
setValue(val: T) {
|
||||
setValue(val: any) {
|
||||
this.value = val;
|
||||
}
|
||||
|
||||
@ -123,20 +124,27 @@ export class BaseInput<T> extends Ion implements CommonInput<T> {
|
||||
}
|
||||
|
||||
_writeValue(val: any): boolean {
|
||||
const normalized = this._inputNormalize(val);
|
||||
const shouldUpdate = this._inputShouldChange(normalized);
|
||||
if (shouldUpdate) {
|
||||
if (isUndefined(val)) {
|
||||
return false;
|
||||
}
|
||||
const normalized = (val === null)
|
||||
? deepCopy(this._defaultValue)
|
||||
: this._inputNormalize(val);
|
||||
|
||||
const notUpdate = isUndefined(normalized) || !this._inputShouldChange(normalized);
|
||||
if (notUpdate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
console.debug('BaseInput: value changed:', normalized, this);
|
||||
this._value = normalized;
|
||||
this._inputCheckHasValue(normalized);
|
||||
this._inputUpdated();
|
||||
if (this._init) {
|
||||
this.ionChange.emit(this);
|
||||
this._debouncer.debounce(() => this.ionChange.emit(this));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
@ -224,12 +232,11 @@ export class BaseInput<T> extends Ion implements CommonInput<T> {
|
||||
if (!this._item) {
|
||||
return;
|
||||
}
|
||||
let hasValue: boolean;
|
||||
if (isArray(val)) {
|
||||
hasValue = val.length > 0;
|
||||
} else {
|
||||
hasValue = isPresent(val);
|
||||
}
|
||||
|
||||
const hasValue = isArray(val)
|
||||
? val.length > 0
|
||||
: isPresent(val);
|
||||
|
||||
this._item.setElementClass('input-has-value', hasValue);
|
||||
}
|
||||
|
||||
@ -249,7 +256,7 @@ export class BaseInput<T> extends Ion implements CommonInput<T> {
|
||||
* @hidden
|
||||
*/
|
||||
_inputShouldChange(val: T): boolean {
|
||||
return (typeof val !== 'undefined') && this._value !== val;
|
||||
return this._value !== val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -21,7 +21,7 @@ export const NUMBER_CORPUS: any[] = [
|
||||
[123456789, 123456789],
|
||||
['1.1234', 1.1234],
|
||||
['123456789', 123456789],
|
||||
['-123456789', -123456789],
|
||||
['-123456789', -123456789]
|
||||
];
|
||||
|
||||
export const BOOLEAN_CORPUS: any[] = [
|
||||
@ -30,13 +30,11 @@ export const BOOLEAN_CORPUS: any[] = [
|
||||
['', true],
|
||||
['false', false],
|
||||
['true', true],
|
||||
['hola', false]
|
||||
];
|
||||
|
||||
export const ANY_CORPUS: any[] = [
|
||||
[true, true],
|
||||
[false, false],
|
||||
[null, null],
|
||||
[0, 0],
|
||||
['', ''],
|
||||
[' ', ' '],
|
||||
@ -68,16 +66,36 @@ function testInput<T>(input: BaseInput<T>, config: TestConfig, isInit: boolean)
|
||||
}
|
||||
|
||||
function testState<T>(input: BaseInput<T>, config: TestConfig, isInit: boolean) {
|
||||
assert(input._init === isInit, 'input must be init');
|
||||
assert(!input._isFocus && !input.isFocus(), 'should not be focus');
|
||||
assert(input.value === config.defaultValue, 'default value is wrong');
|
||||
|
||||
assertEqual(input._init, isInit, 'input must be init');
|
||||
assertEqual(input._isFocus, false, 'should not be focus');
|
||||
assertEqual(input.isFocus(), false, 'should not be focus');
|
||||
assertEqual(input.value, config.defaultValue, 'default value is wrong');
|
||||
|
||||
let blurCount = 0;
|
||||
let focusCount = 0;
|
||||
const subBlur = input.ionBlur.subscribe((ev: any) => {
|
||||
assertEqual(ev, input, 'ionBlur argument is wrong');
|
||||
blurCount++;
|
||||
});
|
||||
const subFocus = input.ionFocus.subscribe((ev: any) => {
|
||||
assertEqual(ev, input, 'ionFocus argument is wrong');
|
||||
focusCount++;
|
||||
});
|
||||
input._setFocus();
|
||||
assert(input._isFocus && input.isFocus(), 'should be focus');
|
||||
input._setFocus(); // it should not crash
|
||||
assertEqual(input._isFocus, true, 'should be focus');
|
||||
assertEqual(input.isFocus(), true, 'should be focus');
|
||||
input._setFocus();
|
||||
|
||||
input._setBlur();
|
||||
assert(!input._isFocus && !input.isFocus(), 'should not be focus');
|
||||
assertEqual(input._isFocus, false, 'should be not focus');
|
||||
assertEqual(input.isFocus(), false, 'should be not focus');
|
||||
input._setBlur(); // it should not crash
|
||||
|
||||
assertEqual(focusCount, 1, 'ionFocus was not called correctly');
|
||||
assertEqual(blurCount, 1, 'ionBlur was not called correctly');
|
||||
|
||||
subBlur.unsubscribe();
|
||||
subFocus.unsubscribe();
|
||||
}
|
||||
|
||||
function testWriteValue<T>(input: BaseInput<T>, config: TestConfig, isInit: boolean) {
|
||||
@ -87,27 +105,28 @@ function testWriteValue<T>(input: BaseInput<T>, config: TestConfig, isInit: bool
|
||||
let OnChangeCalled = 0;
|
||||
let OnTouchedCalled = 0;
|
||||
|
||||
input.value = config.defaultValue;
|
||||
|
||||
// Test ionChange
|
||||
let sub = input.ionChange.subscribe((ev: any) => {
|
||||
assert(ionChangeCalled === 0, 'internal error');
|
||||
assert(ev === input, 'ev is not the input');
|
||||
assert(test[1] === ev.value, 'value does not match');
|
||||
assertEqual(ionChangeCalled, 0, 'ionChange: internal error');
|
||||
assertEqual(ev, input, 'ionChange: ev is not the input');
|
||||
assertEqual(ev.value, test[1], 'ionChange: value does not match');
|
||||
|
||||
ionChangeCalled++;
|
||||
});
|
||||
|
||||
// Test registerOnChange
|
||||
input.registerOnChange((ev: any) => {
|
||||
assert(OnChangeCalled === 0, 'internal error');
|
||||
assert(ev === input.value, 'ev output does not match');
|
||||
assert(test[1] === input.value, 'value does not match');
|
||||
assertEqual(OnChangeCalled, 0, 'registerOnChange: internal error');
|
||||
assertEqual(input.value, ev, 'registerOnChange: ev output does not match');
|
||||
assertEqual(input.value, test[1], 'registerOnChange: value does not match');
|
||||
|
||||
OnChangeCalled++;
|
||||
});
|
||||
|
||||
// Test registerOnChange
|
||||
input.registerOnTouched(() => {
|
||||
assert(OnTouchedCalled === 0, 'internal error');
|
||||
assertEqual(OnTouchedCalled, 0, 'registerOnTouched: internal error');
|
||||
|
||||
OnTouchedCalled++;
|
||||
});
|
||||
|
||||
@ -115,28 +134,45 @@ function testWriteValue<T>(input: BaseInput<T>, config: TestConfig, isInit: bool
|
||||
for (i = 0; i < config.corpus.length; i++) {
|
||||
test = config.corpus[i];
|
||||
input.value = test[0];
|
||||
assert(input.value === test[1], 'input/output does not match');
|
||||
assertEqual(input.value, test[1], 'loop: input/output does not match');
|
||||
if (isInit) {
|
||||
assert(ionChangeCalled === 1, 'ionChange error');
|
||||
assertEqual(ionChangeCalled, 1, 'loop: ionChange error');
|
||||
} else {
|
||||
assert(ionChangeCalled === 0, 'ionChange error');
|
||||
assertEqual(ionChangeCalled, 0, 'loop: ionChange error');
|
||||
}
|
||||
assert(OnChangeCalled === 1, 'OnChangeCalled was not called');
|
||||
assert(OnTouchedCalled === 1, 'OnTouchedCalled was not called');
|
||||
assertEqual(OnChangeCalled, 1, 'loop: OnChangeCalled was not called');
|
||||
assertEqual(OnTouchedCalled, 1, 'loop: OnTouchedCalled was not called');
|
||||
|
||||
OnTouchedCalled = OnChangeCalled = ionChangeCalled = 0;
|
||||
|
||||
console.log(test[0], input.value);
|
||||
// Set same value (it should not redispatch)
|
||||
input.value = test[0];
|
||||
assert(ionChangeCalled === 0, 'ionChange should not be called');
|
||||
assert(OnChangeCalled === 0, 'OnChangeCalled should not be called');
|
||||
assertEqual(ionChangeCalled, 0, 'loop: ionChange should not be called');
|
||||
assertEqual(OnChangeCalled, 0, 'loop: OnChangeCalled should not be called');
|
||||
// TODO OnTouchedCalled?
|
||||
OnTouchedCalled = OnChangeCalled = ionChangeCalled = 0;
|
||||
}
|
||||
|
||||
// Test undefined
|
||||
input.value = undefined;
|
||||
assertEqual(input.value, test[1], 'undefined should not change the value');
|
||||
assertEqual(ionChangeCalled, 0, 'undefined: ionChange should not be called');
|
||||
assertEqual(OnChangeCalled, 0, 'undefined: OnChangeCalled should not be called');
|
||||
assertEqual(OnTouchedCalled, 0, 'undefined: OnTouchedCalled should not be called');
|
||||
|
||||
|
||||
// Test null (reset)
|
||||
test = [null, config.defaultValue];
|
||||
input.value = null;
|
||||
assertEqual(input.value, config.defaultValue, 'null: wrong default value');
|
||||
assertEqual(OnChangeCalled, 1, 'null: OnChangeCalled was not called');
|
||||
assertEqual(OnTouchedCalled, 1, 'null: OnTouchedCalled was not called');
|
||||
|
||||
|
||||
input.registerOnChange(null);
|
||||
input.registerOnTouched(null);
|
||||
sub.unsubscribe();
|
||||
input.value = config.defaultValue;
|
||||
}
|
||||
|
||||
function testNgModelChange<T>(input: BaseInput<T>, config: TestConfig, isInit: boolean) {
|
||||
@ -148,9 +184,10 @@ function testNgModelChange<T>(input: BaseInput<T>, config: TestConfig, isInit: b
|
||||
|
||||
// Test ionChange
|
||||
let sub = input.ionChange.subscribe((ev: any) => {
|
||||
assert(ionChangeCalled === 0, 'internal error');
|
||||
assert(ev === input, 'ev output does not match');
|
||||
assert(test[1] === ev.value, 'value does not match');
|
||||
assertEqual(ionChangeCalled, 0, 'internal error');
|
||||
assertEqual(ev, input, 'ev output does not match');
|
||||
assertEqual(test[1], ev.value, 'value does not match');
|
||||
|
||||
ionChangeCalled++;
|
||||
});
|
||||
|
||||
@ -169,21 +206,21 @@ function testNgModelChange<T>(input: BaseInput<T>, config: TestConfig, isInit: b
|
||||
test = config.corpus[i];
|
||||
input.writeValue(test[0]);
|
||||
|
||||
assert(input.value === test[1], 'input/output does not match');
|
||||
assertEqual(input.value, test[1], 'input/output does not match');
|
||||
if (isInit) {
|
||||
assert(ionChangeCalled === 1, 'ionChange error');
|
||||
assertEqual(ionChangeCalled, 1, 'ionChange error');
|
||||
} else {
|
||||
assert(ionChangeCalled === 0, 'ionChange error');
|
||||
assertEqual(ionChangeCalled, 0, 'ionChange error');
|
||||
}
|
||||
assert(OnChangeCalled === 0, 'OnChangeCalled should not be called');
|
||||
assert(OnTouchedCalled === 0, 'OnTouchedCalled should not be called');
|
||||
assertEqual(OnChangeCalled, 0, 'OnChangeCalled should not be called');
|
||||
assertEqual(OnTouchedCalled, 0, 'OnTouchedCalled should not be called');
|
||||
OnTouchedCalled = OnChangeCalled = ionChangeCalled = 0;
|
||||
|
||||
// Set same value (it should not redispatch)
|
||||
input.writeValue(test[0]);
|
||||
input.value = test[0];
|
||||
assert(ionChangeCalled === 0, 'ionChange should not be called');
|
||||
assert(OnChangeCalled === 0, 'OnChangeCalled should not be called');
|
||||
assertEqual(ionChangeCalled, 0, 'ionChange should not be called');
|
||||
assertEqual(OnChangeCalled, 0, 'OnChangeCalled should not be called');
|
||||
|
||||
// TODO OnTouchedCalled?
|
||||
OnTouchedCalled = OnChangeCalled = ionChangeCalled = 0;
|
||||
@ -195,7 +232,19 @@ function testNgModelChange<T>(input: BaseInput<T>, config: TestConfig, isInit: b
|
||||
input.value = config.defaultValue;
|
||||
}
|
||||
|
||||
function assertEqual(a: any, b: any, message: string) {
|
||||
if (!equal(a, b)) {
|
||||
assert(false, a + ' != ' + b + ' ' + message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function equal(a: any, b: any): boolean {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
// return false;
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -51,5 +51,5 @@ function mockInput(form: any, item: any, ngControl: any): BaseInput<any> {
|
||||
config = mockConfig(null, '/', platform);
|
||||
elementRef = mockElementRef();
|
||||
renderer = mockRenderer();
|
||||
return new BaseInput(config, elementRef, renderer, 'input', form, item, ngControl);
|
||||
return new BaseInput(config, elementRef, renderer, 'input', null, form, item, ngControl);
|
||||
}
|
||||
|
||||
@ -16,6 +16,14 @@ export function deepCopy(obj: any) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
export function deepEqual(a: any, b: any) {
|
||||
if (a === b) {
|
||||
return true;
|
||||
}
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
export function debounce(fn: Function, wait: number, immediate: boolean = false): any {
|
||||
var timeout: number, args: any, context: any, timestamp: number, result: any;
|
||||
|
||||
Reference in New Issue
Block a user