From 035f1ad3cc7f679e465fdaeb88bc1c5c146c9421 Mon Sep 17 00:00:00 2001 From: Andrii Kamaldinov <129040945+andriikamaldinov1@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:46:28 +0200 Subject: [PATCH] feat(ref: no-ref): enhancements (#1467) * feat(ref: no-ref): chane @Input, @Ouput to signal * feat(ref: no-ref): add security autoCsp, unusedStandaloneImports to error * feat(ref: no-ref): change tests to signals * feat(ref: no-ref): change tests to signals * feat(ref: no-ref): remove unusable code * feat(ref: no-ref): remove unusable code * feat(ref: no-ref): did ngxtension migration --- CHANGELOG.md | 9 + angular.json | 1 + bun.lockb | Bin 1078786 -> 1092623 bytes package.json | 3 +- projects/ngx-mask-lib/package.json | 2 +- .../src/lib/ngx-mask-applier.service.ts | 11 - .../ngx-mask-lib/src/lib/ngx-mask.config.ts | 2 - .../src/lib/ngx-mask.directive.ts | 502 ++++++------ .../ngx-mask-lib/src/lib/ngx-mask.pipe.ts | 27 +- .../ngx-mask-lib/src/lib/ngx-mask.service.ts | 30 +- .../ngx-mask-lib/src/test/add-prefix.spec.ts | 75 +- .../ngx-mask-lib/src/test/add-suffix.spec.ts | 21 +- .../src/test/allow-negative-numbers.spec.ts | 51 +- .../ngx-mask-lib/src/test/basic-logic.spec.ts | 203 +++-- .../test/clear-if-not-match-the-mask.spec.ts | 25 +- .../src/test/complete-mask.spec.ts | 13 +- .../ngx-mask-lib/src/test/copy-paste.spec.ts | 9 +- .../ngx-mask-lib/src/test/custom-date.spec.ts | 9 +- .../src/test/custom-patterns.spec.ts | 37 +- .../src/test/custom-symbol-regexp.spec.ts | 9 +- .../src/test/default-config.spec.ts | 21 +- projects/ngx-mask-lib/src/test/delete.spec.ts | 39 +- .../src/test/drop-special-charaters.spec.ts | 51 +- .../ngx-mask-lib/src/test/dynamic.spec.ts | 43 +- .../ngx-mask-lib/src/test/export-as.spec.ts | 3 +- .../src/test/inputTransformFn.spec.ts | 87 +- .../ngx-mask-lib/src/test/mask.pipe.spec.ts | 4 +- .../ngx-mask-lib/src/test/percent.spec.ts | 131 ++- .../src/test/place-holder-character.spec.ts | 57 +- .../ngx-mask-lib/src/test/repeat-mask.spec.ts | 33 +- .../ngx-mask-lib/src/test/secure-mask.spec.ts | 99 ++- .../src/test/separator-non-en-locale.spec.ts | 39 +- .../ngx-mask-lib/src/test/separator.spec.ts | 757 +++++++++--------- .../src/test/show-mask-typed.spec.ts | 139 ++-- .../ngx-mask-lib/src/test/test-sufix.spec.ts | 31 +- .../ngx-mask-lib/src/test/time-mask.spec.ts | 163 ++-- .../src/test/trigger-on-mask-change.spec.ts | 15 +- .../ngx-mask-lib/src/test/type-number.spec.ts | 14 +- .../test/utils/test-component.component.ts | 136 ++-- .../ngx-mask-lib/src/test/validation.spec.ts | 54 +- src/app/options/options.component.html | 5 +- src/assets/content/optional.ts | 2 +- src/libraries | 2 +- tsconfig.json | 8 +- 44 files changed, 1463 insertions(+), 1509 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fe19938..eea45e25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# 19.0.1(2024-11-29) + +### Feature + +- change @Input to input in NgxMaskDirective +- change @Output output in NgxMaskDirective +- change variables to signals in NgxMaskDirective + + # 19.0.0(2024-11-22) ### Feature diff --git a/angular.json b/angular.json index 19f82bd1..aa3b1f07 100644 --- a/angular.json +++ b/angular.json @@ -13,6 +13,7 @@ "build": { "builder": "@angular-devkit/build-angular:application", "options": { + "security": { "autoCsp": true }, "outputPath": "dist/ngx-mask", "index": "src/index.html", "browser": "src/main.ts", diff --git a/bun.lockb b/bun.lockb index fea09b4a36133c6ae0053971dbd085f77e92c1a1..42384d2ff595357fe6cf37da863fe024cd6ddd21 100755 GIT binary patch delta 231394 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

_4F>?p_BJ!tdV?R`q?AfsLblocl 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 z zd}Gj4C;TttO(Vl;OX{>m?~?IrGeg5lMS6x~;^0+}EN0_nr-6pgmKlqN8md@iR2XhJ zVnuI88Y*VAOf`I0ln%w)7-;b*L!k`!$%eO18P=-};k9Y_14BP@KW1=4h9^T7wR>m? z%J}=CA-Wg^zc&=gi22)4p(dsJ+Z3ee>Nabr^L@xBpoUF~kBB?+O6Y|IDNw<<*gjsY zP3V`{L{{sFgh2sb=(2dMs9wFW9B0%u*}S*RC{)X)gN4*aYVirOSQ}*Hk?|?Wrkn-6 rm}jubaI0fe&N8EQJ)4~t8KDhqZtSDqJ{w$iPPEOm$Vk)LrX~J=2k$Wm delta 225084 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 nWw`CtUC6&AHm3&(); - - private _maskValue = ''; - - private _inputValue!: string; - - private _position: number | null = null; - - private _code!: string; - - private _maskExpressionArray: string[] = []; - - private _allowFewMaskChangeMask = false; - - private _justPasted = false; - - private _isFocused = false; - + public mask = input(''); + public specialCharacters = input([]); + public patterns = input({}); + public prefix = input(''); + public suffix = input(''); + public thousandSeparator = input(' '); + public decimalMarker = input('.'); + public dropSpecialCharacters = input(null); + public hiddenInput = input(null); + public showMaskTyped = input(null); + public placeHolderCharacter = input(null); + public shownMaskExpression = input(null); + public clearIfNotMatch = input(null); + public validation = input(null); + public separatorLimit = input(''); + public allowNegativeNumbers = input(null); + public leadZeroDateTime = input(null); + public leadZero = input(null); + public triggerOnMaskChange = input(null); + public apm = input(null); + public inputTransformFn = input(null); + public outputTransformFn = input(null); + public keepCharacterPositions = input(null); + + public maskFilled = output(); + + private _maskValue = signal(''); + private _inputValue = signal(''); + private _position = signal(null); + private _code = signal(''); + private _maskExpressionArray = signal([]); + private _allowFewMaskChangeMask = signal(false); + private _justPasted = signal(false); + private _isFocused = signal(false); /**For IME composition event */ - private _isComposing = false; - - private readonly document = inject(DOCUMENT); + private _isComposing = signal(false); public _maskService = inject(NgxMaskService, { self: true }); + private readonly document = inject(DOCUMENT); + protected _config = inject(NGX_MASK_CONFIG); // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -117,7 +85,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida public ngOnChanges(changes: SimpleChanges): void { const { - maskExpression, + mask, specialCharacters, patterns, prefix, @@ -129,7 +97,6 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida showMaskTyped, placeHolderCharacter, shownMaskExpression, - showTemplate, clearIfNotMatch, validation, separatorLimit, @@ -142,27 +109,21 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida outputTransformFn, keepCharacterPositions, } = changes; - if (maskExpression) { - if ( - maskExpression.currentValue !== maskExpression.previousValue && - !maskExpression.firstChange - ) { + if (mask) { + if (mask.currentValue !== mask.previousValue && !mask.firstChange) { this._maskService.maskChanged = true; } - if ( - maskExpression.currentValue && - maskExpression.currentValue.split(MaskExpression.OR).length > 1 - ) { - this._maskExpressionArray = maskExpression.currentValue - .split(MaskExpression.OR) - .sort((a: string, b: string) => { + if (mask.currentValue && mask.currentValue.split(MaskExpression.OR).length > 1) { + this._maskExpressionArray.set( + mask.currentValue.split(MaskExpression.OR).sort((a: string, b: string) => { return a.length - b.length; - }); + }) + ); this._setMask(); } else { - this._maskExpressionArray = []; - this._maskValue = maskExpression.currentValue || MaskExpression.EMPTY_STRING; - this._maskService.maskExpression = this._maskValue; + this._maskExpressionArray.set([]); + this._maskValue.set(mask.currentValue || MaskExpression.EMPTY_STRING); + this._maskService.maskExpression = this._maskValue(); } } if (specialCharacters) { @@ -210,7 +171,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida if ( showMaskTyped.previousValue === false && showMaskTyped.currentValue === true && - this._isFocused + this._isFocused() ) { requestAnimationFrame(() => { this._maskService._elementRef?.nativeElement.click(); @@ -223,9 +184,6 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida if (shownMaskExpression) { this._maskService.shownMaskExpression = shownMaskExpression.currentValue; } - if (showTemplate) { - this._maskService.showTemplate = showTemplate.currentValue; - } if (clearIfNotMatch) { this._maskService.clearIfNotMatch = clearIfNotMatch.currentValue; } @@ -258,8 +216,9 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida public validate({ value }: FormControl): ValidationErrors | null { const processedValue: string = typeof value === 'number' ? String(value) : value; + const maskValue = this._maskValue(); - if (!this._maskService.validation || !this._maskValue) { + if (!this._maskService.validation || !maskValue) { return null; } if (this._maskService.ipError) { @@ -268,19 +227,19 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida if (this._maskService.cpfCnpjError) { return this._createValidationError(processedValue); } - if (this._maskValue.startsWith(MaskExpression.SEPARATOR)) { + if (maskValue.startsWith(MaskExpression.SEPARATOR)) { return null; } - if (withoutValidation.includes(this._maskValue)) { + if (withoutValidation.includes(maskValue)) { return null; } if (this._maskService.clearIfNotMatch) { return null; } - if (timeMasks.includes(this._maskValue)) { + if (timeMasks.includes(maskValue)) { return this._validateTime(processedValue); } - if (this._maskValue === MaskExpression.EMAIL_MASK) { + if (maskValue === MaskExpression.EMAIL_MASK) { const emailPattern = /^[^@]+@[^@]+\.[^@]+$/; if (!emailPattern.test(processedValue) && processedValue) { @@ -293,63 +252,63 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida let counterOfOpt = 0; if ( - this._maskValue.includes(MaskExpression.CURLY_BRACKETS_LEFT) && - this._maskValue.includes(MaskExpression.CURLY_BRACKETS_RIGHT) + maskValue.includes(MaskExpression.CURLY_BRACKETS_LEFT) && + maskValue.includes(MaskExpression.CURLY_BRACKETS_RIGHT) ) { - const lengthInsideCurlyBrackets = this._maskValue.slice( - this._maskValue.indexOf(MaskExpression.CURLY_BRACKETS_LEFT) + 1, - this._maskValue.indexOf(MaskExpression.CURLY_BRACKETS_RIGHT) + const lengthInsideCurlyBrackets = maskValue.slice( + maskValue.indexOf(MaskExpression.CURLY_BRACKETS_LEFT) + 1, + maskValue.indexOf(MaskExpression.CURLY_BRACKETS_RIGHT) ); return lengthInsideCurlyBrackets === String(processedValue.length) ? null : this._createValidationError(processedValue); } - if (this._maskValue.startsWith(MaskExpression.PERCENT)) { + if (maskValue.startsWith(MaskExpression.PERCENT)) { return null; } for (const key in this._maskService.patterns) { if (this._maskService.patterns[key]?.optional) { - if (this._maskValue.indexOf(key) !== this._maskValue.lastIndexOf(key)) { - const opt: string = this._maskValue + if (maskValue.indexOf(key) !== maskValue.lastIndexOf(key)) { + const opt: string = maskValue .split(MaskExpression.EMPTY_STRING) .filter((i: string) => i === key) .join(MaskExpression.EMPTY_STRING); counterOfOpt += opt.length; - } else if (this._maskValue.indexOf(key) !== -1) { + } else if (maskValue.indexOf(key) !== -1) { counterOfOpt++; } if ( - this._maskValue.indexOf(key) !== -1 && - processedValue.length >= this._maskValue.indexOf(key) + maskValue.indexOf(key) !== -1 && + processedValue.length >= maskValue.indexOf(key) ) { return null; } - if (counterOfOpt === this._maskValue.length) { + if (counterOfOpt === maskValue.length) { return null; } } } if ( - (this._maskValue.indexOf(MaskExpression.SYMBOL_STAR) > 1 && - processedValue.length < this._maskValue.indexOf(MaskExpression.SYMBOL_STAR)) || - (this._maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) > 1 && - processedValue.length < this._maskValue.indexOf(MaskExpression.SYMBOL_QUESTION)) + (maskValue.indexOf(MaskExpression.SYMBOL_STAR) > 1 && + processedValue.length < maskValue.indexOf(MaskExpression.SYMBOL_STAR)) || + (maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) > 1 && + processedValue.length < maskValue.indexOf(MaskExpression.SYMBOL_QUESTION)) ) { return this._createValidationError(processedValue); } if ( - this._maskValue.indexOf(MaskExpression.SYMBOL_STAR) === -1 || - this._maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) === -1 + maskValue.indexOf(MaskExpression.SYMBOL_STAR) === -1 || + maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) === -1 ) { - const array = this._maskValue.split('*'); + const array = maskValue.split('*'); const length: number = this._maskService.dropSpecialCharacters - ? this._maskValue.length - - this._maskService.checkDropSpecialCharAmount(this._maskValue) - + ? maskValue.length - + this._maskService.checkDropSpecialCharAmount(maskValue) - counterOfOpt - : this.prefix - ? this._maskValue.length + this.prefix.length - counterOfOpt - : this._maskValue.length - counterOfOpt; + : this.prefix() + ? maskValue.length + this.prefix().length - counterOfOpt + : maskValue.length - counterOfOpt; if (array.length === 1) { if (processedValue.length < length) { @@ -362,7 +321,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida lastIndexArray && this._maskService.specialCharacters.includes(lastIndexArray[0] as string) && String(processedValue).includes(lastIndexArray[0] ?? '') && - !this.dropSpecialCharacters + !this.dropSpecialCharacters() ) { const special = value.split(lastIndexArray[0]); return special[special.length - 1].length === lastIndexArray.length - 1 @@ -384,8 +343,8 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida } } if ( - this._maskValue.indexOf(MaskExpression.SYMBOL_STAR) === 1 || - this._maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) === 1 + maskValue.indexOf(MaskExpression.SYMBOL_STAR) === 1 || + maskValue.indexOf(MaskExpression.SYMBOL_QUESTION) === 1 ) { return null; } @@ -399,11 +358,11 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida @HostListener('paste') public onPaste() { - this._justPasted = true; + this._justPasted.set(true); } @HostListener('focus', ['$event']) public onFocus() { - this._isFocused = true; + this._isFocused.set(true); } @HostListener('ngModelChange', ['$event']) @@ -424,19 +383,20 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida @HostListener('input', ['$event']) public onInput(e: CustomKeyboardEvent): void { // If IME is composing text, we wait for the composed text. - if (this._isComposing) { + if (this._isComposing()) { return; } const el: HTMLInputElement = e.target as HTMLInputElement; const transformedValue = this._maskService.inputTransformFn(el.value); + if (el.type !== 'number') { if (typeof transformedValue === 'string' || typeof transformedValue === 'number') { el.value = transformedValue.toString(); - this._inputValue = el.value; + this._inputValue.set(el.value); this._setMask(); - if (!this._maskValue) { + if (!this._maskValue()) { this.onChange(el.value); return; } @@ -447,12 +407,14 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida : (el.selectionStart as number); if ( - this.showMaskTyped && - this.keepCharacterPositions && + this.showMaskTyped() && + this.keepCharacterPositions() && this._maskService.placeHolderCharacter.length === 1 ) { + const suffix = this.suffix(); + const prefix = this.prefix(); const inputSymbol = el.value.slice(position - 1, position); - const prefixLength = this.prefix.length; + const prefixLength = prefix.length; const checkSymbols: boolean = this._maskService._checkSymbolMask( inputSymbol, this._maskService.maskExpression[position - 1 - prefixLength] ?? @@ -470,21 +432,21 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida const selEnd = Number(this._maskService.selEnd) - prefixLength; const backspaceOrDelete = - this._code === MaskExpression.BACKSPACE || - this._code === MaskExpression.DELETE; + this._code() === MaskExpression.BACKSPACE || + this._code() === MaskExpression.DELETE; if (backspaceOrDelete) { if (!selectRangeBackspace) { if (this._maskService.selStart === prefixLength) { - this._maskService.actualValue = `${this.prefix}${this._maskService.maskIsShown.slice(0, selEnd)}${this._inputValue.split(this.prefix).join('')}`; + this._maskService.actualValue = `${prefix}${this._maskService.maskIsShown.slice(0, selEnd)}${this._inputValue().split(prefix).join('')}`; } else if ( this._maskService.selStart === this._maskService.maskIsShown.length + prefixLength ) { - this._maskService.actualValue = `${this._inputValue}${this._maskService.maskIsShown.slice(selStart, selEnd)}`; + this._maskService.actualValue = `${this._inputValue()}${this._maskService.maskIsShown.slice(selStart, selEnd)}`; } else { - this._maskService.actualValue = `${this.prefix}${this._inputValue - .split(this.prefix) + this._maskService.actualValue = `${prefix}${this._inputValue() + .split(prefix) .join('') .slice( 0, @@ -492,23 +454,23 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida )}${this._maskService.maskIsShown.slice(selStart, selEnd)}${this._maskService.actualValue.slice( selEnd + prefixLength, this._maskService.maskIsShown.length + prefixLength - )}${this.suffix}`; + )}${suffix}`; } } else if ( !this._maskService.specialCharacters.includes( this._maskService.maskExpression.slice( - position - this.prefix.length, - position + 1 - this.prefix.length + position - prefixLength, + position + 1 - prefixLength ) ) && selectRangeBackspace ) { - if (selStart === 1 && this.prefix) { - this._maskService.actualValue = `${this.prefix}${this._maskService.placeHolderCharacter}${el.value - .split(this.prefix) + if (selStart === 1 && prefix) { + this._maskService.actualValue = `${prefix}${this._maskService.placeHolderCharacter}${el.value + .split(prefix) .join('') - .split(this.suffix) - .join('')}${this.suffix}`; + .split(suffix) + .join('')}${suffix}`; position = position - 1; } else { @@ -517,7 +479,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida this._maskService.actualValue = `${part1}${this._maskService.placeHolderCharacter}${part2}`; } } - position = this._code === MaskExpression.DELETE ? position + 1 : position; + position = this._code() === MaskExpression.DELETE ? position + 1 : position; } if (!backspaceOrDelete) { if (!checkSymbols && !checkSpecialCharacter && selectRangeBackspace) { @@ -535,18 +497,18 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida position = position + 1; } else if (checkSymbols) { if (el.value.length === 1 && position === 1) { - this._maskService.actualValue = `${this.prefix}${inputSymbol}${this._maskService.maskIsShown.slice( + this._maskService.actualValue = `${prefix}${inputSymbol}${this._maskService.maskIsShown.slice( 1, this._maskService.maskIsShown.length - )}${this.suffix}`; + )}${suffix}`; } else { this._maskService.actualValue = `${el.value.slice(0, position - 1)}${inputSymbol}${el.value .slice(position + 1) - .split(this.suffix) - .join('')}${this.suffix}`; + .split(suffix) + .join('')}${suffix}`; } } else if ( - this.prefix && + prefix && el.value.length === 1 && position - prefixLength === 1 && this._maskService._checkSymbolMask( @@ -555,34 +517,34 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida MaskExpression.EMPTY_STRING ) ) { - this._maskService.actualValue = `${this.prefix}${el.value}${this._maskService.maskIsShown.slice( + this._maskService.actualValue = `${prefix}${el.value}${this._maskService.maskIsShown.slice( 1, this._maskService.maskIsShown.length - )}${this.suffix}`; + )}${suffix}`; } } } let caretShift = 0; let backspaceShift = false; - if (this._code === MaskExpression.DELETE && MaskExpression.SEPARATOR) { + if (this._code() === MaskExpression.DELETE && MaskExpression.SEPARATOR) { this._maskService.deletedSpecialCharacter = true; } if ( - this._inputValue.length >= this._maskService.maskExpression.length - 1 && - this._code !== MaskExpression.BACKSPACE && + this._inputValue().length >= this._maskService.maskExpression.length - 1 && + this._code() !== MaskExpression.BACKSPACE && this._maskService.maskExpression === MaskExpression.DAYS_MONTHS_YEARS && position < 10 ) { - const inputSymbol = this._inputValue.slice(position - 1, position); + const inputSymbol = this._inputValue().slice(position - 1, position); el.value = - this._inputValue.slice(0, position - 1) + + this._inputValue().slice(0, position - 1) + inputSymbol + - this._inputValue.slice(position + 1); + this._inputValue().slice(position + 1); } if ( this._maskService.maskExpression === MaskExpression.DAYS_MONTHS_YEARS && - this.leadZeroDateTime + this.leadZeroDateTime() ) { if ( (position < 3 && Number(el.value) > 31 && Number(el.value) < 40) || @@ -593,9 +555,9 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida } if ( this._maskService.maskExpression === MaskExpression.HOURS_MINUTES_SECONDS && - this.apm + this.apm() ) { - if (this._justPasted && el.value.slice(0, 2) === MaskExpression.DOUBLE_ZERO) { + if (this._justPasted() && el.value.slice(0, 2) === MaskExpression.DOUBLE_ZERO) { el.value = el.value.slice(1, 2) + el.value.slice(2, el.value.length); } el.value = @@ -606,10 +568,11 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida this._maskService.applyValueChanges( position, - this._justPasted, - this._code === MaskExpression.BACKSPACE || this._code === MaskExpression.DELETE, + this._justPasted(), + this._code() === MaskExpression.BACKSPACE || + this._code() === MaskExpression.DELETE, (shift: number, _backspaceShift: boolean) => { - this._justPasted = false; + this._justPasted.set(false); caretShift = shift; backspaceShift = _backspaceShift; } @@ -624,17 +587,17 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida this._maskService.plusOnePosition = false; } // update position after applyValueChanges to prevent cursor on wrong position when it has an array of maskExpression - if (this._maskExpressionArray.length) { - if (this._code === MaskExpression.BACKSPACE) { - const specialChartMinusOne = this.specialCharacters.includes( + if (this._maskExpressionArray().length) { + if (this._code() === MaskExpression.BACKSPACE) { + const specialChartMinusOne = this.specialCharacters().includes( this._maskService.actualValue.slice(position - 1, position) ); - const specialChartPlusOne = this.specialCharacters.includes( + const specialChartPlusOne = this.specialCharacters().includes( this._maskService.actualValue.slice(position, position + 1) ); - if (this._allowFewMaskChangeMask && !specialChartPlusOne) { + if (this._allowFewMaskChangeMask() && !specialChartPlusOne) { position = (el.selectionStart as number) + 1; - this._allowFewMaskChangeMask = false; + this._allowFewMaskChangeMask.set(false); } else { position = specialChartMinusOne ? position - 1 : position; } @@ -645,12 +608,17 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida : (el.selectionStart as number); } } - this._position = - this._position === 1 && this._inputValue.length === 1 ? null : this._position; - let positionToApply: number = this._position - ? this._inputValue.length + position + caretShift + this._position.set( + this._position() === 1 && this._inputValue().length === 1 + ? null + : this._position() + ); + let positionToApply: number = this._position() + ? this._inputValue().length + position + caretShift : position + - (this._code === MaskExpression.BACKSPACE && !backspaceShift ? 0 : caretShift); + (this._code() === MaskExpression.BACKSPACE && !backspaceShift + ? 0 + : caretShift); if (positionToApply > this._getActualInputLength()) { positionToApply = el.value === this._maskService.decimalMarker && el.value.length === 1 @@ -661,7 +629,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida positionToApply = 0; } el.setSelectionRange(positionToApply, positionToApply); - this._position = null; + this._position.set(null); } else { // eslint-disable-next-line no-console console.warn( @@ -670,14 +638,14 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida ); } } else { - if (!this._maskValue) { + if (!this._maskValue()) { this.onChange(el.value); return; } this._maskService.applyValueChanges( el.value.length, - this._justPasted, - this._code === MaskExpression.BACKSPACE || this._code === MaskExpression.DELETE + this._justPasted(), + this._code() === MaskExpression.BACKSPACE || this._code() === MaskExpression.DELETE ); } } @@ -685,20 +653,20 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida // IME starts @HostListener('compositionstart', ['$event']) public onCompositionStart(): void { - this._isComposing = true; + this._isComposing.set(true); } // IME completes @HostListener('compositionend', ['$event']) public onCompositionEnd(e: CustomKeyboardEvent): void { - this._isComposing = false; - this._justPasted = true; + this._isComposing.set(false); + this._justPasted.set(true); this.onInput(e); } @HostListener('blur', ['$event']) public onBlur(e: CustomKeyboardEvent): void { - if (this._maskValue) { + if (this._maskValue()) { const el: HTMLInputElement = e.target as HTMLInputElement; if ( this._maskService.leadZero && @@ -706,6 +674,8 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida typeof this._maskService.decimalMarker === 'string' ) { const maskExpression = this._maskService.maskExpression; + const decimalMarker = this._maskService.decimalMarker as string; + const suffix = this._maskService.suffix; const precision = Number( this._maskService.maskExpression.slice( maskExpression.length - 1, @@ -714,33 +684,29 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida ); if (precision > 0) { - el.value = this._maskService.suffix - ? el.value.split(this._maskService.suffix).join('') - : el.value; - const decimalPart = el.value.split( - this._maskService.decimalMarker - )[1] as string; - - el.value = el.value.includes(this._maskService.decimalMarker) + el.value = suffix ? el.value.split(suffix).join('') : el.value; + const decimalPart = el.value.split(decimalMarker)[1] as string; + + el.value = el.value.includes(decimalMarker) ? el.value + MaskExpression.NUMBER_ZERO.repeat(precision - decimalPart.length) + - this._maskService.suffix + suffix : el.value + - this._maskService.decimalMarker + + decimalMarker + MaskExpression.NUMBER_ZERO.repeat(precision) + - this._maskService.suffix; + suffix; this._maskService.actualValue = el.value; } } this._maskService.clearIfNotMatchFn(); } - this._isFocused = false; + this._isFocused.set(false); this.onTouch(); } @HostListener('click', ['$event']) public onClick(e: MouseEvent | CustomKeyboardEvent): void { - if (!this._maskValue) { + if (!this._maskValue()) { return; } @@ -755,7 +721,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida el.selectionStart > this._maskService.prefix.length && (e as any).keyCode !== 38 ) { - if (this._maskService.showMaskTyped && !this.keepCharacterPositions) { + if (this._maskService.showMaskTyped && !this.keepCharacterPositions()) { // We are showing the mask in the input this._maskService.maskIsShown = this._maskService.showMaskInInput(); if ( @@ -812,11 +778,11 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida @HostListener('keydown', ['$event']) public onKeyDown(e: CustomKeyboardEvent): void { - if (!this._maskValue) { + if (!this._maskValue()) { return; } - if (this._isComposing) { + if (this._isComposing()) { // User finalize their choice from IME composition, so trigger onInput() for the composed text. if (e.key === 'Enter') { this.onCompositionEnd(e); @@ -824,9 +790,9 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida return; } - this._code = e.code ? e.code : e.key; + this._code.set(e.code ? e.code : e.key); const el: HTMLInputElement = e.target as HTMLInputElement; - this._inputValue = el.value; + this._inputValue.set(el.value); this._setMask(); if (el.type !== 'number') { @@ -842,30 +808,29 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida el.selectionStart = el.selectionEnd; } if (e.key === MaskExpression.BACKSPACE && (el.selectionStart as number) !== 0) { + const prefixLength = this.prefix().length; // If specialChars is false, (shouldn't ever happen) then set to the defaults - this.specialCharacters = this.specialCharacters?.length - ? this.specialCharacters + const specialCharacters = this.specialCharacters().length + ? this.specialCharacters() : this._config.specialCharacters; - if ( - this.prefix.length > 1 && - (el.selectionStart as number) <= this.prefix.length - ) { - el.setSelectionRange(this.prefix.length, el.selectionEnd); + + if (prefixLength > 1 && (el.selectionStart as number) <= prefixLength) { + el.setSelectionRange(prefixLength, el.selectionEnd); } else { if ( - this._inputValue.length !== (el.selectionStart as number) && + this._inputValue().length !== (el.selectionStart as number) && (el.selectionStart as number) !== 1 ) { while ( - this.specialCharacters.includes( + specialCharacters.includes( ( - this._inputValue[(el.selectionStart as number) - 1] ?? + this._inputValue()[(el.selectionStart as number) - 1] ?? MaskExpression.EMPTY_STRING ).toString() ) && - ((this.prefix.length >= 1 && - (el.selectionStart as number) > this.prefix.length) || - this.prefix.length === 0) + ((prefixLength >= 1 && + (el.selectionStart as number) > prefixLength) || + prefixLength === 0) ) { el.setSelectionRange( (el.selectionStart as number) - 1, @@ -891,22 +856,24 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida el.selectionEnd === el.value.length && el.value.length !== 0 ) { - this._position = this._maskService.prefix ? this._maskService.prefix.length : 0; + this._position.set( + this._maskService.prefix ? this._maskService.prefix.length : 0 + ); this._maskService.applyMask( this._maskService.prefix, this._maskService.maskExpression, - this._position + this._position() as number ); } } if ( - !!this.suffix && - this.suffix.length > 1 && - this._inputValue.length - this.suffix.length < (el.selectionStart as number) + !!this.suffix() && + this.suffix().length > 1 && + this._inputValue().length - this.suffix().length < (el.selectionStart as number) ) { el.setSelectionRange( - this._inputValue.length - this.suffix.length, - this._inputValue.length + this._inputValue().length - this.suffix().length, + this._inputValue().length ); } else if ( (e.code === 'KeyA' && e.ctrlKey) || @@ -923,6 +890,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida /** It writes the value in the input */ public async writeValue(controlValue: unknown): Promise { let value = controlValue; + const inputTransformFn = this.inputTransformFn(); if (typeof value === 'object' && value !== null && 'value' in value) { if ('disable' in value) { this.setDisabledState(Boolean(value.disable)); @@ -931,7 +899,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida value = value.value; } if (value !== null) { - value = this.inputTransformFn ? this.inputTransformFn(value) : value; + value = inputTransformFn ? inputTransformFn(value) : value; } if ( typeof value === 'string' || @@ -940,14 +908,14 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida typeof value === 'undefined' ) { if (value === null || typeof value === 'undefined' || value === '') { - this._maskService._currentValue = ''; - this._maskService._previousValue = ''; + this._maskService.currentValue = ''; + this._maskService.previousValue = ''; } let inputValue: string | number | null | undefined = value; if ( typeof inputValue === 'number' || - this._maskValue.startsWith(MaskExpression.SEPARATOR) + this._maskValue().startsWith(MaskExpression.SEPARATOR) ) { inputValue = String(inputValue); const localeDecimalMarker = this._maskService.currentLocaleDecimalMarker(); @@ -964,8 +932,8 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida if ( this._maskService.leadZero && inputValue && - this.maskExpression && - this.dropSpecialCharacters !== false + this.mask() && + this.dropSpecialCharacters() !== false ) { inputValue = this._maskService._checkPrecision( this._maskService.maskExpression, @@ -982,7 +950,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida .toString() .replace(MaskExpression.DOT, MaskExpression.COMMA); } - if (this.maskExpression?.startsWith(MaskExpression.SEPARATOR) && this.leadZero) { + if (this.mask()?.startsWith(MaskExpression.SEPARATOR) && this.leadZero()) { requestAnimationFrame(() => { this._maskService.applyMask( inputValue?.toString() ?? '', @@ -997,7 +965,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida inputValue = ''; } - this._inputValue = inputValue; + this._inputValue.set(inputValue); this._setMask(); if ( @@ -1006,7 +974,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida (this._maskService.prefix || this._maskService.showMaskTyped)) ) { // Let the service we know we are writing value so that triggering onChange function won't happen during applyMask - if (typeof this.inputTransformFn !== 'function') { + if (typeof inputTransformFn !== 'function') { this._maskService.writingValue = true; } @@ -1015,13 +983,13 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida this._maskService.applyMask(inputValue, this._maskService.maskExpression), ]; // Let the service know we've finished writing value - if (typeof this.inputTransformFn !== 'function') { + if (typeof inputTransformFn !== 'function') { this._maskService.writingValue = false; } } else { this._maskService.formElementProperty = ['value', inputValue]; } - this._inputValue = inputValue; + this._inputValue.set(inputValue); } else { // eslint-disable-next-line no-console console.warn( @@ -1049,13 +1017,17 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida } public checkSelectionOnDeletion(el: HTMLInputElement): void { + const prefixLength = this.prefix().length; + const suffixLength = this.suffix().length; + const inputValueLength = this._inputValue().length; + el.selectionStart = Math.min( - Math.max(this.prefix.length, el.selectionStart as number), - this._inputValue.length - this.suffix.length + Math.max(prefixLength, el.selectionStart as number), + inputValueLength - suffixLength ); el.selectionEnd = Math.min( - Math.max(this.prefix.length, el.selectionEnd as number), - this._inputValue.length - this.suffix.length + Math.max(prefixLength, el.selectionEnd as number), + inputValueLength - suffixLength ); } @@ -1066,16 +1038,16 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida private _applyMask(): any { this._maskService.maskExpression = this._maskService._repeatPatternSymbols( - this._maskValue || '' + this._maskValue() || '' ); this._maskService.formElementProperty = [ 'value', - this._maskService.applyMask(this._inputValue, this._maskService.maskExpression), + this._maskService.applyMask(this._inputValue(), this._maskService.maskExpression), ]; } private _validateTime(value: string): ValidationErrors | null { - const rowMaskLen: number = this._maskValue + const rowMaskLen: number = this._maskValue() .split(MaskExpression.EMPTY_STRING) .filter((s: string) => s !== ':').length; if (!value) { @@ -1102,61 +1074,60 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida private _createValidationError(actualValue: string): ValidationErrors { return { mask: { - requiredMask: this._maskValue, + requiredMask: this._maskValue(), actualValue, }, }; } private _setMask() { - this._maskExpressionArray.some((mask): boolean | void => { + this._maskExpressionArray().some((mask): boolean | void => { const specialChart: boolean = mask .split(MaskExpression.EMPTY_STRING) .some((char) => this._maskService.specialCharacters.includes(char)); - if ( (specialChart && - this._inputValue && - this._areAllCharactersInEachStringSame(this._maskExpressionArray)) || + this._inputValue() && + this._areAllCharactersInEachStringSame(this._maskExpressionArray())) || mask.includes(MaskExpression.CURLY_BRACKETS_LEFT) ) { const test = - this._maskService.removeMask(this._inputValue)?.length <= + this._maskService.removeMask(this._inputValue())?.length <= this._maskService.removeMask(mask)?.length; if (test) { - this._maskValue = - this.maskExpression = - this._maskService.maskExpression = - mask.includes(MaskExpression.CURLY_BRACKETS_LEFT) - ? this._maskService._repeatPatternSymbols(mask) - : mask; + const maskValue = mask.includes(MaskExpression.CURLY_BRACKETS_LEFT) + ? this._maskService._repeatPatternSymbols(mask) + : mask; + this._maskValue.set(maskValue); + this._maskService.maskExpression = maskValue; return test; } else { - if (this._code === MaskExpression.BACKSPACE) { - this._allowFewMaskChangeMask = true; + if (this._code() === MaskExpression.BACKSPACE) { + this._allowFewMaskChangeMask.set(true); } const expression = - this._maskExpressionArray[this._maskExpressionArray.length - 1] ?? + this._maskExpressionArray()[this._maskExpressionArray().length - 1] ?? MaskExpression.EMPTY_STRING; - this._maskValue = - this.maskExpression = - this._maskService.maskExpression = - expression.includes(MaskExpression.CURLY_BRACKETS_LEFT) - ? this._maskService._repeatPatternSymbols(expression) - : expression; + + const maskValue = expression.includes(MaskExpression.CURLY_BRACKETS_LEFT) + ? this._maskService._repeatPatternSymbols(expression) + : expression; + this._maskValue.set(maskValue); + this._maskService.maskExpression = maskValue; } } else { const check: boolean = this._maskService - .removeMask(this._inputValue) + .removeMask(this._inputValue()) ?.split(MaskExpression.EMPTY_STRING) .every((character, index) => { const indexMask = mask.charAt(index); return this._maskService._checkSymbolMask(character, indexMask); }); - if (check || this._justPasted) { - this._maskValue = this.maskExpression = this._maskService.maskExpression = mask; + if (check || this._justPasted()) { + this._maskValue.set(mask); + this._maskService.maskExpression = mask; return check; } } @@ -1165,6 +1136,7 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida private _areAllCharactersInEachStringSame(array: string[]): boolean { const specialCharacters = this._maskService.specialCharacters; + function removeSpecialCharacters(str: string): string { const regex = new RegExp(`[${specialCharacters.map((ch) => `\\${ch}`).join('')}]`, 'g'); return str.replace(regex, ''); diff --git a/projects/ngx-mask-lib/src/lib/ngx-mask.pipe.ts b/projects/ngx-mask-lib/src/lib/ngx-mask.pipe.ts index 0e141dc5..010f3e59 100644 --- a/projects/ngx-mask-lib/src/lib/ngx-mask.pipe.ts +++ b/projects/ngx-mask-lib/src/lib/ngx-mask.pipe.ts @@ -1,5 +1,5 @@ import type { PipeTransform } from '@angular/core'; -import { inject, Pipe } from '@angular/core'; +import { inject, Pipe, signal } from '@angular/core'; import type { NgxMaskConfig } from './ngx-mask.config'; import { NGX_MASK_CONFIG } from './ngx-mask.config'; @@ -16,9 +16,8 @@ export class NgxMaskPipe implements PipeTransform { private readonly _maskService = inject(NgxMaskService); - private _maskExpressionArray: string[] = []; - - private mask = ''; + private _maskExpressionArray = signal([]); + private _mask = signal(''); public transform( value: string | number, @@ -44,14 +43,14 @@ export class NgxMaskPipe implements PipeTransform { if (mask.includes('||')) { const maskParts = mask.split('||'); if (maskParts.length > 1) { - this._maskExpressionArray = maskParts.sort( - (a: string, b: string) => a.length - b.length + this._maskExpressionArray.set( + maskParts.sort((a: string, b: string) => a.length - b.length) ); this._setMask(processedValue as string); - return this._maskService.applyMask(`${processedValue}`, this.mask); + return this._maskService.applyMask(`${processedValue}`, this._mask()); } else { - this._maskExpressionArray = []; - return this._maskService.applyMask(`${processedValue}`, this.mask); + this._maskExpressionArray.set([]); + return this._maskService.applyMask(`${processedValue}`, this._mask()); } } @@ -112,19 +111,19 @@ export class NgxMaskPipe implements PipeTransform { } private _setMask(value: string) { - if (this._maskExpressionArray.length > 0) { - this._maskExpressionArray.some((mask): boolean | void => { + if (this._maskExpressionArray().length > 0) { + this._maskExpressionArray().some((mask): boolean | void => { const test = this._maskService.removeMask(value)?.length <= this._maskService.removeMask(mask)?.length; if (value && test) { - this.mask = mask; + this._mask.set(mask); return test; } else { const expression = - this._maskExpressionArray[this._maskExpressionArray.length - 1] ?? + this._maskExpressionArray()[this._maskExpressionArray.length - 1] ?? MaskExpression.EMPTY_STRING; - this.mask = expression; + this._mask.set(expression); } }); } diff --git a/projects/ngx-mask-lib/src/lib/ngx-mask.service.ts b/projects/ngx-mask-lib/src/lib/ngx-mask.service.ts index 2dcad3cf..307e8d49 100644 --- a/projects/ngx-mask-lib/src/lib/ngx-mask.service.ts +++ b/projects/ngx-mask-lib/src/lib/ngx-mask.service.ts @@ -9,32 +9,22 @@ import { MaskExpression } from './ngx-mask-expression.enum'; @Injectable() export class NgxMaskService extends NgxMaskApplierService { public isNumberValue = false; - public maskIsShown = ''; - public selStart: number | null = null; - public selEnd: number | null = null; - + public maskChanged = false; + public maskExpressionArray: string[] = []; + public triggerOnMaskChange = false; + public previousValue = ''; + public currentValue = ''; /** * Whether we are currently in writeValue function, in this case when applying the mask we don't want to trigger onChange function, * since writeValue should be a one way only process of writing the DOM value based on the Angular model value. */ public writingValue = false; - public maskChanged = false; - public _maskExpressionArray: string[] = []; - - public triggerOnMaskChange = false; - - public _previousValue = ''; - - public _currentValue = ''; - private _emitValue = false; - private _start!: number; - private _end!: number; // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -123,7 +113,7 @@ export class NgxMaskService extends NgxMaskApplierService { this.showMaskTyped && !this.prefix ) { - newInputValue = this._currentValue; + newInputValue = this.currentValue; } if (this.deletedSpecialCharacter && newPosition) { if ( @@ -201,13 +191,13 @@ export class NgxMaskService extends NgxMaskApplierService { } if (result || result === '') { - this._previousValue = this._currentValue; - this._currentValue = result; + this.previousValue = this.currentValue; + this.currentValue = result; this._emitValue = - this._previousValue !== this._currentValue || + this.previousValue !== this.currentValue || this.maskChanged || this.writingValue || - (this._previousValue === this._currentValue && justPasted); + (this.previousValue === this.currentValue && justPasted); } // eslint-disable-next-line no-unused-expressions,@typescript-eslint/no-unused-expressions diff --git a/projects/ngx-mask-lib/src/test/add-prefix.spec.ts b/projects/ngx-mask-lib/src/test/add-prefix.spec.ts index 21b198c2..6a277d6f 100644 --- a/projects/ngx-mask-lib/src/test/add-prefix.spec.ts +++ b/projects/ngx-mask-lib/src/test/add-prefix.spec.ts @@ -3,8 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Add prefix)', () => { let fixture: ComponentFixture; @@ -21,13 +20,13 @@ describe('Directive: Mask (Add prefix)', () => { }); it('should have a prefix', () => { - component.mask = '00-000-000-00'; - component.prefix = '+7 '; + component.mask.set('00-000-000-00'); + component.prefix.set('+7 '); equal('6', '+7 6', fixture); - component.mask = '(00) 0000-0000||(00) 0 0000-0000'; - component.prefix = '+55 '; - component.showMaskTyped = true; + component.mask.set('(00) 0000-0000||(00) 0 0000-0000'); + component.prefix.set('+55 '); + component.showMaskTyped.set(true); equal('1', '+55 (1_) ____-____', fixture); equal('12', '+55 (12) ____-____', fixture); equal('123', '+55 (12) 3___-____', fixture); @@ -53,23 +52,23 @@ describe('Directive: Mask (Add prefix)', () => { equal('+55 (12) 3 4567-8901', '+55 (12) 3 4567-8901', fixture); }); it('dropSpecialCharacters false should return value with prefix', () => { - component.mask = '00-000-000-00'; - component.dropSpecialCharacters = false; - component.prefix = '+7 '; + component.mask.set('00-000-000-00'); + component.dropSpecialCharacters.set(false); + component.prefix.set('+7 '); equal('097', '+7 09-7', fixture); expect(component.form.value).toEqual('+7 09-7'); }); it('dropSpecialCharacters false should return value with suffix', () => { - component.mask = '00'; - component.dropSpecialCharacters = false; - component.suffix = '$'; + component.mask.set('00'); + component.dropSpecialCharacters.set(false); + component.suffix.set('$'); equal('97', '97$', fixture); expect(component.form.value).toEqual('97$'); }); it('should delete prefix in pasted content', () => { - component.mask = 'AAA-AAA-AAA'; - component.prefix = 'FOO-'; + component.mask.set('AAA-AAA-AAA'); + component.prefix.set('FOO-'); equal('FOO-D', 'FOO-D', fixture); equal('FOO-DD', 'FOO-DD', fixture); equal('FOO-DDD', 'FOO-DDD', fixture); @@ -83,9 +82,9 @@ describe('Directive: Mask (Add prefix)', () => { }); it('should delete prefix in pasted content', () => { - component.mask = 'AAA-AAA-AAA'; - component.prefix = 'FOO-'; - component.dropSpecialCharacters = false; + component.mask.set('AAA-AAA-AAA'); + component.prefix.set('FOO-'); + component.dropSpecialCharacters.set(false); equal('FOO-S', 'FOO-S', fixture); equal('FOO-SS', 'FOO-SS', fixture); equal('FOO-SSS', 'FOO-SSS', fixture); @@ -99,9 +98,9 @@ describe('Directive: Mask (Add prefix)', () => { }); it('should replace $ with minus', () => { - component.mask = '0000.00'; - component.prefix = '$'; - component.allowNegativeNumbers = true; + component.mask.set('0000.00'); + component.prefix.set('$'); + component.allowNegativeNumbers.set(true); equal('-1', '-$1', fixture); equal('-12', '-$12', fixture); equal('-123', '-$123', fixture); @@ -111,9 +110,9 @@ describe('Directive: Mask (Add prefix)', () => { }); it('should replace euro with minus', () => { - component.mask = '0000.00'; - component.prefix = '€'; - component.allowNegativeNumbers = true; + component.mask.set('0000.00'); + component.prefix.set('€'); + component.allowNegativeNumbers.set(true); equal('-1', '-€1', fixture); equal('-12', '-€12', fixture); equal('-123', '-€123', fixture); @@ -123,20 +122,20 @@ describe('Directive: Mask (Add prefix)', () => { }); it('should remove prefix when setValue triggerOnMaskChange = true', () => { - component.mask = '000 000'; - component.prefix = 'KZ'; - component.dropSpecialCharacters = true; - component.triggerOnMaskChange = true; + component.mask.set('000 000'); + component.prefix.set('KZ'); + component.dropSpecialCharacters.set(true); + component.triggerOnMaskChange.set(true); component.form.setValue('KZ123123'); equal('KZ123123', 'KZ123 123', fixture); expect(component.form.value).toBe('123123'); }); it('should remove prefix when setValue triggerOnMaskChange =true', () => { - component.mask = '000 000'; - component.prefix = 'KZ'; - component.dropSpecialCharacters = false; - component.triggerOnMaskChange = true; + component.mask.set('000 000'); + component.prefix.set('KZ'); + component.dropSpecialCharacters.set(false); + component.triggerOnMaskChange.set(true); component.form.setValue('KZ123123'); equal('KZ123123', 'KZ123 123', fixture); @@ -144,18 +143,18 @@ describe('Directive: Mask (Add prefix)', () => { }); it('should remove prefix when setValue triggerOnMaskChange = false', () => { - component.mask = '000 000'; - component.prefix = 'KZ'; - component.dropSpecialCharacters = true; + component.mask.set('000 000'); + component.prefix.set('KZ'); + component.dropSpecialCharacters.set(true); component.form.setValue('KZ123123'); equal('KZ123123', 'KZ123 123', fixture); expect(component.form.value).toBe('KZ123123'); }); it('should remove prefix when setValue triggerOnMaskChange = false', () => { - component.mask = '000 000'; - component.prefix = 'KZ'; - component.dropSpecialCharacters = false; + component.mask.set('000 000'); + component.prefix.set('KZ'); + component.dropSpecialCharacters.set(false); component.form.setValue('KZ123123'); equal('KZ123123', 'KZ123 123', fixture); expect(component.form.value).toBe('KZ123123'); diff --git a/projects/ngx-mask-lib/src/test/add-suffix.spec.ts b/projects/ngx-mask-lib/src/test/add-suffix.spec.ts index 1a3095b9..26b32891 100644 --- a/projects/ngx-mask-lib/src/test/add-suffix.spec.ts +++ b/projects/ngx-mask-lib/src/test/add-suffix.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Add suffix)', () => { let fixture: ComponentFixture; @@ -22,27 +21,27 @@ describe('Directive: Mask (Add suffix)', () => { }); it('should have a suffix', () => { - component.mask = '00-000-000-00'; - component.suffix = '$'; + component.mask.set('00-000-000-00'); + component.suffix.set('$'); equal('6', '6$', fixture); }); it('should have a suffix if first letter entered is y', () => { - component.mask = 'L{80}'; - component.suffix = '.sh'; + component.mask.set('L{80}'); + component.suffix.set('.sh'); equal('y', 'y.sh', fixture); }); it('should have a suffix if the first character entered same as the last letter of the suffix', () => { - component.mask = 'L{80}'; - component.suffix = '.sh'; + component.mask.set('L{80}'); + component.suffix.set('.sh'); equal('h', 'h.sh', fixture); }); it('should display suffix at the end with showMaskTyped mask 0 000', () => { - component.mask = '0 000'; - component.suffix = '$'; - component.showMaskTyped = true; + component.mask.set('0 000'); + component.suffix.set('$'); + component.showMaskTyped.set(true); equal('1', '1 ___$', fixture); equal('12', '1 2__$', fixture); equal('123', '1 23_$', fixture); diff --git a/projects/ngx-mask-lib/src/test/allow-negative-numbers.spec.ts b/projects/ngx-mask-lib/src/test/allow-negative-numbers.spec.ts index 335845e6..5eb8bf00 100644 --- a/projects/ngx-mask-lib/src/test/allow-negative-numbers.spec.ts +++ b/projects/ngx-mask-lib/src/test/allow-negative-numbers.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Allow negative numbers)', () => { let fixture: ComponentFixture; @@ -22,10 +21,10 @@ describe('Directive: Mask (Allow negative numbers)', () => { }); it('FormControl or NgModel should not allow negative numbers (default functionality)', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; - component.allowNegativeNumbers = false; - component.dropSpecialCharacters = true; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); + component.allowNegativeNumbers.set(false); + component.dropSpecialCharacters.set(true); equal('-10,000.00', '10,000.00', fixture); expect(component.form.value).toBe('10000.00'); @@ -36,10 +35,10 @@ describe('Directive: Mask (Allow negative numbers)', () => { }); it('FormControl and NgModel should be filled with negative values', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; - component.allowNegativeNumbers = true; - component.dropSpecialCharacters = true; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); + component.allowNegativeNumbers.set(true); + component.dropSpecialCharacters.set(true); component.form.setValue(-123456); equal('-123456.00', '-123,456.00', fixture); @@ -47,16 +46,16 @@ describe('Directive: Mask (Allow negative numbers)', () => { }); it('allowNegativeNumber to mask', () => { - component.mask = '000.00'; - component.allowNegativeNumbers = true; + component.mask.set('000.00'); + component.allowNegativeNumbers.set(true); equal('-123.00', '-123.00', fixture); equal('-311.9', '-311.9', fixture); equal('-311', '-311', fixture); equal('123.00', '123.00', fixture); - component.mask = '0000'; - component.allowNegativeNumbers = true; + component.mask.set('0000'); + component.allowNegativeNumbers.set(true); equal('-1230', '-1230', fixture); equal('-3119', '-3119', fixture); @@ -67,16 +66,16 @@ describe('Directive: Mask (Allow negative numbers)', () => { }); it('allowNegativeNumber to percent', () => { - component.mask = 'percent'; - component.allowNegativeNumbers = true; + component.mask.set('percent'); + component.allowNegativeNumbers.set(true); equal('-101', '-10', fixture); equal('-100', '-100', fixture); equal('-999', '-99', fixture); equal('-20', '-20', fixture); - component.mask = 'percent.2'; - component.allowNegativeNumbers = true; + component.mask.set('percent.2'); + component.allowNegativeNumbers.set(true); equal('-100.00', '-100.00', fixture); equal('-100.02', '-100.0', fixture); @@ -85,8 +84,8 @@ describe('Directive: Mask (Allow negative numbers)', () => { equal('-11.11', '-11.11', fixture); equal('-12.30', '-12.30', fixture); - component.mask = 'percent.3'; - component.allowNegativeNumbers = true; + component.mask.set('percent.3'); + component.allowNegativeNumbers.set(true); equal('-100.000', '-100.000', fixture); equal('-99.001', '-99.001', fixture); @@ -97,16 +96,16 @@ describe('Directive: Mask (Allow negative numbers)', () => { }); it('allowNegativeNumber to separator', () => { - component.mask = 'separator'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.allowNegativeNumbers.set(true); equal('-101', '-101', fixture); equal('-100', '-100', fixture); equal('-999', '-999', fixture); equal('-3000', '-3 000', fixture); - component.mask = 'separator.2'; - component.allowNegativeNumbers = true; + component.mask.set('separator.2'); + component.allowNegativeNumbers.set(true); equal('-100.00', '-100.00', fixture); equal('-100.02', '-100.02', fixture); @@ -115,8 +114,8 @@ describe('Directive: Mask (Allow negative numbers)', () => { equal('-91.11', '-91.11', fixture); equal('-1112.30', '-1 112.30', fixture); - component.mask = 'separator.3'; - component.allowNegativeNumbers = true; + component.mask.set('separator.3'); + component.allowNegativeNumbers.set(true); equal('-100.000', '-100.000', fixture); equal('-99.001', '-99.001', fixture); diff --git a/projects/ngx-mask-lib/src/test/basic-logic.spec.ts b/projects/ngx-mask-lib/src/test/basic-logic.spec.ts index 667d8f3c..b916c348 100644 --- a/projects/ngx-mask-lib/src/test/basic-logic.spec.ts +++ b/projects/ngx-mask-lib/src/test/basic-logic.spec.ts @@ -6,8 +6,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal, typeTest } from './utils/test-functions.component'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; +import { provideNgxMask, NgxMaskDirective } from 'ngx-mask'; describe('Directive: Mask', () => { let fixture: ComponentFixture; @@ -24,7 +23,7 @@ describe('Directive: Mask', () => { }); it('Pristine and dirty', () => { - component.mask = '0000.0000'; + component.mask.set('0000.0000'); expect(component.form.dirty).toBeFalsy(); expect(component.form.pristine).toBeTruthy(); equal('1.', '1', fixture); @@ -38,19 +37,19 @@ describe('Directive: Mask', () => { }); it('When I change the mask on-the-fly things should work normally', () => { - component.mask = '0000.0000'; + component.mask.set('0000.0000'); equal('1.', '1', fixture); equal('1éáa2aaaaqwo', '12', fixture); equal('1234567', '1234.567', fixture); - component.mask = '0.000.000'; + component.mask.set('0.000.000'); equal('1.', '1.', fixture); equal('1éáa2aaaaqwo', '1.2', fixture); equal('1234567', '1.234.567', fixture); }); it('More tests', () => { - component.mask = '0.00'; + component.mask.set('0.00'); equal('1', '1', fixture); equal('12', '1.2', fixture); equal('123', '1.23', fixture); @@ -60,7 +59,7 @@ describe('Directive: Mask', () => { equal('1234567', '1.23', fixture); equal('12345678', '1.23', fixture); - component.mask = '0000.0000'; + component.mask.set('0000.0000'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -72,7 +71,7 @@ describe('Directive: Mask', () => { }); it('When I typed a char thats the same as the mask char', () => { - component.mask = '00/00/0000'; + component.mask.set('00/00/0000'); equal('00/', '00/', fixture); equal('00a', '00/', fixture); equal('00a00/00', '00/00/00', fixture); @@ -81,7 +80,7 @@ describe('Directive: Mask', () => { }); it('When I typed exactly the same as the mask', () => { - component.mask = '00/00/0000'; + component.mask.set('00/00/0000'); equal('00', '00', fixture); equal('00/', '00/', fixture); equal('aa/', '', fixture); @@ -92,12 +91,12 @@ describe('Directive: Mask', () => { }); it('Testing masks with a literal on the last char', () => { - component.mask = '(99)'; + component.mask.set('(99)'); equal('99', '(99)', fixture); }); it('Masks with numbers and special characters.', () => { - component.mask = '(000) 000-0000'; + component.mask.set('(000) 000-0000'); equal('1', '(1', fixture); equal('12', '(12', fixture); equal('123', '(123', fixture); @@ -108,7 +107,7 @@ describe('Directive: Mask', () => { }); it('Masks with numbers, strings e special characters', () => { - component.mask = '(099) A99-SSSS'; + component.mask.set('(099) A99-SSSS'); equal('as', '(', fixture); equal('(1', '(1', fixture); equal('(12', '(12', fixture); @@ -127,14 +126,14 @@ describe('Directive: Mask', () => { }); describe('Masks with ip', () => { it('should correct', () => { - component.mask = 'IP'; + component.mask.set('IP'); equal('1.1.1.1', '1.1.1.1', fixture); equal('12.1.12.1', '12.1.12.1', fixture); equal('127.001.1.1', '127.001.1.1', fixture); equal('192.168.1.78', '192.168.1.78', fixture); }); it('form should be invalid', () => { - component.mask = 'IP'; + component.mask.set('IP'); equal('192.168.1.78', '192.168.1.78', fixture); expect(component.form.valid).toBeTrue(); equal('127.001.1.1', '127.001.1.1', fixture); @@ -145,7 +144,7 @@ describe('Directive: Mask', () => { expect(component.form.valid).toBeTrue(); }); it('form should be valid', () => { - component.mask = 'IP'; + component.mask.set('IP'); equal('1.1.1.', '1.1.1.', fixture); expect(component.form.valid).toBeFalse(); equal('12.1.12', '12.1.12', fixture); @@ -168,7 +167,7 @@ describe('Directive: Mask', () => { }); it('Masks with cpf', () => { - component.mask = '000.000.000-00'; + component.mask.set('000.000.000-00'); equal('', '', fixture); equal('1', '1', fixture); equal('12', '12', fixture); @@ -192,7 +191,7 @@ describe('Directive: Mask', () => { }); it('Masks with cnpj', () => { - component.mask = '00.000.000/0000-00'; + component.mask.set('00.000.000/0000-00'); equal('', '', fixture); equal('1', '1', fixture); equal('12', '12', fixture); @@ -223,7 +222,7 @@ describe('Directive: Mask', () => { }); it('Masks with CPF_CNPJ', () => { - component.mask = 'CPF_CNPJ'; + component.mask.set('CPF_CNPJ'); equal('', '', fixture); equal('1', '1', fixture); equal('12', '12', fixture); @@ -253,7 +252,7 @@ describe('Directive: Mask', () => { }); it('Dynamic Masks CPF_CNPJ', () => { - component.mask = '000.000.000-00||00.000.000/0000-00'; + component.mask.set('000.000.000-00||00.000.000/0000-00'); equal('', '', fixture); equal('1', '1', fixture); equal('12', '12', fixture); @@ -283,7 +282,7 @@ describe('Directive: Mask', () => { }); it('Dynamic Masks PHONE_BR', () => { - component.mask = '(00) 0000-0000||(00) 0 0000-0000'; + component.mask.set('(00) 0000-0000||(00) 0 0000-0000'); equal('', '', fixture); equal('1', '(1', fixture); equal('12', '(12', fixture); @@ -313,7 +312,7 @@ describe('Directive: Mask', () => { }); it('Mask with optional numbers and 2 decimals', () => { - component.mask = '9999.00'; + component.mask.set('9999.00'); equal('.', '.', fixture); equal('1.23', '1.23', fixture); equal('.23', '.23', fixture); @@ -326,7 +325,7 @@ describe('Directive: Mask', () => { }); it('Masks with numbers, strings e special characters #2 ', () => { - component.mask = 'AAA 000-S0S'; + component.mask.set('AAA 000-S0S'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -337,21 +336,21 @@ describe('Directive: Mask', () => { }); it('should strip special characters from form control value', () => { - component.mask = '00/00/0000'; + component.mask.set('00/00/0000'); typeTest('30/08/19921', fixture); expect(component.form.value).toBe('30081992'); }); it('model values shouldnt be bigger length than masks', () => { - component.mask = '00-00-00'; - component.dropSpecialCharacters = false; + component.mask.set('00-00-00'); + component.dropSpecialCharacters.set(false); equal('2578989', '25-78-98', fixture); expect(component.form.value).toBe('25-78-98'); }); it('should work with custom special characters', () => { - component.mask = '[000]-[000]*[00]'; - component.specialCharacters = ['[', ']', '-', '*']; + component.mask.set('[000]-[000]*[00]'); + component.specialCharacters.set(['[', ']', '-', '*']); equal('', '', fixture); equal('2578989', '[257]-[898]*[9', fixture); equal('2578989888988', '[257]-[898]*[98]', fixture); @@ -359,56 +358,56 @@ describe('Directive: Mask', () => { }); it('should work with custom patterns', () => { - component.mask = '[000]-[000]*[00]'; - component.specialCharacters = ['[', ']', '-', '*']; - component.patterns = { + component.mask.set('[000]-[000]*[00]'); + component.specialCharacters.set(['[', ']', '-', '*']); + component.patterns.set({ '0': { pattern: new RegExp('[a-zA-Z]'), }, - }; + }); equal('', '', fixture); equal('2578989', '[', fixture); equal('hello world', '[hel]-[low]*[or]', fixture); equal('111.111-11', '[', fixture); - component.mask = '(000-000)'; - component.specialCharacters = ['(', '-', ')']; + component.mask.set('(000-000)'); + component.specialCharacters.set(['(', '-', ')']); equal('323HelloWorld', '(Hel-loW)', fixture); - component.mask = '[00]*[000]'; - component.specialCharacters = ['[', ']', '*']; - component.patterns = { + component.mask.set('[00]*[000]'); + component.specialCharacters.set(['[', ']', '*']); + component.patterns.set({ '0': { pattern: new RegExp('\\d'), }, - }; + }); equal('789-874.98', '[78]*[987]', fixture); }); it('When I change the mask on-the-fly things should work normally', () => { - component.mask = '0000.0000'; + component.mask.set('0000.0000'); equal('1.', '1', fixture); equal('1éáa2aaaaqwo', '12', fixture); equal('1234567', '1234.567', fixture); - component.mask = '0.000.000'; + component.mask.set('0.000.000'); equal('1.', '1.', fixture); equal('1éáa2aaaaqwo', '1.2', fixture); equal('1234567', '1.234.567', fixture); - component.mask = ''; + component.mask.set(''); equal('1.', '1.', fixture); equal('1éáa2aaaaqwo', '1éáa2aaaaqwo', fixture); equal('1234567', '1234567', fixture); - component.mask = '0000.0000'; + component.mask.set('0000.0000'); equal('1.', '1', fixture); equal('1éáa2aaaaqwo', '12', fixture); equal('1234567', '1234.567', fixture); }); it('should work even has no mask', () => { - component.mask = ''; + component.mask.set(''); equal('1234567', '1234567', fixture); @@ -416,22 +415,22 @@ describe('Directive: Mask', () => { }); it('should be a UA phone', () => { - component.mask = '000-00-00-00-000'; + component.mask.set('000-00-00-00-000'); equal('380975577234', '380-97-55-77-234', fixture); }); it('should be a pasport number', () => { - component.mask = 'AA 000000'; + component.mask.set('AA 000000'); equal('GH 234098', 'GH 234098', fixture); }); it('should be bank card number', () => { - component.mask = '0000-0000-0000-0000'; + component.mask.set('0000-0000-0000-0000'); equal('1234567890123456', '1234-5678-9012-3456', fixture); }); it('should apply mask on backspace for non readonly inputs when all text is selected', () => { - component.mask = 'AAAAAA'; + component.mask.set('AAAAAA'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -455,7 +454,7 @@ describe('Directive: Mask', () => { }); it('should not apply mask on backspace for readonly inputs when all text is selected', () => { - component.mask = 'AAAAAA'; + component.mask.set('AAAAAA'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -478,7 +477,7 @@ describe('Directive: Mask', () => { }); it('should right work with {value, disable}', () => { - component.mask = '000'; + component.mask.set('000'); fixture.detectChanges(); component.form.setValue({ value: 123, @@ -492,7 +491,7 @@ describe('Directive: Mask', () => { }); it('should return empty string if input consist only special symbols', () => { - component.mask = '(000) 000-00-00'; + component.mask.set('(000) 000-00-00'); fixture.detectChanges(); equal('0', '(0', fixture); equal('(', '(', fixture); @@ -507,17 +506,17 @@ describe('Directive: Mask', () => { }); it('should remove ghost character on toggling mask', () => { - component.mask = '0000'; - component.triggerOnMaskChange = true; + component.mask.set('0000'); + component.triggerOnMaskChange.set(true); component.form.setValue('1111a'); equal('1111a', '1111', fixture); expect(component.form.value).toBe('1111'); - component.mask = null; + component.mask.set(null); expect(component.form.value).toBe('1111'); }); it('Masks with letters uppercase', () => { - component.mask = 'UUUU'; + component.mask.set('UUUU'); fixture.detectChanges(); equal('A', 'A', fixture); equal('AB', 'AB', fixture); @@ -526,7 +525,7 @@ describe('Directive: Mask', () => { }); it('Masks with letters lowercase', () => { - component.mask = 'LLLL'; + component.mask.set('LLLL'); fixture.detectChanges(); equal('a', 'a', fixture); equal('ab', 'ab', fixture); @@ -534,14 +533,14 @@ describe('Directive: Mask', () => { equal('abcd', 'abcd', fixture); }); it('0.0000004 after writeValue should be 0.0000004', () => { - component.mask = 'separator.7'; + component.mask.set('separator.7'); fixture.detectChanges(); component.form.setValue(0.0000004); equal('0.0000004', '0.0000004', fixture); expect(component.form.value).toBe(0.0000004); }); it('mask 0000 0000 0000 9999 9999', () => { - component.mask = '0000 0000 0000 9999 9999'; + component.mask.set('0000 0000 0000 9999 9999'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -565,7 +564,7 @@ describe('Directive: Mask', () => { equal('1234 5678 9012 3456', '1234 5678 9012 3456', fixture); }); it('mask SS00 AAAA 0000 0000 0000 0000 9999 9999 99', () => { - component.mask = 'SS00 AAAA 0000 0000 0000 0000 9999 9999 99'; + component.mask.set('SS00 AAAA 0000 0000 0000 0000 9999 9999 99'); equal( 'FR12345678901234567890123456789012', 'FR12 3456 7890 1234 5678 9012 3456 7890 12', @@ -579,7 +578,7 @@ describe('Directive: Mask', () => { }); it('Mask with optional parameter', () => { - component.mask = '9999 999 999'; + component.mask.set('9999 999 999'); equal('3', '3', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -593,7 +592,7 @@ describe('Directive: Mask', () => { }); it('Mask 099.09', () => { - component.mask = '099.09'; + component.mask.set('099.09'); equal('1.23', '1.23', fixture); equal('1', '1', fixture); equal('12', '12', fixture); @@ -607,7 +606,7 @@ describe('Directive: Mask', () => { }); it('Mask 09/09/0099', () => { - component.mask = '09/09/0099'; + component.mask.set('09/09/0099'); equal('1123', '11/23', fixture); equal('1/2', '1/2', fixture); equal('12/2/2020', '12/2/2020', fixture); @@ -621,16 +620,16 @@ describe('Directive: Mask', () => { }); it('Mask 099.00099999999999', () => { - component.mask = '099.00099999999999'; + component.mask.set('099.00099999999999'); equal('1.2222222', '1.2222222', fixture); equal('111111111111', '111.111111111', fixture); equal('11.11111111111', '11.11111111111', fixture); }); it('dropSpecialCharacter should return prefix or delete it value', () => { - component.mask = '0000'; - component.prefix = 'foo/'; - component.dropSpecialCharacters = false; + component.mask.set('0000'); + component.prefix.set('foo/'); + component.dropSpecialCharacters.set(false); equal('2574', 'foo/2574', fixture); expect(component.form.value).toBe('foo/2574'); expect(component.form.valid).toBeTruthy(); @@ -652,8 +651,8 @@ describe('Directive: Mask', () => { }); it('Should be not valid if length of input doesnt match mask', () => { - component.mask = '000 000-00-00'; - component.prefix = '+7 '; + component.mask.set('000 000-00-00'); + component.prefix.set('+7 '); equal('2', '+7 2', fixture); expect(component.form.value).toBe('2'); expect(component.form.valid).toBeFalse(); @@ -695,14 +694,14 @@ describe('Directive: Mask', () => { }); it('Mask 0/9', () => { - component.mask = '0/9'; + component.mask.set('0/9'); equal('1', '1', fixture); equal('1/', '1/', fixture); equal('1/2', '1/2', fixture); }); it('Mask 9*/0*', () => { - component.mask = '9*/0*'; + component.mask.set('9*/0*'); equal('1', '1', fixture); equal('1/', '1/', fixture); equal('1/2', '1/2', fixture); @@ -714,26 +713,26 @@ describe('Directive: Mask', () => { }); it('Mask 9000/0000', () => { - component.mask = '0009/0000'; + component.mask.set('0009/0000'); equal('111/1111', '111/1111', fixture); equal('1111/1111', '1111/1111', fixture); }); it('Mask 00009-0000', () => { - component.mask = '00009-0000'; + component.mask.set('00009-0000'); equal('0000-0000', '0000-0000', fixture); equal('12345-6789', '12345-6789', fixture); }); it('Mask 099L', () => { - component.mask = '099L'; + component.mask.set('099L'); equal('1d', '1d', fixture); equal('22r', '22r', fixture); equal('223r', '223r', fixture); }); it('Mask 09999/099L', () => { - component.mask = '09999/099L'; + component.mask.set('09999/099L'); equal('1/2d', '1/2d', fixture); equal('12/2d', '12/2d', fixture); equal('123/2d', '123/2d', fixture); @@ -744,7 +743,7 @@ describe('Directive: Mask', () => { }); it('Mask 099SS', () => { - component.mask = '099SS'; + component.mask.set('099SS'); equal('1d', '1d', fixture); equal('1dD', '1dD', fixture); equal('11d', '11d', fixture); @@ -753,7 +752,7 @@ describe('Directive: Mask', () => { }); it('Mask 999999-0009999999/0000', () => { - component.mask = '999999-0009999999/0000'; + component.mask.set('999999-0009999999/0000'); equal('1-123/1234', '1-123/1234', fixture); equal('12-123/1234', '12-123/1234', fixture); equal('123-123/1234', '123-123/1234', fixture); @@ -770,14 +769,14 @@ describe('Directive: Mask', () => { }); it('setValue undefined should return null', () => { - component.mask = '0000'; + component.mask.set('0000'); equal('1234', '1234', fixture); component.form.setValue(null); expect(component.form.value).toBe(null); }); it('after resetValue should show in model same value', () => { - component.mask = '0'; + component.mask.set('0'); equal('1', '1', fixture); component.form.reset(); equal('1', '1', fixture); @@ -785,7 +784,7 @@ describe('Directive: Mask', () => { }); it('after resetValue should show in model same value', () => { - component.mask = '9'; + component.mask.set('9'); equal('2', '2', fixture); component.form.reset(); equal('2', '2', fixture); @@ -793,7 +792,7 @@ describe('Directive: Mask', () => { }); it('should work with optional mask 09.09', () => { - component.mask = '09.09'; + component.mask.set('09.09'); equal('2', '2', fixture); equal('2.3', '2.3', fixture); equal('2.34', '2.34', fixture); @@ -803,7 +802,7 @@ describe('Directive: Mask', () => { }); it('should work change value after setValue to empty string mask 9', () => { - component.mask = '9'; + component.mask.set('9'); equal('2', '2', fixture); component.form.setValue(''); equal('2', '2', fixture); @@ -811,7 +810,7 @@ describe('Directive: Mask', () => { }); it('should work change value after setValue to empty string mask 0', () => { - component.mask = '0'; + component.mask.set('0'); equal('4', '4', fixture); component.form.setValue(''); equal('4', '4', fixture); @@ -819,7 +818,7 @@ describe('Directive: Mask', () => { }); it('should return empty string if first character not same in mask (000) 000-0000', () => { - component.mask = '(000) 000-0000'; + component.mask.set('(000) 000-0000'); equal('', '', fixture); equal('@', '', fixture); @@ -835,8 +834,8 @@ describe('Directive: Mask', () => { }); it('should return empty string if first character not same in mask (000) 000-0000 with prefix', () => { - component.mask = '(000) 000-0000'; - component.prefix = '+7'; + component.mask.set('(000) 000-0000'); + component.prefix.set('+7'); equal('', '', fixture); equal('@', '', fixture); equal('!', '', fixture); @@ -851,8 +850,8 @@ describe('Directive: Mask', () => { }); it('should return empty string if first character not same in mask (000) 000-0000 with suffix', () => { - component.mask = '(000) 000-0000'; - component.prefix = '+7'; + component.mask.set('(000) 000-0000'); + component.prefix.set('+7'); equal('', '', fixture); equal('@', '', fixture); equal('!', '', fixture); @@ -867,7 +866,7 @@ describe('Directive: Mask', () => { }); it('should return empty string if first character not same in mask (000) 000-0000||+000000000000000', () => { - component.mask = '(000) 000-0000||+000000000000000'; + component.mask.set('(000) 000-0000||+000000000000000'); equal('', '', fixture); equal('@', '', fixture); @@ -883,8 +882,8 @@ describe('Directive: Mask', () => { }); it('should return empty string if first character not same in mask +(000) 000-0000', () => { - component.mask = '(000) 000-0000'; - component.prefix = '+7'; + component.mask.set('(000) 000-0000'); + component.prefix.set('+7'); equal('', '', fixture); equal('@', '', fixture); equal('!', '', fixture); @@ -899,7 +898,7 @@ describe('Directive: Mask', () => { }); it('optional mask should work correct 99-99', () => { - component.mask = '99-99'; + component.mask.set('99-99'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '12-3', fixture); @@ -909,7 +908,7 @@ describe('Directive: Mask', () => { }); it('custom mask with optional symbol should work correct mask=999-999-999', () => { - component.mask = '999-999-999'; + component.mask.set('999-999-999'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -936,9 +935,9 @@ describe('Directive: Mask', () => { spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); fixture.detectChanges(); - component.mask = '00/00/0000'; - component.showMaskTyped = true; - component.keepCharacterPositions = true; + component.mask.set('00/00/0000'); + component.showMaskTyped.set(true); + component.keepCharacterPositions.set(true); equal('11/11/1111', '11/11/1111', fixture); component.form.setValue('22/22/2222'); @@ -948,35 +947,35 @@ describe('Directive: Mask', () => { }); it('mask sepator.0 after setValue should be dont dirty', () => { - component.mask = 'separator.0'; + component.mask.set('separator.0'); component.form.setValue('2'); expect(component.form.dirty).toBe(false); }); it('mask sepator.2 after setValue should be dont dirty', () => { - component.mask = 'separator.0'; + component.mask.set('separator.0'); component.form.setValue('2002'); expect(component.form.dirty).toBe(false); }); it('mask 00/00/0000 after setValue should be dont dirty', () => { - component.mask = 'separator.0'; + component.mask.set('separator.0'); component.form.setValue('12312312'); expect(component.form.dirty).toBe(false); }); it('mask sepator.2 after setValue should be dont dirty', () => { - component.mask = 'separator.0'; + component.mask.set('separator.0'); component.form.setValue('2002'); expect(component.form.dirty).toBe(false); }); it('should return empty string in formControl mask SSS-SSS-SSS', () => { - component.mask = 'SSS-SSS-SSS'; + component.mask.set('SSS-SSS-SSS'); component.form.setValue('978-1-93624-386-0'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; @@ -987,7 +986,7 @@ describe('Directive: Mask', () => { }); it('should return empty string in formControl mask AAA-AAA-AAA', () => { - component.mask = 'AAA-AAA-AAA'; + component.mask.set('AAA-AAA-AAA'); component.form.setValue('978-123-936'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; @@ -998,7 +997,7 @@ describe('Directive: Mask', () => { }); it('should return empty string in formControl mask (000) 000-000', () => { - component.mask = '(000) 000-000'; + component.mask.set('(000) 000-000'); component.form.setValue('978-123-936'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; @@ -1009,8 +1008,8 @@ describe('Directive: Mask', () => { }); it('should return empty string in formControl mask (000) 000-000 with prefix +7', () => { - component.mask = '(000) 000-000'; - component.prefix = '+7 '; + component.mask.set('(000) 000-000'); + component.prefix.set('+7 '); component.form.setValue('978-123-936'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; diff --git a/projects/ngx-mask-lib/src/test/clear-if-not-match-the-mask.spec.ts b/projects/ngx-mask-lib/src/test/clear-if-not-match-the-mask.spec.ts index 88794ac5..9e55714c 100644 --- a/projects/ngx-mask-lib/src/test/clear-if-not-match-the-mask.spec.ts +++ b/projects/ngx-mask-lib/src/test/clear-if-not-match-the-mask.spec.ts @@ -3,8 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask', () => { let fixture: ComponentFixture; @@ -21,8 +20,8 @@ describe('Directive: Mask', () => { }); it('should clear if mask is not matched', async () => { - component.mask = '000.000-00'; - component.clearIfNotMatch = true; + component.mask.set('000.000-00'); + component.clearIfNotMatch.set(true); equal('', '', fixture, true); equal('2578989', '', fixture, true); equal('2578989888988', '257.898-98', fixture); @@ -30,18 +29,18 @@ describe('Directive: Mask', () => { }); it('should clear if mask is not matched with prefix', async () => { - component.mask = '000-000-00'; - component.prefix = '+5'; - component.clearIfNotMatch = true; + component.mask.set('000-000-00'); + component.prefix.set('+5'); + component.clearIfNotMatch.set(true); equal('', '', fixture, true); equal('2578989', '', fixture, true); equal('25789898', '+5257-898-98', fixture); }); it('should clear if mask is not matched with another placeholderCharacter *', async () => { - component.mask = '0000'; - component.placeHolderCharacter = '*'; - component.clearIfNotMatch = true; + component.mask.set('0000'); + component.placeHolderCharacter.set('*'); + component.clearIfNotMatch.set(true); equal('', '', fixture, true); equal('333', '', fixture, true); equal('22', '', fixture, true); @@ -49,9 +48,9 @@ describe('Directive: Mask', () => { }); it('should clear if mask is not matched with another placeholderCharacter X', async () => { - component.mask = '00000'; - component.placeHolderCharacter = 'X'; - component.clearIfNotMatch = true; + component.mask.set('00000'); + component.placeHolderCharacter.set('X'); + component.clearIfNotMatch.set(true); equal('', '', fixture, true); equal('333', '', fixture, true); equal('22', '', fixture, true); diff --git a/projects/ngx-mask-lib/src/test/complete-mask.spec.ts b/projects/ngx-mask-lib/src/test/complete-mask.spec.ts index c6de3d70..dbb2abd6 100644 --- a/projects/ngx-mask-lib/src/test/complete-mask.spec.ts +++ b/projects/ngx-mask-lib/src/test/complete-mask.spec.ts @@ -1,9 +1,8 @@ -import { Component } from '@angular/core'; +import { Component, signal } from '@angular/core'; import type { ComponentFixture } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; @Component({ selector: 'jsdaddy-open-source-test', @@ -14,10 +13,10 @@ import { NgxMaskDirective } from '../lib/ngx-mask.directive'; class TestMaskComponent { public form: FormControl = new FormControl(''); - public isMaskFilled = false; + public isMaskFilled = signal(false); public maskFilled(): void { - this.isMaskFilled = true; + this.isMaskFilled.set(true); } } @@ -38,11 +37,11 @@ describe('Directive: Mask (Function maskFilled)', () => { }); it('should call function maskFilled and isMaskFilled should be true', () => { component.form.setValue('9999'); - expect(component.isMaskFilled).toBeTrue(); + expect(component.isMaskFilled()).toBeTrue(); expect(maskFilledSpy).toHaveBeenCalledOnceWith(); }); it('isMaskFilled should be false', () => { component.form.setValue('999'); - expect(component.isMaskFilled).toBeFalse(); + expect(component.isMaskFilled()).toBeFalse(); }); }); diff --git a/projects/ngx-mask-lib/src/test/copy-paste.spec.ts b/projects/ngx-mask-lib/src/test/copy-paste.spec.ts index 59eb800b..0314796e 100644 --- a/projects/ngx-mask-lib/src/test/copy-paste.spec.ts +++ b/projects/ngx-mask-lib/src/test/copy-paste.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { By } from '@angular/platform-browser'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Event: paste', () => { let fixture: ComponentFixture; @@ -22,7 +21,7 @@ describe('Event: paste', () => { }); it('After paste to control cursor should be on the end of input)', () => { - component.mask = '00 - 0000 - 00000'; + component.mask.set('00 - 0000 - 00000'); fixture.detectChanges(); const inputDebuggerElement = fixture.debugElement.query(By.css('#mask')); @@ -43,8 +42,8 @@ describe('Event: paste', () => { expect(inputDebuggerElement.nativeElement.selectionStart).toBe(15); }); it('After paste to control cursor should be on the end of input for mask with separator', () => { - component.mask = 'separator.0'; - component.thousandSeparator = ','; + component.mask.set('separator.0'); + component.thousandSeparator.set(','); fixture.detectChanges(); const inputDebuggerElement = fixture.debugElement.query(By.css('#mask')); diff --git a/projects/ngx-mask-lib/src/test/custom-date.spec.ts b/projects/ngx-mask-lib/src/test/custom-date.spec.ts index c39b2701..9669877c 100644 --- a/projects/ngx-mask-lib/src/test/custom-date.spec.ts +++ b/projects/ngx-mask-lib/src/test/custom-date.spec.ts @@ -3,8 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Custom date)', () => { let fixture: ComponentFixture; @@ -21,8 +20,8 @@ describe('Directive: Mask (Custom date)', () => { }); it('repeat mask', () => { - component.mask = 'd0/m0/0000'; - // equal('18052019', '18/05/2019', fixture); + component.mask.set('d0/m0/0000'); + equal('18', '18', fixture); equal('11111111', '11/11/1111', fixture); }); @@ -30,7 +29,7 @@ describe('Directive: Mask (Custom date)', () => { it('should keep the cursor position after deleting a character', () => { // Set the initial input value and trigger an input event const inputElement = fixture.nativeElement.querySelector('input'); - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); inputElement.value = '12:34:56'; inputElement.dispatchEvent(new Event('input')); fixture.detectChanges(); diff --git a/projects/ngx-mask-lib/src/test/custom-patterns.spec.ts b/projects/ngx-mask-lib/src/test/custom-patterns.spec.ts index 666d4729..1770d7c9 100644 --- a/projects/ngx-mask-lib/src/test/custom-patterns.spec.ts +++ b/projects/ngx-mask-lib/src/test/custom-patterns.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; import type { NgxMaskConfig } from 'ngx-mask'; import { initialConfig } from 'ngx-mask'; @@ -24,12 +23,12 @@ describe('Directive: Mask (Custom patterns)', () => { }); it('custom patterns', () => { - component.mask = 'FFF'; - component.patterns = { + component.mask.set('FFF'); + component.patterns.set({ F: { pattern: new RegExp('[0-9]'), }, - }; + }); equal('F', '', fixture); equal('123', '123', fixture); }); @@ -58,7 +57,7 @@ describe('Directive: Mask (Provide custom patterns)', () => { }); it('custom patterns B should be work like optional', () => { - component.mask = 'SSBB-0999'; + component.mask.set('SSBB-0999'); equal('F', 'F', fixture); equal('FF', 'FF', fixture); @@ -101,29 +100,29 @@ describe('Directive: Mask (Provide custom patterns with symbol *)', () => { }); it('custom patterns * should work with mask *-*', () => { - component.mask = '*-*'; + component.mask.set('*-*'); equal('22', '2-2', fixture); }); it('custom patterns * should work with mask **-**', () => { - component.mask = '**-**'; + component.mask.set('**-**'); equal('22', '22', fixture); equal('123', '12-3', fixture); equal('1234', '12-34', fixture); }); it('custom patterns * should work with mask ***-***', () => { - component.mask = '***-***'; + component.mask.set('***-***'); equal('123456', '123-456', fixture); }); it('custom patterns * should work with mask ****-****', () => { - component.mask = '****-****'; + component.mask.set('****-****'); equal('12345678', '1234-5678', fixture); }); it('custom patterns * should work with mask *****-*****', () => { - component.mask = '*****-*****'; + component.mask.set('*****-*****'); equal('1234567890', '12345-67890', fixture); }); }); @@ -155,23 +154,23 @@ describe('Directive: Mask (Provide custom patterns with symbol f and F)', () => }); it('custom patterns f* should work not delete space after setTimeout', () => { - component.mask = 'f*'; + component.mask.set('f*'); equal('test value', 'test value', fixture); equal('test value with', 'test value with', fixture); equal('test value with space', 'test value with space', fixture); setTimeout(() => { - component.mask = 'F*'; + component.mask.set('F*'); expect(component.form.value).toBe('test value with space'); }); }); it('custom patterns F* should work not delete space after setTimeout', () => { - component.mask = 'F*'; + component.mask.set('F*'); equal('test value', 'test value', fixture); equal('test value with', 'test value with', fixture); equal('test value with space', 'test value with space', fixture); setTimeout(() => { - component.mask = 'f*'; + component.mask.set('f*'); expect(component.form.value).toBe('test value with space'); }); }); @@ -201,8 +200,9 @@ describe('Directive: Mask (Provide custom patterns with symbol B optional)', () }); it('custom mask with optional symbol should work correct mask=(000) 000-0000 x BBBBBBBBBB', () => { - component.mask = '(000) 000-0000 x BBBBBBBBBB'; - component.specialCharacters = ['(', ')', ' ', '-', 'x']; + component.mask.set('(000) 000-0000 x BBBBBBBBBB'); + component.specialCharacters.set(['(', ')', ' ', '-', 'x']); + equal('1', '(1', fixture); equal('12', '(12', fixture); equal('123', '(123', fixture); @@ -226,7 +226,8 @@ describe('Directive: Mask (Provide custom patterns with symbol B optional)', () }); it('custom mask with optional symbol should work correct mask=BBB-BBB-BBB', () => { - component.mask = 'BBB-BBB-BBB'; + component.mask.set('BBB-BBB-BBB'); + equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); diff --git a/projects/ngx-mask-lib/src/test/custom-symbol-regexp.spec.ts b/projects/ngx-mask-lib/src/test/custom-symbol-regexp.spec.ts index bbe4e83d..e8265db9 100644 --- a/projects/ngx-mask-lib/src/test/custom-symbol-regexp.spec.ts +++ b/projects/ngx-mask-lib/src/test/custom-symbol-regexp.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask', () => { let fixture: ComponentFixture; @@ -22,7 +21,7 @@ describe('Directive: Mask', () => { }); it('custom patterns', () => { - component.mask = '00*.00'; + component.mask.set('00*.00'); equal('22222.333333', '22222.33', fixture); equal('22212323232', '22212323232', fixture); }); @@ -31,8 +30,8 @@ describe('Directive: Mask', () => { const testPattern = { S: { pattern: new RegExp('[A-Za-z-Áá]') }, }; - component.mask = 'S*'; - component.patterns = testPattern; + component.mask.set('S*'); + component.patterns.set(testPattern); equal('Fernándos', 'Fernándos', fixture); equal('Ánton', 'Ánton', fixture); }); diff --git a/projects/ngx-mask-lib/src/test/default-config.spec.ts b/projects/ngx-mask-lib/src/test/default-config.spec.ts index b94bed1b..123984af 100644 --- a/projects/ngx-mask-lib/src/test/default-config.spec.ts +++ b/projects/ngx-mask-lib/src/test/default-config.spec.ts @@ -2,9 +2,8 @@ import type { ComponentFixture } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, FormControl } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; -import { provideEnvironmentNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; -import type { NgxMaskOptions } from '../lib/ngx-mask.config'; +import { provideEnvironmentNgxMask, NgxMaskDirective } from 'ngx-mask'; +import type { NgxMaskOptions } from 'ngx-mask'; function createComponentWithDefaultConfig( defaultConfig?: NgxMaskOptions @@ -24,7 +23,7 @@ describe('Default config', () => { thousandSeparator: '.', }); const component = fixture.componentInstance; - component.mask = 'separator'; + component.mask.set('separator'); component.form = new FormControl(1234.56); fixture.detectChanges(); fixture.whenRenderingDone().then(() => { @@ -38,7 +37,7 @@ describe('Default config', () => { thousandSeparator: ' ', }); const component = fixture.componentInstance; - component.mask = 'separator'; + component.mask.set('separator'); component.form = new FormControl(1234.56); fixture.detectChanges(); fixture.whenRenderingDone().then(() => { @@ -52,12 +51,12 @@ describe('Default config', () => { thousandSeparator: ' ', }); const component = fixture.componentInstance; - component.mask = 'separator'; + component.mask.set('separator'); // Override default decimalMarker and thousandSeparator - component.decimalMarker = ','; - component.thousandSeparator = '.'; + component.decimalMarker.set(','); + component.thousandSeparator.set('.'); component.form = new FormControl(1234.56); - component.specialCharacters = ['/']; // Explicit set needed to prevent bug in ngx-mask.directive.ts OnChanges event (if specialCharacters is undefined, OnChanges function will return prematurely and won't apply provided thousandSeparator and decimalMarker) + component.specialCharacters.set(['/']); // Explicit set needed to prevent bug in ngx-mask.directive.ts OnChanges event (if specialCharacters is undefined, OnChanges function will return prematurely and won't apply provided thousandSeparator and decimalMarker) fixture.detectChanges(); fixture.whenRenderingDone().then(() => { expect(fixture.nativeElement.querySelector('input').value).toBe('1.234,56'); @@ -72,7 +71,7 @@ describe('Default config', () => { separatorLimit: '100', }); const component = fixture.componentInstance; - component.mask = 'separator.2'; + component.mask.set('separator.2'); component.form = new FormControl(123); fixture.detectChanges(); @@ -89,7 +88,7 @@ describe('Default config', () => { leadZero: true, }); const component = fixture.componentInstance; - component.mask = 'separator.2'; + component.mask.set('separator.2'); component.form = new FormControl(15000.33); fixture.detectChanges(); diff --git a/projects/ngx-mask-lib/src/test/delete.spec.ts b/projects/ngx-mask-lib/src/test/delete.spec.ts index 73c01f11..eaf32869 100644 --- a/projects/ngx-mask-lib/src/test/delete.spec.ts +++ b/projects/ngx-mask-lib/src/test/delete.spec.ts @@ -6,8 +6,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; +import { provideNgxMask, NgxMaskDirective } from 'ngx-mask'; describe('Directive: Mask (Delete)', () => { let fixture: ComponentFixture; @@ -24,7 +23,7 @@ describe('Directive: Mask (Delete)', () => { }); it('delete character in input', () => { - component.mask = '00/00/0000'; + component.mask.set('00/00/0000'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -46,7 +45,7 @@ describe('Directive: Mask (Delete)', () => { }); it('delete special character in input', () => { - component.mask = '00/00/0000'; + component.mask.set('00/00/0000'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -68,8 +67,8 @@ describe('Directive: Mask (Delete)', () => { }); it('delete special character in secure input', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -91,7 +90,7 @@ describe('Directive: Mask (Delete)', () => { }); it('delete special character on 1 position', () => { - component.mask = '[00]'; + component.mask.set('[00]'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -112,8 +111,8 @@ describe('Directive: Mask (Delete)', () => { }); it('delete suffix with backspace and delete', () => { - component.mask = 'A{5}'; - component.suffix = '.com'; + component.mask.set('A{5}'); + component.suffix.set('.com'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -147,8 +146,8 @@ describe('Directive: Mask (Delete)', () => { }); it('prefix shouldn`t be deleted', () => { - component.mask = '00 00'; - component.prefix = '+1'; + component.mask.set('00 00'); + component.prefix.set('+1'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -172,8 +171,8 @@ describe('Directive: Mask (Delete)', () => { }); it('prefix shouldn`t be deleted', () => { - component.mask = '00 00'; - component.prefix = '+1 '; + component.mask.set('00 00'); + component.prefix.set('+1 '); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -197,8 +196,8 @@ describe('Directive: Mask (Delete)', () => { }); it('prefix shouldn`t be deleted', () => { - component.mask = '(00) 00'; - component.prefix = '+1'; + component.mask.set('(00) 00'); + component.prefix.set('+1'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -222,8 +221,8 @@ describe('Directive: Mask (Delete)', () => { }); it('prefix shouldn`t be deleted', () => { - component.mask = '(00) 00'; - component.prefix = '+1 '; + component.mask.set('(00) 00'); + component.prefix.set('+1 '); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -247,7 +246,7 @@ describe('Directive: Mask (Delete)', () => { }); it('date mask should show keep right value d0/M0/0000', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '4/4/4444'; @@ -270,7 +269,7 @@ describe('Directive: Mask (Delete)', () => { }); it('date mask should show keep right value d0:M0:0000', () => { - component.mask = 'd0:M0:0000'; + component.mask.set('d0:M0:0000'); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '4:4:4444'; @@ -293,7 +292,7 @@ describe('Directive: Mask (Delete)', () => { }); it('date mask should show keep right value d0-M0-0000', () => { - component.mask = 'd0-M0-0000'; + component.mask.set('d0-M0-0000'); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '4-4-4444'; diff --git a/projects/ngx-mask-lib/src/test/drop-special-charaters.spec.ts b/projects/ngx-mask-lib/src/test/drop-special-charaters.spec.ts index e1335d95..161c6725 100644 --- a/projects/ngx-mask-lib/src/test/drop-special-charaters.spec.ts +++ b/projects/ngx-mask-lib/src/test/drop-special-charaters.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Drop special characters)', () => { let fixture: ComponentFixture; @@ -22,8 +21,8 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('FormControl should be filled without special characters', () => { - component.mask = '00-00-00'; - component.dropSpecialCharacters = false; + component.mask.set('00-00-00'); + component.dropSpecialCharacters.set(false); equal('257898', '25-78-98', fixture); expect(component.form.value).toBe('25-78-98'); @@ -33,16 +32,16 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('should correct value with mask 00-00/00 with dropSpecialCharacters = /', () => { - component.mask = '00-00/00'; - component.dropSpecialCharacters = ['/']; + component.mask.set('00-00/00'); + component.dropSpecialCharacters.set(['/']); equal('257898', '25-78/98', fixture); expect(component.form.value).toBe('25-7898'); }); it('should correct value with mask 0000.00 with dropSpecialCharacters = true', () => { - component.mask = '0000.00'; - component.dropSpecialCharacters = true; + component.mask.set('0000.00'); + component.dropSpecialCharacters.set(true); component.form.setValue(123456); equal('123456', '1234.56', fixture); @@ -50,9 +49,9 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('FormControl should be filled without special characters', () => { - component.mask = 'separator.4'; - component.thousandSeparator = ','; - component.dropSpecialCharacters = true; + component.mask.set('separator.4'); + component.thousandSeparator.set(','); + component.dropSpecialCharacters.set(true); component.form.setValue(2578.9812); equal('2578.9812', '2,578.9812', fixture); @@ -60,9 +59,9 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('FormControl should normally handle the removal of whitespace', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ' '; - component.dropSpecialCharacters = true; + component.mask.set('separator.2'); + component.thousandSeparator.set(' '); + component.dropSpecialCharacters.set(true); component.form.setValue(1234567.89); // @todo add backspace event check @@ -72,9 +71,9 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('dropSpecialCharacter test for valid', () => { - component.mask = '(000) 000-0000'; - component.dropSpecialCharacters = true; - component.validation = true; + component.mask.set('(000) 000-0000'); + component.dropSpecialCharacters.set(true); + component.validation.set(true); equal('1', '(1', fixture); expect(component.form.valid).toBe(false); equal('12', '(12', fixture); @@ -98,9 +97,9 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('dropSpecialCharacter = false test for valid', () => { - component.mask = '(000) 000-0000'; - component.dropSpecialCharacters = true; - component.validation = true; + component.mask.set('(000) 000-0000'); + component.dropSpecialCharacters.set(true); + component.validation.set(true); equal('1', '(1', fixture); expect(component.form.valid).toBe(false); equal('12', '(12', fixture); @@ -124,18 +123,18 @@ describe('Directive: Mask (Drop special characters)', () => { }); it('dropSpecialCharacter = true test for valid with setValue', () => { - component.mask = '(000) 000-0000'; - component.dropSpecialCharacters = true; - component.validation = true; + component.mask.set('(000) 000-0000'); + component.dropSpecialCharacters.set(true); + component.validation.set(true); component.form.setValue('1234567890'); equal('1234567890', '(123) 456-7890', fixture); expect(component.form.valid).toBe(true); }); it('dropSpecialCharacter = false test for valid with setValue', () => { - component.mask = '(000) 000-0000'; - component.dropSpecialCharacters = false; - component.validation = true; + component.mask.set('(000) 000-0000'); + component.dropSpecialCharacters.set(false); + component.validation.set(true); equal('1', '(1', fixture); expect(component.form.valid).toBeFalsy(); equal('12', '(12', fixture); diff --git a/projects/ngx-mask-lib/src/test/dynamic.spec.ts b/projects/ngx-mask-lib/src/test/dynamic.spec.ts index 6a600039..908c6692 100644 --- a/projects/ngx-mask-lib/src/test/dynamic.spec.ts +++ b/projects/ngx-mask-lib/src/test/dynamic.spec.ts @@ -5,8 +5,7 @@ import { By } from '@angular/platform-browser'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import type { DebugElement } from '@angular/core'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; import { equal } from './utils/test-functions.component'; describe('Directive: Mask (Dynamic)', () => { @@ -24,7 +23,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('The input value when set by the FormControl should be masked accordingly the dynamic mask', async () => { - component.mask = '000-0||0000-0||00000-0'; + component.mask.set('000-0||0000-0||00000-0'); fixture.detectChanges(); component.form.setValue({ @@ -63,13 +62,13 @@ describe('Directive: Mask (Dynamic)', () => { return ''; } - component.mask = ''; + component.mask.set(''); fixture.detectChanges(); component.form.setValue({ value: 9000000000000000000, }); - component.mask = getMask(); + component.mask.set(getMask()); fixture.detectChanges(); const inputEl = fixture.debugElement.query(By.css('input')); @@ -79,7 +78,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('Change mask dynamically from mask several masks to one', async () => { - component.mask = '(000)0000-000||(000)0000-0000||00-00000-00000'; // China phone formats + component.mask.set('(000)0000-000||(000)0000-0000||00-00000-00000'); // China phone formats fixture.detectChanges(); component.form.setValue({ @@ -109,7 +108,7 @@ describe('Directive: Mask (Dynamic)', () => { expect(inputEl.nativeElement.value).toEqual('12-34567-89012'); }); - component.mask = '00-00-00-00'; // For example Denmark phone format + component.mask.set('00-00-00-00'); // For example Denmark phone format fixture.detectChanges(); component.form.setValue({ @@ -124,9 +123,9 @@ describe('Directive: Mask (Dynamic)', () => { it('The input value when set by the FormControl should be masked accordingly the dynamic mask', async () => { let inputEl: DebugElement; - component.mask = 'separator.2'; - component.thousandSeparator = '.'; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); + component.decimalMarker.set(','); fixture.detectChanges(); @@ -156,7 +155,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('Should update position to the end of input when mask changes while typing', async () => { - component.mask = '(00) 00000000||+00 (00) 00000000'; + component.mask.set('(00) 00000000||+00 (00) 00000000'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -183,7 +182,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with number or letters', () => { - component.mask = '00||SS'; + component.mask.set('00||SS'); equal('0', '0', fixture); equal('11', '11', fixture); equal('D', 'D', fixture); @@ -191,7 +190,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with number or letters', () => { - component.mask = '00||SS||000||000SS||0S0S'; + component.mask.set('00||SS||000||000SS||0S0S'); equal('0', '0', fixture); expect(component.form.valid).toBeFalse(); equal('11', '11', fixture); @@ -215,7 +214,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work for UK Post Codes', () => { - component.mask = 'S0 0SS||SAA 0SS||SS0A 0SS'; + component.mask.set('S0 0SS||SAA 0SS||SS0A 0SS'); equal('A', 'A', fixture); expect(component.form.valid).toBeFalse(); equal('A0', 'A0', fixture); @@ -229,7 +228,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with number or letters', () => { - component.mask = '00||SS||000||000SS'; + component.mask.set('00||SS||000||000SS'); equal('0', '0', fixture); expect(component.form.invalid).toBeTrue(); equal('11', '11', fixture); @@ -247,8 +246,8 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should be valid if mask dont changes 00000||00000-0000', () => { - component.mask = '00000||00000-0000'; - component.showMaskTyped = true; + component.mask.set('00000||00000-0000'); + component.showMaskTyped.set(true); equal('1', '1____', fixture); expect(component.form.invalid).toBeTrue(); equal('11', '11___', fixture); @@ -270,7 +269,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with when justPasted', () => { - component.mask = '00000||S0S 0S0'; + component.mask.set('00000||S0S 0S0'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -285,7 +284,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with only S', () => { - component.mask = 'S.||S.S.||S.S.S.||S.S.S.S.||S.S.S.S.S.'; + component.mask.set('S.||S.S.||S.S.S.||S.S.S.S.||S.S.S.S.S.'); equal('D', 'D.', fixture); equal('D.D', 'D.D.', fixture); equal('DDD', 'D.D.D.', fixture); @@ -294,7 +293,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with only A', () => { - component.mask = 'A.||A.A.||A.A.A.||A.A.A.A.||A.A.A.A.A.'; + component.mask.set('A.||A.A.||A.A.A.||A.A.A.A.||A.A.A.A.A.'); equal('D', 'D.', fixture); equal('D.D', 'D.D.', fixture); equal('DDD', 'D.D.D.', fixture); @@ -303,7 +302,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with only U', () => { - component.mask = 'U.||U.U.||U.U.U.||U.U.U.U.||U.U.U.U.U.'; + component.mask.set('U.||U.U.||U.U.U.||U.U.U.U.||U.U.U.U.U.'); equal('D', 'D.', fixture); equal('D.D', 'D.D.', fixture); equal('DDD', 'D.D.D.', fixture); @@ -312,7 +311,7 @@ describe('Directive: Mask (Dynamic)', () => { }); it('should work with only L', () => { - component.mask = 'L.||L.L.||L.L.L.||L.L.L.L.||L.L.L.L.L.'; + component.mask.set('L.||L.L.||L.L.L.||L.L.L.L.||L.L.L.L.L.'); equal('d', 'd.', fixture); equal('d.d', 'd.d.', fixture); equal('ddd', 'd.d.d.', fixture); diff --git a/projects/ngx-mask-lib/src/test/export-as.spec.ts b/projects/ngx-mask-lib/src/test/export-as.spec.ts index 231087b4..800a526b 100644 --- a/projects/ngx-mask-lib/src/test/export-as.spec.ts +++ b/projects/ngx-mask-lib/src/test/export-as.spec.ts @@ -3,8 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { Component, viewChild } from '@angular/core'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; @Component({ selector: 'jsdaddy-open-source-test', diff --git a/projects/ngx-mask-lib/src/test/inputTransformFn.spec.ts b/projects/ngx-mask-lib/src/test/inputTransformFn.spec.ts index 56ae77b2..1d0fd98c 100644 --- a/projects/ngx-mask-lib/src/test/inputTransformFn.spec.ts +++ b/projects/ngx-mask-lib/src/test/inputTransformFn.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; +import { provideNgxMask, NgxMaskDirective } from 'ngx-mask'; describe('Directive: Mask', () => { let fixture: ComponentFixture; @@ -22,8 +21,8 @@ describe('Directive: Mask', () => { }); it('inputTransformFn should return value toUpperCase', () => { - component.mask = 'S*'; - component.inputTransformFn = (value: unknown): string => String(value).toUpperCase(); + component.mask.set('S*'); + component.inputTransformFn.set((value: unknown): string => String(value).toUpperCase()); equal('a', 'A', fixture); equal('an', 'AN', fixture); @@ -34,9 +33,10 @@ describe('Directive: Mask', () => { }); it('inputTransformFn should return value formValue toUpperCase', () => { - component.mask = 'S*'; - component.outputTransformFn = (value: string | number | undefined | null): string => - String(value).toUpperCase(); + component.mask.set('S*'); + component.outputTransformFn.set((value: string | number | undefined | null): string => + String(value).toUpperCase() + ); equal('a', 'a', fixture); equal('an', 'an', fixture); @@ -48,10 +48,11 @@ describe('Directive: Mask', () => { }); it('inputTransformFn should return value formValue toUpperCase but input value to lowerCase', () => { - component.mask = 'S*'; - component.outputTransformFn = (value: string | number | undefined | null): string => - String(value).toUpperCase(); - component.inputTransformFn = (value: unknown): string => String(value).toLowerCase(); + component.mask.set('S*'); + component.outputTransformFn.set((value: string | number | undefined | null): string => + String(value).toUpperCase() + ); + component.inputTransformFn.set((value: unknown): string => String(value).toLowerCase()); equal('A', 'a', fixture); equal('AN', 'an', fixture); @@ -63,14 +64,14 @@ describe('Directive: Mask', () => { }); it('separator.2 should replace dot in model', () => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; - component.outputTransformFn = (value: string | number | undefined | null): string => { + component.mask.set('separator.2'); + component.decimalMarker.set('.'); + component.outputTransformFn.set((value: string | number | undefined | null): string => { if (String(value).includes('.')) { return String(value).replace('.', ','); } return String(value); - }; + }); equal('10.2', '10.2', fixture); expect(component.form.value).toBe('10,2'); @@ -83,16 +84,16 @@ describe('Directive: Mask', () => { }); it('separator.3 should toFixed value in model and return Number', () => { - component.mask = 'separator.3'; - component.decimalMarker = '.'; - component.outputTransformFn = (value: string | number | undefined | null): number => { + component.mask.set('separator.3'); + component.decimalMarker.set('.'); + component.outputTransformFn.set((value: string | number | undefined | null): number => { if (String(value).includes('.')) { const numberValue = parseFloat(String(value)); const formattedValue = Number(numberValue.toFixed(2)); return formattedValue; } return Number(value); - }; + }); equal('237.356', '237.356', fixture); expect(component.form.value).toBe(237.36); @@ -105,14 +106,14 @@ describe('Directive: Mask', () => { }); it('mask 000.00 should replace dot in model', () => { - component.mask = '000.00'; - component.dropSpecialCharacters = false; - component.outputTransformFn = (value: string | number | undefined | null): string => { + component.mask.set('000.00'); + component.dropSpecialCharacters.set(false); + component.outputTransformFn.set((value: string | number | undefined | null): string => { if (String(value).includes('.')) { return String(value).replace('.', ','); } return String(value); - }; + }); equal('100.22', '100.22', fixture); expect(component.form.value).toBe('100,22'); @@ -122,10 +123,11 @@ describe('Directive: Mask', () => { }); it('mask separator.1 should return number', () => { - component.mask = 'separator.1'; - component.decimalMarker = ','; - component.outputTransformFn = (value: string | number | undefined | null): number => - Number(value); + component.mask.set('separator.1'); + component.decimalMarker.set(','); + component.outputTransformFn.set((value: string | number | undefined | null): number => + Number(value) + ); equal('123,2', '123,2', fixture); expect(component.form.value).toBe(123.2); @@ -141,10 +143,11 @@ describe('Directive: Mask', () => { }); it('mask separator.1 should return number decimalMarker dot', () => { - component.mask = 'separator.1'; - component.decimalMarker = '.'; - component.outputTransformFn = (value: string | number | undefined | null): number => - Number(value); + component.mask.set('separator.1'); + component.decimalMarker.set('.'); + component.outputTransformFn.set((value: string | number | undefined | null): number => + Number(value) + ); equal('123.4', '123.4', fixture); expect(component.form.value).toBe(123.4); @@ -160,13 +163,13 @@ describe('Directive: Mask', () => { }); it('mask percent should replace dot in model', () => { - component.mask = 'percent.2'; - component.outputTransformFn = (value: string | number | undefined | null): string => { + component.mask.set('percent.2'); + component.outputTransformFn.set((value: string | number | undefined | null): string => { if (String(value).includes('.')) { return String(value).replace('.', ','); } return String(value); - }; + }); equal('1.2', '1.2', fixture); expect(component.form.value).toBe('1,2'); @@ -178,11 +181,11 @@ describe('Directive: Mask', () => { }); it('mask percent should replace dot in model', () => { - component.mask = 'Hh:m0'; - component.showMaskTyped = true; - component.dropSpecialCharacters = false; - component.leadZeroDateTime = true; - component.outputTransformFn = (value: string | number | undefined | null) => { + component.mask.set('Hh:m0'); + component.showMaskTyped.set(true); + component.dropSpecialCharacters.set(false); + component.leadZeroDateTime.set(true); + component.outputTransformFn.set((value: string | number | undefined | null) => { if (value) { const fetch = new Date(); const values = String(value).split(':'); @@ -196,9 +199,9 @@ describe('Directive: Mask', () => { return fetch.toString(); } return; - }; + }); const date = new Date(); - component.inputTransformFn = (value: unknown): string => { + component.inputTransformFn.set((value: unknown): string => { if (typeof value !== 'object') { return String(value); } @@ -206,7 +209,7 @@ describe('Directive: Mask', () => { 2, '0' )}`; - }; + }); component.form.setValue(new Date().toString()); expect(component.form.value).toBe(date.toString()); }); diff --git a/projects/ngx-mask-lib/src/test/mask.pipe.spec.ts b/projects/ngx-mask-lib/src/test/mask.pipe.spec.ts index 6cb7c216..87b3d646 100644 --- a/projects/ngx-mask-lib/src/test/mask.pipe.spec.ts +++ b/projects/ngx-mask-lib/src/test/mask.pipe.spec.ts @@ -1,8 +1,6 @@ import { TestBed } from '@angular/core/testing'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskPipe } from '../lib/ngx-mask.pipe'; import type { NgxMaskConfig } from 'ngx-mask'; -import { NgxMaskDirective } from 'ngx-mask'; +import { NgxMaskDirective, provideNgxMask, NgxMaskPipe } from 'ngx-mask'; describe('Pipe: Mask', () => { let maskPipe: NgxMaskPipe; diff --git a/projects/ngx-mask-lib/src/test/percent.spec.ts b/projects/ngx-mask-lib/src/test/percent.spec.ts index 4075b8b7..1682f4f6 100644 --- a/projects/ngx-mask-lib/src/test/percent.spec.ts +++ b/projects/ngx-mask-lib/src/test/percent.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Percent)', () => { let fixture: ComponentFixture; @@ -22,60 +21,60 @@ describe('Directive: Mask (Percent)', () => { }); it('percent for empty', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('', '', fixture); }); it('percent for 100', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('100', '100', fixture); }); it('percent for 99', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('99', '99', fixture); }); it('percent for 123', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('123', '12', fixture); }); it('percent for 99.99', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('99.99', '99.99', fixture); }); it('percent for 99', () => { - component.mask = 'percent.0'; + component.mask.set('percent.0'); equal('99.99999', '99', fixture); }); it('percent for 99.99', () => { - component.mask = 'percent.2'; + component.mask.set('percent.2'); equal('99.9999', '99.99', fixture); }); it('percent for 1.123', () => { - component.mask = 'percent.3'; + component.mask.set('percent.3'); equal('1.12345', '1.123', fixture); }); it('percent for 123.23', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('123.23', '12.23', fixture); }); it('percent with suffix', () => { - component.mask = 'percent'; - component.suffix = '%'; + component.mask.set('percent'); + component.suffix.set('%'); equal('50', '50%', fixture); equal('123', '12%', fixture); equal('50.50', '50.50%', fixture); }); it('percent for split zero percent.2', () => { - component.mask = 'percent.2'; + component.mask.set('percent.2'); equal('01.23', '1.23', fixture); equal('012.23', '12.23', fixture); equal('099.23', '99.23', fixture); @@ -84,7 +83,7 @@ describe('Directive: Mask (Percent)', () => { }); it('percent for split zero percent', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('01.23', '1.23', fixture); equal('012.23', '12.23', fixture); equal('099.23', '99.23', fixture); @@ -93,7 +92,7 @@ describe('Directive: Mask (Percent)', () => { }); it('percent for split zero percent.3', () => { - component.mask = 'percent.3'; + component.mask.set('percent.3'); equal('01.233', '1.233', fixture); equal('012.232', '12.232', fixture); equal('099.230', '99.230', fixture); @@ -102,8 +101,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent for split zero percent.2 should be valid', () => { - component.mask = 'percent.2'; - component.validation = true; + component.mask.set('percent.2'); + component.validation.set(true); fixture.detectChanges(); equal('1', '1', fixture); @@ -112,8 +111,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent for split zero percent.3 should be valid', () => { - component.mask = 'percent.3'; - component.validation = true; + component.mask.set('percent.3'); + component.validation.set(true); fixture.detectChanges(); equal('1', '1', fixture); @@ -122,8 +121,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent for split zero percent should be valid', () => { - component.mask = 'percent'; - component.validation = true; + component.mask.set('percent'); + component.validation.set(true); fixture.detectChanges(); equal('1', '1', fixture); @@ -132,8 +131,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.2 ', () => { - component.mask = 'percent.2'; - component.decimalMarker = ','; + component.mask.set('percent.2'); + component.decimalMarker.set(','); equal('1', '1', fixture); equal('12', '12', fixture); @@ -143,8 +142,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.3 ', () => { - component.mask = 'percent.3'; - component.decimalMarker = ','; + component.mask.set('percent.3'); + component.decimalMarker.set(','); equal('1', '1', fixture); equal('12', '12', fixture); @@ -155,9 +154,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.2 drop false ', () => { - component.mask = 'percent.2'; - component.dropSpecialCharacters = false; - component.decimalMarker = ','; + component.mask.set('percent.2'); + component.dropSpecialCharacters.set(false); + component.decimalMarker.set(','); equal('1', '1', fixture); equal('12', '12', fixture); @@ -167,9 +166,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.3 drop false ', () => { - component.mask = 'percent.3'; - component.dropSpecialCharacters = false; - component.decimalMarker = ','; + component.mask.set('percent.3'); + component.dropSpecialCharacters.set(false); + component.decimalMarker.set(','); equal('2', '2', fixture); equal('22', '22', fixture); @@ -179,10 +178,10 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.2 drop false with suffix ', () => { - component.mask = 'percent.2'; - component.dropSpecialCharacters = false; - component.decimalMarker = ','; - component.suffix = '%'; + component.mask.set('percent.2'); + component.dropSpecialCharacters.set(false); + component.decimalMarker.set(','); + component.suffix.set('%'); equal('1', '1%', fixture); equal('12', '12%', fixture); @@ -192,10 +191,10 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.3 drop false with suffix ', () => { - component.mask = 'percent.3'; - component.dropSpecialCharacters = false; - component.suffix = '%'; - component.decimalMarker = ','; + component.mask.set('percent.3'); + component.dropSpecialCharacters.set(false); + component.suffix.set('%'); + component.decimalMarker.set(','); equal('2', '2%', fixture); equal('22', '22%', fixture); @@ -205,9 +204,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.2with suffix ', () => { - component.mask = 'percent.2'; - component.suffix = '%'; - component.decimalMarker = ','; + component.mask.set('percent.2'); + component.suffix.set('%'); + component.decimalMarker.set(','); equal('1', '1%', fixture); equal('12', '12%', fixture); @@ -217,9 +216,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with decimalMarker = , percent.3 with suffix ', () => { - component.mask = 'percent.3'; - component.suffix = '%'; - component.decimalMarker = ','; + component.mask.set('percent.3'); + component.suffix.set('%'); + component.decimalMarker.set(','); equal('2', '2%', fixture); equal('22', '22%', fixture); @@ -229,8 +228,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with allowNegative = true', () => { - component.mask = 'percent'; - component.allowNegativeNumbers = true; + component.mask.set('percent'); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -240,8 +239,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with allowNegative = true', () => { - component.mask = 'percent.1'; - component.allowNegativeNumbers = true; + component.mask.set('percent.1'); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -251,9 +250,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with allowNegative = true', () => { - component.mask = 'percent.1'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + component.mask.set('percent.1'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -263,8 +262,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent 2 with allowNegative = true', () => { - component.mask = 'percent.2'; - component.allowNegativeNumbers = true; + component.mask.set('percent.2'); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -279,8 +278,8 @@ describe('Directive: Mask (Percent)', () => { }); it('percent 3 with allowNegative = true', () => { - component.mask = 'percent.3'; - component.allowNegativeNumbers = true; + component.mask.set('percent.3'); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -297,9 +296,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent with allowNegative = true, decimalMarker = ,', () => { - component.mask = 'percent'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + component.mask.set('percent'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -309,9 +308,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent 2 with allowNegative = true, decimalMarker = ,', () => { - component.mask = 'percent.2'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + component.mask.set('percent.2'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); equal('-', '-', fixture); equal('-0', '-0', fixture); @@ -326,9 +325,9 @@ describe('Directive: Mask (Percent)', () => { }); it('percent 3 with allowNegative = true, decimalMarker = ,', () => { - component.mask = 'percent.3'; - component.allowNegativeNumbers = true; - component.decimalMarker = ','; + component.mask.set('percent.3'); + component.allowNegativeNumbers.set(true); + component.decimalMarker.set(','); equal('-', '-', fixture); equal('-0', '-0', fixture); diff --git a/projects/ngx-mask-lib/src/test/place-holder-character.spec.ts b/projects/ngx-mask-lib/src/test/place-holder-character.spec.ts index ef95b8ab..7c983c11 100644 --- a/projects/ngx-mask-lib/src/test/place-holder-character.spec.ts +++ b/projects/ngx-mask-lib/src/test/place-holder-character.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Placeholder character)', () => { let fixture: ComponentFixture; @@ -22,25 +21,25 @@ describe('Directive: Mask (Placeholder character)', () => { }); it('should display the default placeholder when not configured', () => { - component.mask = '(000) 000-0000'; - component.showMaskTyped = true; + component.mask.set('(000) 000-0000'); + component.showMaskTyped.set(true); equal('', '(___) ___-____', fixture); equal('2345678', '(234) 567-8___', fixture); - component.prefix = '+7'; - component.showMaskTyped = true; + component.prefix.set('+7'); + component.showMaskTyped.set(true); equal('', '+7(___) ___-____', fixture); equal('2345678', '+7(234) 567-8___', fixture); - component.mask = 'IP'; - component.prefix = ''; - component.showMaskTyped = true; + component.mask.set('IP'); + component.prefix.set(''); + component.showMaskTyped.set(true); equal('', '_._._._', fixture); equal('1921681', '192.168.1_', fixture); - component.mask = 'CPF_CNPJ'; - component.prefix = ''; - component.showMaskTyped = true; + component.mask.set('CPF_CNPJ'); + component.prefix.set(''); + component.showMaskTyped.set(true); equal('', '___.___.___-__', fixture); equal('1', '1__.___.___-__', fixture); equal('12', '12_.___.___-__', fixture); @@ -57,9 +56,9 @@ describe('Directive: Mask (Placeholder character)', () => { equal('1234567890123', '12.345.678/9012-3_', fixture); equal('12345678901234', '12.345.678/9012-34', fixture); - component.mask = '000.000.000-00||00.000.000/0000-00'; - component.prefix = ''; - component.showMaskTyped = true; + component.mask.set('000.000.000-00||00.000.000/0000-00'); + component.prefix.set(''); + component.showMaskTyped.set(true); equal('1', '1__.___.___-__', fixture); equal('12', '12_.___.___-__', fixture); equal('123', '123.___.___-__', fixture); @@ -75,9 +74,9 @@ describe('Directive: Mask (Placeholder character)', () => { equal('1234567890123', '12.345.678/9012-3_', fixture); equal('12345678901234', '12.345.678/9012-34', fixture); - component.mask = '(00) 0000-0000||(00) 0 0000-0000'; - component.prefix = ''; - component.showMaskTyped = true; + component.mask.set('(00) 0000-0000||(00) 0 0000-0000'); + component.prefix.set(''); + component.showMaskTyped.set(true); equal('1', '(1_) ____-____', fixture); equal('12', '(12) ____-____', fixture); equal('123', '(12) 3___-____', fixture); @@ -104,26 +103,26 @@ describe('Directive: Mask (Placeholder character)', () => { }); it('should display the modified placeholder when configured', () => { - component.mask = '(000) 000-0000'; - component.showMaskTyped = true; - component.placeHolderCharacter = '*'; + component.mask.set('(000) 000-0000'); + component.showMaskTyped.set(true); + component.placeHolderCharacter.set('*'); equal('', '(***) ***-****', fixture); equal('2345678', '(234) 567-8***', fixture); - component.prefix = '+7'; - component.showMaskTyped = true; + component.prefix.set('+7'); + component.showMaskTyped.set(true); equal('', '+7(***) ***-****', fixture); equal('2345678', '+7(234) 567-8***', fixture); - component.mask = 'IP'; - component.prefix = ''; - component.showMaskTyped = true; + component.mask.set('IP'); + component.prefix.set(''); + component.showMaskTyped.set(true); equal('', '*.*.*.*', fixture); equal('1921681', '192.168.1*', fixture); - component.mask = 'CPF_CNPJ'; - component.prefix = ''; - component.showMaskTyped = true; + component.mask.set('CPF_CNPJ'); + component.prefix.set(''); + component.showMaskTyped.set(true); equal('', '***.***.***-**', fixture); equal('1', '1**.***.***-**', fixture); equal('12', '12*.***.***-**', fixture); diff --git a/projects/ngx-mask-lib/src/test/repeat-mask.spec.ts b/projects/ngx-mask-lib/src/test/repeat-mask.spec.ts index 318468a1..dbecd372 100644 --- a/projects/ngx-mask-lib/src/test/repeat-mask.spec.ts +++ b/projects/ngx-mask-lib/src/test/repeat-mask.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Directive: Mask (Repeat)', () => { let fixture: ComponentFixture; @@ -22,40 +21,40 @@ describe('Directive: Mask (Repeat)', () => { }); it('repeat mask', () => { - component.mask = '0{4}'; + component.mask.set('0{4}'); equal('1234', '1234', fixture); }); it('should work when repeat value is more then 9', () => { - component.mask = 'A{12}'; + component.mask.set('A{12}'); equal('123456789ABC', '123456789ABC', fixture); }); it('should correctly handle leading zeros', () => { - component.mask = 'A{02}'; + component.mask.set('A{02}'); equal('1234', '12', fixture); - component.mask = 'A{0000012}'; + component.mask.set('A{0000012}'); equal('123456789ABCDE', '123456789ABC', fixture); }); it('should repeat digits only', () => { - component.mask = '0{6}'; + component.mask.set('0{6}'); equal('AbC12345678Bfc', '123456', fixture); }); it('should repeat digits and letters', () => { - component.mask = 'A{6}'; + component.mask.set('A{6}'); equal('AbC12345678Bfc', 'AbC123', fixture); }); it('should repeat only letters', () => { - component.mask = 'S{6}'; + component.mask.set('S{6}'); equal('AbC12345678Bfc', 'AbCBfc', fixture); }); it('repeat mask date', () => { - component.mask = '0{2}/0{2}/0{4}'; + component.mask.set('0{2}/0{2}/0{4}'); equal('12345678', '12/34/5678', fixture); }); @@ -65,13 +64,13 @@ describe('Directive: Mask (Repeat)', () => { // }); it('specialCharacters quotes', () => { - component.mask = '0-0-0*-0*-0*'; + component.mask.set('0-0-0*-0*-0*'); equal('123', '1-2-3', fixture); equal('123-42-', '1-2-3-42-', fixture); }); it('should repeat digits only and work with dynamicMask', () => { - component.mask = '0{4}||0{6}'; + component.mask.set('0{4}||0{6}'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -81,7 +80,7 @@ describe('Directive: Mask (Repeat)', () => { }); it('should repeat digits only and work with dynamicMask', () => { - component.mask = 'SS0{4}'; + component.mask.set('SS0{4}'); equal('d', 'd', fixture); equal('dd', 'dd', fixture); equal('dd1', 'dd1', fixture); @@ -91,7 +90,7 @@ describe('Directive: Mask (Repeat)', () => { }); it('should repeat digits only and work with dynamicMask', () => { - component.mask = 'A{5}.S{2}'; + component.mask.set('A{5}.S{2}'); equal('d', 'd', fixture); equal('dd', 'dd', fixture); equal('dd1', 'dd1', fixture); @@ -102,7 +101,7 @@ describe('Directive: Mask (Repeat)', () => { }); it('should A{8} be valid if length 8', () => { - component.mask = 'A{8}'; + component.mask.set('A{8}'); equal('1', '1', fixture); expect(component.form.valid).toBe(false); equal('12', '12', fixture); @@ -128,7 +127,7 @@ describe('Directive: Mask (Repeat)', () => { }); it('should A{9} be valid if length 9', () => { - component.mask = 'A{9}'; + component.mask.set('A{9}'); equal('1', '1', fixture); expect(component.form.valid).toBe(false); equal('12', '12', fixture); @@ -157,7 +156,7 @@ describe('Directive: Mask (Repeat)', () => { }); it('should A{10} be valid if length 10', () => { - component.mask = 'A{10}'; + component.mask.set('A{10}'); equal('1', '1', fixture); expect(component.form.valid).toBe(false); equal('12', '12', fixture); diff --git a/projects/ngx-mask-lib/src/test/secure-mask.spec.ts b/projects/ngx-mask-lib/src/test/secure-mask.spec.ts index 295659a5..7916b436 100644 --- a/projects/ngx-mask-lib/src/test/secure-mask.spec.ts +++ b/projects/ngx-mask-lib/src/test/secure-mask.spec.ts @@ -5,8 +5,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal, typeTest } from './utils/test-functions.component'; -import { provideNgxMask } from 'ngx-mask'; -import { NgxMaskDirective } from 'ngx-mask'; +import { provideNgxMask, NgxMaskDirective } from 'ngx-mask'; import type { DebugElement } from '@angular/core'; import { By } from '@angular/platform-browser'; @@ -25,50 +24,50 @@ describe('Directive: Mask (Secure)', () => { }); it('it checks secure input functionality ', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); equal('1234', '***/*', fixture); expect(component.form.value).toBe('1234'); }); it('it checks secure input functionality ', () => { - component.mask = 'XXX/XX/0000'; - component.hiddenInput = true; + component.mask.set('XXX/XX/0000'); + component.hiddenInput.set(true); equal('123456789', '***/**/6789', fixture); expect(component.form.value).toBe('123456789'); }); it('it checks secure input functionality ', () => { - component.mask = 'XXX/XX/XXX0'; - component.hiddenInput = true; + component.mask.set('XXX/XX/XXX0'); + component.hiddenInput.set(true); equal('123456789', '***/**/***9', fixture); expect(component.form.value).toBe('123456789'); }); it('it checks secure input functionality ', () => { - component.mask = 'XXX/XX/XXXX'; - component.hiddenInput = true; + component.mask.set('XXX/XX/XXXX'); + component.hiddenInput.set(true); equal('123456789', '***/**/****', fixture); expect(component.form.value).toBe('123456789'); }); it('it checks secure input functionality ', () => { - component.mask = '0000-00-XXXX'; - component.hiddenInput = true; + component.mask.set('0000-00-XXXX'); + component.hiddenInput.set(true); equal('123456789', '1234-56-***', fixture); expect(component.form.value).toBe('123456789'); }); it('it checks secure input functionality ', () => { - component.mask = '0000-X0-XXXX'; - component.hiddenInput = true; + component.mask.set('0000-X0-XXXX'); + component.hiddenInput.set(true); equal('123456789', '1234-*6-***', fixture); expect(component.form.value).toBe('123456789'); }); it('it checks secure input functionality on reset', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); typeTest('54321', fixture); component.form.reset(); @@ -79,16 +78,16 @@ describe('Directive: Mask (Secure)', () => { }); it('it checks secure input functionality on reset then typed', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); typeTest('54321', fixture); component.form.reset(); equal('98765', '***/*5', fixture); }); it('it checks secure input functionality on setValue(longer string)', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); typeTest('54321', fixture); component.form.reset(); @@ -99,14 +98,14 @@ describe('Directive: Mask (Secure)', () => { }); it('should be same form state (pristine) after mask change triggerOnMaskChange = true', async () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; - component.triggerOnMaskChange = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); + component.triggerOnMaskChange.set(true); component.form.reset('123456789'); fixture.detectChanges(); expect(component.form.dirty).toBeTruthy(); expect(component.form.pristine).toBeFalsy(); - component.mask = '000/00/0000'; + component.mask.set('000/00/0000'); fixture.detectChanges(); expect(component.form.dirty).toBeTruthy(); expect(component.form.pristine).toBeFalsy(); @@ -116,15 +115,15 @@ describe('Directive: Mask (Secure)', () => { }); it('should be same form state (dirty) after mask change', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); component.form.reset('123456789'); component.form.markAsDirty(); component.form.markAsTouched(); fixture.detectChanges(); expect(component.form.dirty).toBeTruthy(); expect(component.form.pristine).toBeFalsy(); - component.mask = '000/00/0000'; + component.mask.set('000/00/0000'); fixture.detectChanges(); expect(component.form.dirty).toBeTruthy(); expect(component.form.pristine).toBeFalsy(); @@ -134,8 +133,8 @@ describe('Directive: Mask (Secure)', () => { }); it('should not keep shadow copy when form reset', () => { - component.hiddenInput = true; - component.mask = 'XXX/X0/0000'; + component.hiddenInput.set(true); + component.mask.set('XXX/X0/0000'); equal('54321', '***/*1', fixture); typeTest('1', fixture); expect(component.form.value).toBe('1'); @@ -146,19 +145,19 @@ describe('Directive: Mask (Secure)', () => { }); it('mask changes should work with null input', () => { - component.hiddenInput = true; - component.mask = '000/00/0000'; + component.hiddenInput.set(true); + component.mask.set('000/00/0000'); equal('987654321', '987/65/4321', fixture); component.form.reset(); - component.mask = 'XXX/X0/0000'; + component.mask.set('XXX/X0/0000'); equal('54321', '***/*1', fixture); expect(component.form.value).toBe('54321'); }); it('it checks secure input functionality on reset then typed', () => { - component.mask = 'XXX/X0/0000'; - component.hiddenInput = true; - component.showMaskTyped = true; + component.mask.set('XXX/X0/0000'); + component.hiddenInput.set(true); + component.showMaskTyped.set(true); equal('98765', '***/*5/____', fixture); equal('1234', '***/*_/____', fixture); equal('', '___/__/____', fixture); @@ -184,9 +183,9 @@ describe('Directive: Mask (Secure)', () => { })); it('hideInput with showMaskTyped mask=XXXX', () => { - component.mask = 'XXXX'; - component.hiddenInput = true; - component.showMaskTyped = true; + component.mask.set('XXXX'); + component.hiddenInput.set(true); + component.showMaskTyped.set(true); equal('1', '*___', fixture); equal('12', '**__', fixture); equal('123', '***_', fixture); @@ -194,9 +193,9 @@ describe('Directive: Mask (Secure)', () => { }); it('hideInput with showMaskTyped mask=XX-XX', () => { - component.mask = 'XX-XX'; - component.hiddenInput = true; - component.showMaskTyped = true; + component.mask.set('XX-XX'); + component.hiddenInput.set(true); + component.showMaskTyped.set(true); equal('1234', '**-**', fixture); }); @@ -206,11 +205,11 @@ describe('Directive: Mask (Secure)', () => { const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); fixture.detectChanges(); - component.mask = 'XXX-XX-XXXX'; - component.hiddenInput = true; + component.mask.set('XXX-XX-XXXX'); + component.hiddenInput.set(true); equal('1234', '***-*', fixture); fixture.detectChanges(); - component.hiddenInput = false; + component.hiddenInput.set(false); equal(inputTarget.value, '123-4', fixture, true); }); @@ -219,11 +218,11 @@ describe('Directive: Mask (Secure)', () => { const inputTarget: HTMLInputElement = debug.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); fixture.detectChanges(); - component.mask = 'XXX-XX-XXXX'; - component.hiddenInput = true; + component.mask.set('XXX-XX-XXXX'); + component.hiddenInput.set(true); equal('123456', '***-**-*', fixture); fixture.detectChanges(); - component.hiddenInput = false; + component.hiddenInput.set(false); equal(inputTarget.value, '123-45-6', fixture, true); }); @@ -232,12 +231,12 @@ describe('Directive: Mask (Secure)', () => { const inputTarget: HTMLInputElement = debug.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); fixture.detectChanges(); - component.mask = 'XXX/XX/XXXX'; - component.hiddenInput = true; + component.mask.set('XXX/XX/XXXX'); + component.hiddenInput.set(true); equal('123456789', '***/**/****', fixture); expect(component.form.value).toBe('123456789'); fixture.detectChanges(); - component.hiddenInput = false; + component.hiddenInput.set(false); equal(inputTarget.value, '123/45/6789', fixture, true); expect(component.form.value).toBe('123456789'); }); diff --git a/projects/ngx-mask-lib/src/test/separator-non-en-locale.spec.ts b/projects/ngx-mask-lib/src/test/separator-non-en-locale.spec.ts index 527fc9bb..f14503af 100644 --- a/projects/ngx-mask-lib/src/test/separator-non-en-locale.spec.ts +++ b/projects/ngx-mask-lib/src/test/separator-non-en-locale.spec.ts @@ -5,8 +5,7 @@ import { LOCALE_ID } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal, typeTest } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; import { By } from '@angular/platform-browser'; // FR locale uses comma as decimal marker @@ -25,38 +24,38 @@ describe('Separator: Mask with FR locale', () => { }); it('Should work right when reset decimalMarker', () => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.decimalMarker.set('.'); equal('1000000.00', '1 000 000.00', fixture); }); it('separator precision 2 with thousandSeparator (.) decimalMarker (,) for 12345.67', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); + component.decimalMarker.set('.'); equal('12,345.67', '12,345.67', fixture); }); it('separator precision 2 with thousandSeparator (.) decimalMarker (,) for 12345.67', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); + component.decimalMarker.set('.'); equal('12345.67', '12,345.67', fixture); }); it('check formControl value to be number when decimalMarker is dot', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ' '; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set(' '); + component.decimalMarker.set('.'); typeTest('12 345.67', fixture); expect(component.form.value).toBe('12345.67'); }); it('check formControl value to be number when decimalMarker is array', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ' '; - component.decimalMarker = ['.', ',']; + component.mask.set('separator.2'); + component.thousandSeparator.set(' '); + component.decimalMarker.set(['.', ',']); typeTest('12 345,67', fixture); expect(component.form.value).toBe('12345.67'); @@ -66,10 +65,10 @@ describe('Separator: Mask with FR locale', () => { }); it('should show - at input', fakeAsync(() => { - component.mask = 'separator.2'; - component.thousandSeparator = ' '; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + component.mask.set('separator.2'); + component.thousandSeparator.set(' '); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); diff --git a/projects/ngx-mask-lib/src/test/separator.spec.ts b/projects/ngx-mask-lib/src/test/separator.spec.ts index 1f2e8ea0..521abee4 100644 --- a/projects/ngx-mask-lib/src/test/separator.spec.ts +++ b/projects/ngx-mask-lib/src/test/separator.spec.ts @@ -5,9 +5,7 @@ import type { DebugElement } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal, typeTest } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; -import { initialConfig } from 'ngx-mask'; +import { initialConfig, NgxMaskDirective, provideNgxMask } from 'ngx-mask'; describe('Separator: Mask', () => { let fixture: ComponentFixture; @@ -24,113 +22,113 @@ describe('Separator: Mask', () => { }); it('separator for empty', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('', '', fixture); }); it('separator for 100', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('100', '100', fixture); }); it('separator for -100', () => { - component.mask = 'separator'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.allowNegativeNumbers.set(true); equal('-100', '-100', fixture); }); it('separator for 1000', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('1000', '1 000', fixture); }); it('separator for -1000', () => { - component.mask = 'separator'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.allowNegativeNumbers.set(true); equal('-1000', '-1 000', fixture); }); it('separator for 10000', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('10000', '10 000', fixture); }); it('separator for -10000', () => { - component.mask = 'separator'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.allowNegativeNumbers.set(true); equal('-10000', '-10 000', fixture); }); it('separator for -100000', () => { - component.mask = 'separator'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.allowNegativeNumbers.set(true); equal('-100000', '-100 000', fixture); }); it('separator for 100000', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('100000', '100 000', fixture); }); it('separator for 1000000', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('1000000', '1 000 000', fixture); }); it('separator for -1000000', () => { - component.mask = 'separator'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.allowNegativeNumbers.set(true); equal('-1000000', '-1 000 000', fixture); }); it('should limit separator to 1000', () => { - component.mask = 'separator'; - component.separatorLimit = '1000'; + component.mask.set('separator'); + component.separatorLimit.set('1000'); equal('1000000', '1 000', fixture); }); it('separator precision 2 for 1000000.00', () => { - component.mask = 'separator.2'; + component.mask.set('separator.2'); equal('1000000.00', '1 000 000.00', fixture); }); it('separator precision 2 for -1000000.00', () => { - component.mask = 'separator.2'; - component.allowNegativeNumbers = true; + component.mask.set('separator.2'); + component.allowNegativeNumbers.set(true); equal('-1000000.00', '-1 000 000.00', fixture); }); it('should limit separator with precision 2 to 10000', () => { - component.mask = 'separator.2'; - component.separatorLimit = '10000'; + component.mask.set('separator.2'); + component.separatorLimit.set('10000'); equal('1000000.00', '10 000.00', fixture); }); it('should limit separator with precision 2 to 10 000', () => { - component.mask = 'separator.2'; - component.separatorLimit = '10 000'; + component.mask.set('separator.2'); + component.separatorLimit.set('10 000'); equal('1000000.00', '10 000.00', fixture); }); it('separator precision 0 for 1000000.00', () => { - component.mask = 'separator.0'; + component.mask.set('separator.0'); equal('1000000.00', '1 000 000', fixture); }); it('separator precision 2 with 0 after point for 1000000.00', () => { - component.mask = 'separator.2'; + component.mask.set('separator.2'); equal('1000000.20', '1 000 000.20', fixture); }); it('separator.2 with suffix', () => { - component.mask = 'separator.2'; - component.suffix = '₽'; + component.mask.set('separator.2'); + component.suffix.set('₽'); equal('50', '50₽', fixture); equal('123 4', '1 234₽', fixture); equal('50.50', '50.50₽', fixture); }); it('separator for letters', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('a', '', fixture); equal('1a', '1', fixture); equal('1000a', '1 000', fixture); @@ -138,122 +136,122 @@ describe('Separator: Mask', () => { }); it('separator thousandSeparator . for 1000000', () => { - component.mask = 'separator'; - component.thousandSeparator = '.'; + component.mask.set('separator'); + component.thousandSeparator.set('.'); equal('1000000', '1.000.000', fixture); }); it('should not add any sperator if thousandSeparator set as empty string', () => { - component.mask = 'separator'; - component.thousandSeparator = ''; + component.mask.set('separator'); + component.thousandSeparator.set(''); equal('1000000', '1000000', fixture); }); it('should not accept more than one minus signal at the beginning of input for separator thousandSeparator . for --1000', () => { - component.mask = 'separator'; - component.thousandSeparator = '.'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.thousandSeparator.set('.'); + component.allowNegativeNumbers.set(true); equal('--1000', '-1.000', fixture); }); it('should not accept more than one minus signal for separator thousandSeparator . for -100-0000', () => { - component.mask = 'separator'; - component.thousandSeparator = '.'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.thousandSeparator.set('.'); + component.allowNegativeNumbers.set(true); equal('-100-0000', '-1.000.000', fixture); }); it('should limit separator thousandSeparator . to 100000', () => { - component.mask = 'separator'; - component.thousandSeparator = '.'; - component.separatorLimit = '100000'; + component.mask.set('separator'); + component.thousandSeparator.set('.'); + component.separatorLimit.set('100000'); equal('1000000', '100.000', fixture); }); it('should limit separator thousandSeparator . to -100000', () => { - component.mask = 'separator'; - component.thousandSeparator = '.'; - component.separatorLimit = '100000'; - component.allowNegativeNumbers = true; + component.mask.set('separator'); + component.thousandSeparator.set('.'); + component.separatorLimit.set('100000'); + component.allowNegativeNumbers.set(true); equal('-1000000', '-100.000', fixture); }); it('separator thousandSeparator . precision 2 for 1000000.00', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); equal('1000000,00', '1.000.000,00', fixture); }); it('separator thousandSeparator . precision 2 for -1000000.00', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; - component.allowNegativeNumbers = true; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); + component.allowNegativeNumbers.set(true); equal('-1000000,00', '-1.000.000,00', fixture); }); it('separator thousandSeparator . precision 2 with 0 after point for 1000000.00', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); equal('1000000,20', '1.000.000,20', fixture); }); it('separator thousandSeparator . precision 0 for 1000000.00', () => { - component.mask = 'separator.0'; - component.thousandSeparator = '.'; + component.mask.set('separator.0'); + component.thousandSeparator.set('.'); equal('1000000,00', '1.000.000', fixture); }); it('separator thousandSeparator , for 1000000', () => { - component.mask = 'separator'; - component.thousandSeparator = ','; + component.mask.set('separator'); + component.thousandSeparator.set(','); equal('1000000', '1,000,000', fixture); }); it('separator thousandSeparator , precision 2 for 1000000.00', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); equal('1000000.00', '1,000,000.00', fixture); }); it('separator thousandSeparator , precision 2 with 0 after point for 1000000.00', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); equal('1000000.20', '1,000,000.20', fixture); }); it('separator thousandSeparator , precision 0 for 1000000.00', () => { - component.mask = 'separator.0'; - component.thousandSeparator = ','; + component.mask.set('separator.0'); + component.thousandSeparator.set(','); equal('1000000.00', '1,000,000', fixture); }); it(`separator thousandSeparator ' for 1000000`, () => { - component.mask = 'separator'; - component.thousandSeparator = `'`; + component.mask.set('separator'); + component.thousandSeparator.set(`'`); equal('1000000', `1'000'000`, fixture); }); it(`separator thousandSeparator ' precision 2 for 1000000.00`, () => { - component.mask = 'separator.2'; - component.thousandSeparator = `'`; + component.mask.set('separator.2'); + component.thousandSeparator.set(`'`); equal('1000000.00', `1'000'000.00`, fixture); }); it(`separator thousandSeparator ' precision 2 with 0 after point for 1000000.00`, () => { - component.mask = 'separator.2'; - component.thousandSeparator = `'`; + component.mask.set('separator.2'); + component.thousandSeparator.set(`'`); equal('1000000.20', `1'000'000.20`, fixture); }); it(`separator thousandSeparator ' precision 0 for 1000000.00`, () => { - component.mask = 'separator.0'; - component.thousandSeparator = `'`; + component.mask.set('separator.0'); + component.thousandSeparator.set(`'`); equal('1000000.00', `1'000'000`, fixture); }); it('should not shift cursor for input in-between digits', () => { - component.mask = 'separator.0'; - component.thousandSeparator = ','; + component.mask.set('separator.0'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -268,8 +266,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(3); }); it('should not shift cursor for input in-between digits', () => { - component.mask = 'separator.0'; - component.thousandSeparator = '.'; + component.mask.set('separator.0'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -284,8 +282,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(3); }); it('should not shift cursor for input in-between digits', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -300,8 +298,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(3); }); it('should not shift cursor for input in-between digits', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -316,8 +314,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(3); }); it('should not shift cursor for input in-between digits', () => { - component.mask = 'separator'; - component.thousandSeparator = ','; + component.mask.set('separator'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -332,8 +330,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(3); }); it('should not shift cursor for input in-between digits', () => { - component.mask = 'separator'; - component.thousandSeparator = '.'; + component.mask.set('separator'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -349,8 +347,8 @@ describe('Separator: Mask', () => { }); it('should not shift cursor for backspace on in-between digits', () => { - component.mask = 'separator.0'; - component.thousandSeparator = ','; + component.mask.set('separator.0'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -371,8 +369,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(4); }); it('should not shift cursor for backspace on in-between digits', () => { - component.mask = 'separator.0'; - component.thousandSeparator = '.'; + component.mask.set('separator.0'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -394,8 +392,8 @@ describe('Separator: Mask', () => { }); it('should not shift cursor for backspace on in-between digits', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -416,8 +414,8 @@ describe('Separator: Mask', () => { expect(inputTarget.selectionStart).toEqual(7); }); it('should not shift cursor for backspace on in-between digits', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -439,8 +437,8 @@ describe('Separator: Mask', () => { }); it('should not shift cursor on backspace when result has no separator', () => { - component.mask = 'separator.0'; - component.thousandSeparator = ','; + component.mask.set('separator.0'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -462,8 +460,8 @@ describe('Separator: Mask', () => { }); it('caret should remain in position when deleting the first digit', () => { - component.mask = 'separator'; - component.thousandSeparator = ','; + component.mask.set('separator'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -484,9 +482,9 @@ describe('Separator: Mask', () => { }); it('cursor should move forward if the input starts with -, or 0, or 0.0, or 0.00, or 0.0000000', () => { - component.mask = 'separator.8'; - component.specialCharacters = [',', '.']; - component.allowNegativeNumbers = true; + component.mask.set('separator.8'); + component.specialCharacters.set([',', '.']); + component.allowNegativeNumbers.set(true); component.form.setValue(0.723); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; @@ -519,38 +517,38 @@ describe('Separator: Mask', () => { }); it('Should work right when reset decimalMarker', () => { - component.mask = 'separator.2'; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.decimalMarker.set(','); equal('1000000,00', '1 000 000,00', fixture); }); it('separator precision 2 with thousandSeparator (.) decimalMarker (,) for 12345.67', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); + component.decimalMarker.set(','); equal('12.345,67', '12.345,67', fixture); }); it('separator precision 2 with thousandSeparator (.) decimalMarker (,) for 12345.67', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); + component.decimalMarker.set(','); equal('12345,67', '12.345,67', fixture); }); it('check formControl value to be number when decimalMarker is comma', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ' '; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(' '); + component.decimalMarker.set(','); typeTest('12 345,67', fixture); expect(component.form.value).toBe('12345.67'); }); it('check formControl value to be number when decimalMarker is array', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ' '; - component.decimalMarker = ['.', ',']; + component.mask.set('separator.2'); + component.thousandSeparator.set(' '); + component.decimalMarker.set(['.', ',']); typeTest('12 345,67', fixture); expect(component.form.value).toBe('12345.67'); @@ -560,8 +558,8 @@ describe('Separator: Mask', () => { }); it('right handle character after first 0 value', () => { - component.mask = 'separator'; - component.decimalMarker = ','; + component.mask.set('separator'); + component.decimalMarker.set(','); equal('0', '0', fixture); equal('0,', '0,', fixture); equal('0 ', '0', fixture); @@ -570,7 +568,7 @@ describe('Separator: Mask', () => { equal('0@', '0', fixture); // TODO(inepipenko): strange thet return 0. // equal('0.', '0', fixture); - component.decimalMarker = '.'; + component.decimalMarker.set('.'); equal('0', '0', fixture); equal('0.', '0.', fixture); equal('0 ', '0', fixture); @@ -578,7 +576,7 @@ describe('Separator: Mask', () => { equal('0s', '0', fixture); equal('0@', '0', fixture); equal('0,', '0.', fixture); - component.decimalMarker = ['.', ',']; + component.decimalMarker.set(['.', ',']); equal('0', '0', fixture); equal('0.', '0.', fixture); equal('0,', '0.', fixture); @@ -589,8 +587,8 @@ describe('Separator: Mask', () => { }); it('should add trailing zero when separator.1 and leadZero = true', fakeAsync(() => { - component.mask = 'separator.1'; - component.leadZero = true; + component.mask.set('separator.1'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -614,8 +612,8 @@ describe('Separator: Mask', () => { })); it('should not modify value with one decimal when separator.1 and leadZero = true', fakeAsync(() => { - component.mask = 'separator.1'; - component.leadZero = true; + component.mask.set('separator.1'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -639,8 +637,8 @@ describe('Separator: Mask', () => { })); it('should display zeros at the end separator2', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; + component.mask.set('separator.2'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -712,10 +710,10 @@ describe('Separator: Mask', () => { })); it('should display zeros at the end separator2', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; - component.thousandSeparator = ','; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.leadZero.set(true); + component.thousandSeparator.set(','); + component.decimalMarker.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -759,8 +757,8 @@ describe('Separator: Mask', () => { })); it('should display zeros at the end separator3', fakeAsync(() => { - component.mask = 'separator.3'; - component.leadZero = true; + component.mask.set('separator.3'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -828,10 +826,10 @@ describe('Separator: Mask', () => { })); it('should display zeros at the end separator3', fakeAsync(() => { - component.mask = 'separator.3'; - component.leadZero = true; - component.thousandSeparator = ','; - component.decimalMarker = '.'; + component.mask.set('separator.3'); + component.leadZero.set(true); + component.thousandSeparator.set(','); + component.decimalMarker.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -875,10 +873,10 @@ describe('Separator: Mask', () => { })); it('should display zeros at the end separator2', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; - component.thousandSeparator = '.'; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.leadZero.set(true); + component.thousandSeparator.set('.'); + component.decimalMarker.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -922,10 +920,10 @@ describe('Separator: Mask', () => { })); it('should display zeros at the end separator3', fakeAsync(() => { - component.mask = 'separator.3'; - component.leadZero = true; - component.thousandSeparator = '.'; - component.decimalMarker = ','; + component.mask.set('separator.3'); + component.leadZero.set(true); + component.thousandSeparator.set('.'); + component.decimalMarker.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -969,9 +967,9 @@ describe('Separator: Mask', () => { })); it('should display only 9 separator.2', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); + component.decimalMarker.set('.'); equal('999999999999999', '999,999,999,999,999', fixture); expect(component.form.value).toBe('999999999999999'); @@ -984,9 +982,9 @@ describe('Separator: Mask', () => { }); it('should display only 9 separator.3', () => { - component.mask = 'separator.3'; - component.thousandSeparator = ','; - component.decimalMarker = '.'; + component.mask.set('separator.3'); + component.thousandSeparator.set(','); + component.decimalMarker.set('.'); equal('999999999999999', '999,999,999,999,999', fixture); expect(component.form.value).toBe('999999999999999'); @@ -1000,8 +998,9 @@ describe('Separator: Mask', () => { equal('999999999999999.999', '999,999,999,999,999.999', fixture); expect(component.form.value).toBe('999999999999999.999'); }); + it('should keep the cursor position after deleting a character', () => { - component.mask = 'separator.2'; + component.mask.set('separator.2'); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '123 456'; inputElement.dispatchEvent(new Event('input')); @@ -1017,8 +1016,8 @@ describe('Separator: Mask', () => { }); it('should change formValue separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; + component.mask.set('separator.2'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1033,8 +1032,8 @@ describe('Separator: Mask', () => { })); it('should change formValue separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.leadZero = true; + component.mask.set('separator.3'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1049,9 +1048,9 @@ describe('Separator: Mask', () => { })); it('separator.8 should return number value', fakeAsync(() => { - component.mask = 'separator.8'; - component.thousandSeparator = '.'; - component.decimalMarker = ','; + component.mask.set('separator.8'); + component.thousandSeparator.set('.'); + component.decimalMarker.set(','); equal('12,34', '12,34', fixture); tick(); @@ -1061,9 +1060,9 @@ describe('Separator: Mask', () => { })); it('should display value in input with decimalMarker , and leadZero with separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.leadZero.set(true); + component.decimalMarker.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1087,9 +1086,9 @@ describe('Separator: Mask', () => { })); it('should display value in input with decimalMarker , and leadZero with separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.leadZero = true; - component.decimalMarker = ','; + component.mask.set('separator.3'); + component.leadZero.set(true); + component.decimalMarker.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1113,10 +1112,10 @@ describe('Separator: Mask', () => { })); it('should display value in input with decimalMarker , and leadZero with separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.leadZero = true; - component.decimalMarker = ','; - component.thousandSeparator = '.'; + component.mask.set('separator.3'); + component.leadZero.set(true); + component.decimalMarker.set(','); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1140,10 +1139,10 @@ describe('Separator: Mask', () => { })); it('should display value in input with decimalMarker , and leadZero with separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; - component.decimalMarker = ','; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.leadZero.set(true); + component.decimalMarker.set(','); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1166,152 +1165,152 @@ describe('Separator: Mask', () => { expect(inputTarget.value).toBe('3.000,40'); })); - it('should not allow add two zeros to inputValue', fakeAsync(() => { - component.mask = 'separator.2'; - component.leadZero = true; - component.decimalMarker = ','; - component.thousandSeparator = '.'; - component.allowNegativeNumbers = true; + it('should not allow add two zeros to inputValue', () => { + component.mask.set('separator.2'); + component.leadZero.set(true); + component.decimalMarker.set(','); + component.thousandSeparator.set('.'); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-00', '-0,0', fixture); - })); + }); - it('should not allow add two zeros to inputValue', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; - component.thousandSeparator = ','; - component.allowNegativeNumbers = true; + it('should not allow add two zeros to inputValue', () => { + component.mask.set('separator.2'); + component.decimalMarker.set('.'); + component.thousandSeparator.set(','); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-00', '-0.0', fixture); - })); + }); - it('should not allow add two zeros to inputValue', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = ','; - component.thousandSeparator = '.'; - component.allowNegativeNumbers = true; + it('should not allow add two zeros to inputValue', () => { + component.mask.set('separator.2'); + component.decimalMarker.set(','); + component.thousandSeparator.set('.'); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-00', '-0,0', fixture); - })); + }); - it('should not allow add two zeros to inputValue', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = ','; - component.thousandSeparator = ' '; - component.allowNegativeNumbers = true; + it('should not allow add two zeros to inputValue', () => { + component.mask.set('separator.2'); + component.decimalMarker.set(','); + component.thousandSeparator.set(' '); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-00', '-0,0', fixture); - })); + }); - it('should allow minus after change it to true', fakeAsync(() => { - component.mask = 'separator.2'; - component.allowNegativeNumbers = false; + it('should allow minus after change it to true', () => { + component.mask.set('separator.2'); + component.allowNegativeNumbers.set(false); fixture.detectChanges(); equal('-1234', '1 234', fixture); - component.allowNegativeNumbers = true; + component.allowNegativeNumbers.set(true); equal('-1234', '-1 234', fixture); - })); + }); - it('should change value in formControl mask separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.allowNegativeNumbers = true; - component.specialCharacters = [...initialConfig.specialCharacters]; + it('should change value in formControl mask separator.2', () => { + component.mask.set('separator.2'); + component.allowNegativeNumbers.set(true); + component.specialCharacters.set([...initialConfig.specialCharacters]); fixture.detectChanges(); equal('-1234.10', '-1 234.10', fixture); expect(component.form.value).toBe('-1234.10'); - })); + }); - it('should change value in formControl mask separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.allowNegativeNumbers = true; - component.specialCharacters = [...initialConfig.specialCharacters]; + it('should change value in formControl mask separator.3', () => { + component.mask.set('separator.3'); + component.allowNegativeNumbers.set(true); + component.specialCharacters.set([...initialConfig.specialCharacters]); fixture.detectChanges(); equal('-1234.567', '-1 234.567', fixture); expect(component.form.value).toBe('-1234.567'); - })); + }); - it('should change value in formControl mask separator.1', fakeAsync(() => { - component.mask = 'separator.1'; - component.allowNegativeNumbers = true; - component.specialCharacters = [...initialConfig.specialCharacters]; + it('should change value in formControl mask separator.1', () => { + component.mask.set('separator.1'); + component.allowNegativeNumbers.set(true); + component.specialCharacters.set([...initialConfig.specialCharacters]); fixture.detectChanges(); equal('-1234.9', '-1 234.9', fixture); expect(component.form.value).toBe('-1234.9'); - })); + }); - it('should change value in formControl mask separator.0', fakeAsync(() => { - component.mask = 'separator.0'; - component.allowNegativeNumbers = true; - component.specialCharacters = [...initialConfig.specialCharacters]; + it('should change value in formControl mask separator.0', () => { + component.mask.set('separator.0'); + component.allowNegativeNumbers.set(true); + component.specialCharacters.set([...initialConfig.specialCharacters]); fixture.detectChanges(); equal('-1234', '-1 234', fixture); expect(component.form.value).toBe('-1234'); - })); + }); - it('should change value if user star from zero separator.0', fakeAsync(() => { - component.mask = 'separator.0'; + it('should change value if user star from zero separator.0', () => { + component.mask.set('separator.0'); fixture.detectChanges(); equal('03', '3', fixture); equal('034', '34', fixture); - })); + }); - it('should change value if user star from zero separator.1', fakeAsync(() => { - component.mask = 'separator.1'; - component.decimalMarker = '.'; + it('should change value if user star from zero separator.1', () => { + component.mask.set('separator.1'); + component.decimalMarker.set('.'); fixture.detectChanges(); equal('03', '0.3', fixture); equal('034', '0.3', fixture); equal('.3', '0.3', fixture); equal('.34', '0.3', fixture); - })); + }); - it('should change value if user star from zero separator.1', fakeAsync(() => { - component.mask = 'separator.1'; - component.decimalMarker = ','; + it('should change value if user star from zero separator.1', () => { + component.mask.set('separator.1'); + component.decimalMarker.set(','); fixture.detectChanges(); equal('03', '0,3', fixture); equal('034', '0,3', fixture); equal(',3', '0,3', fixture); equal(',34', '0,3', fixture); - })); + }); - it('should change value if user star from zero separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; + it('should change value if user star from zero separator.2', () => { + component.mask.set('separator.2'); + component.decimalMarker.set('.'); fixture.detectChanges(); equal('03', '0.3', fixture); equal('034', '0.34', fixture); equal('.3', '0.3', fixture); equal('.34', '0.34', fixture); - })); + }); - it('should change value if user star from zero separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = ','; + it('should change value if user star from zero separator.2', () => { + component.mask.set('separator.2'); + component.decimalMarker.set(','); fixture.detectChanges(); equal('03', '0,3', fixture); equal('034', '0,34', fixture); equal(',3', '0,3', fixture); equal(',34', '0,34', fixture); - })); + }); - it('should change value if user star from zero separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.decimalMarker = '.'; + it('should change value if user star from zero separator.3', () => { + component.mask.set('separator.3'); + component.decimalMarker.set('.'); fixture.detectChanges(); equal('03', '0.3', fixture); @@ -1319,11 +1318,11 @@ describe('Separator: Mask', () => { equal('.3', '0.3', fixture); equal('.34', '0.34', fixture); equal('.345', '0.345', fixture); - })); + }); - it('should change value if user star from zero separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.decimalMarker = ','; + it('should change value if user star from zero separator.3', () => { + component.mask.set('separator.3'); + component.decimalMarker.set(','); fixture.detectChanges(); equal('03', '0,3', fixture); @@ -1331,69 +1330,69 @@ describe('Separator: Mask', () => { equal(',3', '0,3', fixture); equal(',34', '0,34', fixture); equal(',345', '0,345', fixture); - })); + }); - it('should change value if user star from zero separator.0 with allowNegativeNumber', fakeAsync(() => { - component.mask = 'separator.0'; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.0 with allowNegativeNumber', () => { + component.mask.set('separator.0'); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-3', fixture); equal('-034', '-34', fixture); - })); + }); - it('should change value if user star from zero separator.1 with allowNegativeNumber', fakeAsync(() => { - component.mask = 'separator.1'; - component.decimalMarker = '.'; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.1 with allowNegativeNumber', () => { + component.mask.set('separator.1'); + component.decimalMarker.set('.'); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-0.3', fixture); equal('-034', '-0.3', fixture); equal('-.3', '-0.3', fixture); equal('-.34', '-0.3', fixture); - })); + }); - it('should change value if user star from zero separator.1 with allowNegativeNumber decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.1'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.1 with allowNegativeNumber decimalMarker= ,', () => { + component.mask.set('separator.1'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-0,3', fixture); equal('-034', '-0,3', fixture); equal('-,3', '-0,3', fixture); equal('-,34', '-0,3', fixture); - })); + }); - it('should change value if user star from zero separator.2 with allowNegativeNumber', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.2 with allowNegativeNumber', () => { + component.mask.set('separator.2'); + component.decimalMarker.set('.'); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-0.3', fixture); equal('-034', '-0.34', fixture); equal('-.3', '-0.3', fixture); equal('-.34', '-0.34', fixture); - })); + }); - it('should change value if user star from zero separator.2 with allowNegativeNumber', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.2 with allowNegativeNumber', () => { + component.mask.set('separator.2'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-0,3', fixture); equal('-034', '-0,34', fixture); equal('-,3', '-0,3', fixture); equal('-,34', '-0,34', fixture); - })); + }); - it('should change value if user star from zero separator.3 with allowNegativeNumber', fakeAsync(() => { - component.mask = 'separator.3'; - component.decimalMarker = '.'; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.3 with allowNegativeNumber', () => { + component.mask.set('separator.3'); + component.decimalMarker.set('.'); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-0.3', fixture); @@ -1402,12 +1401,12 @@ describe('Separator: Mask', () => { equal('-.3', '-0.3', fixture); equal('-.34', '-0.34', fixture); equal('-.345', '-0.345', fixture); - })); + }); - it('should change value if user star from zero separator.3 with allowNegativeNumber', fakeAsync(() => { - component.mask = 'separator.3'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; + it('should change value if user star from zero separator.3 with allowNegativeNumber', () => { + component.mask.set('separator.3'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); fixture.detectChanges(); equal('-03', '-0,3', fixture); @@ -1416,65 +1415,65 @@ describe('Separator: Mask', () => { equal('-,3', '-0,3', fixture); equal('-,34', '-0,34', fixture); equal('-,345', '-0,345', fixture); - })); + }); - it('should change value if user star from zero separator.1 with allowNegativeNumber leadZero decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.1'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; - component.leadZero = true; + it('should change value if user star from zero separator.1 with allowNegativeNumber leadZero decimalMarker= ,', () => { + component.mask.set('separator.1'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); + component.leadZero.set(true); fixture.detectChanges(); equal('-03', '-0,3', fixture); equal('-034', '-0,3', fixture); equal('-,3', '-0,3', fixture); equal('-,34', '-0,3', fixture); - })); + }); - it('should change value if user star from zero separator.1 with allowNegativeNumber leadZero decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.1'; - component.decimalMarker = '.'; - component.allowNegativeNumbers = true; - component.leadZero = true; + it('should change value if user star from zero separator.1 with allowNegativeNumber leadZero decimalMarker= ,', () => { + component.mask.set('separator.1'); + component.decimalMarker.set('.'); + component.allowNegativeNumbers.set(true); + component.leadZero.set(true); fixture.detectChanges(); equal('-03', '-0.3', fixture); equal('-034', '-0.3', fixture); equal('-.3', '-0.3', fixture); equal('-.34', '-0.3', fixture); - })); + }); - it('should change value if user star from zero separator.1 with allowNegativeNumber leadZero decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; - component.leadZero = true; + it('should change value if user star from zero separator.1 with allowNegativeNumber leadZero decimalMarker= ,', () => { + component.mask.set('separator.2'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); + component.leadZero.set(true); fixture.detectChanges(); equal('-03', '-0,3', fixture); equal('-034', '-0,34', fixture); equal('-,3', '-0,3', fixture); equal('-,34', '-0,34', fixture); - })); + }); - it('should change value if user star from zero separator.2 with allowNegativeNumber leadZero decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; - component.allowNegativeNumbers = true; - component.leadZero = true; + it('should change value if user star from zero separator.2 with allowNegativeNumber leadZero decimalMarker= ,', () => { + component.mask.set('separator.2'); + component.decimalMarker.set('.'); + component.allowNegativeNumbers.set(true); + component.leadZero.set(true); fixture.detectChanges(); equal('-03', '-0.3', fixture); equal('-034', '-0.34', fixture); equal('-.3', '-0.3', fixture); equal('-.34', '-0.34', fixture); - })); + }); - it('should change value if user star from zero separator.3 with allowNegativeNumber leadZero decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.3'; - component.decimalMarker = ','; - component.allowNegativeNumbers = true; - component.leadZero = true; + it('should change value if user star from zero separator.3 with allowNegativeNumber leadZero decimalMarker= ,', () => { + component.mask.set('separator.3'); + component.decimalMarker.set(','); + component.allowNegativeNumbers.set(true); + component.leadZero.set(true); fixture.detectChanges(); equal('-03', '-0,3', fixture); @@ -1482,13 +1481,13 @@ describe('Separator: Mask', () => { equal('-,3', '-0,3', fixture); equal('-,34', '-0,34', fixture); equal('-,345', '-0,345', fixture); - })); + }); - it('should change value if user star from zero separator.3 with allowNegativeNumber leadZero decimalMarker= ,', fakeAsync(() => { - component.mask = 'separator.3'; - component.decimalMarker = '.'; - component.allowNegativeNumbers = true; - component.leadZero = true; + it('should change value if user star from zero separator.3 with allowNegativeNumber leadZero decimalMarker= ,', () => { + component.mask.set('separator.3'); + component.decimalMarker.set('.'); + component.allowNegativeNumbers.set(true); + component.leadZero.set(true); fixture.detectChanges(); equal('-03', '-0.3', fixture); @@ -1496,11 +1495,11 @@ describe('Separator: Mask', () => { equal('-.3', '-0.3', fixture); equal('-.34', '-0.34', fixture); equal('-.345', '-0.345', fixture); - })); + }); it('separator.2 thousandSeparator = . should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1515,8 +1514,8 @@ describe('Separator: Mask', () => { })); it('separator.3 thousandSeparator = . should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.mask = 'separator.3'; - component.thousandSeparator = '.'; + component.mask.set('separator.3'); + component.thousandSeparator.set('.'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1530,8 +1529,8 @@ describe('Separator: Mask', () => { })); it('separator.1 thousandSeparator = . should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.thousandSeparator = '.'; - component.mask = 'separator.1'; + component.thousandSeparator.set('.'); + component.mask.set('separator.1'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1547,8 +1546,8 @@ describe('Separator: Mask', () => { it('separator.2 thousandSeparator = , should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; - component.mask = 'separator.2'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); fixture.detectChanges(); @@ -1559,8 +1558,8 @@ describe('Separator: Mask', () => { })); it('separator.3 thousandSeparator = , should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.mask = 'separator.3'; - component.thousandSeparator = ','; + component.mask.set('separator.3'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1573,8 +1572,8 @@ describe('Separator: Mask', () => { })); it('separator.1 thousandSeparator = , should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.mask = 'separator.1'; - component.thousandSeparator = ','; + component.mask.set('separator.1'); + component.thousandSeparator.set(','); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1587,9 +1586,9 @@ describe('Separator: Mask', () => { })); it('separator.2 thousandSeparator = . leadZero should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; - component.leadZero = true; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -1603,9 +1602,9 @@ describe('Separator: Mask', () => { })); it('separator.3 thousandSeparator = . leadZero should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.mask = 'separator.3'; - component.thousandSeparator = '.'; - component.leadZero = true; + component.mask.set('separator.3'); + component.thousandSeparator.set('.'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; @@ -1620,9 +1619,9 @@ describe('Separator: Mask', () => { })); it('separator.1 thousandSeparator = . leadZero should display correct value if decimalMarker is array 12345.67', fakeAsync(() => { - component.thousandSeparator = '.'; - component.mask = 'separator.1'; - component.leadZero = true; + component.thousandSeparator.set('.'); + component.mask.set('separator.1'); + component.leadZero.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; @@ -1636,42 +1635,42 @@ describe('Separator: Mask', () => { }); })); - it('should work when decimalMarker have default value separator.2', fakeAsync(() => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; + it('should work when decimalMarker have default value separator.2', () => { + component.mask.set('separator.2'); + component.thousandSeparator.set(','); fixture.detectChanges(); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); equal('1234', '1,234', fixture); - })); + }); - it('should work when decimalMarker have default value separator.3', fakeAsync(() => { - component.mask = 'separator.3'; - component.thousandSeparator = ','; + it('should work when decimalMarker have default value separator.3', () => { + component.mask.set('separator.3'); + component.thousandSeparator.set(','); fixture.detectChanges(); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); equal('1234', '1,234', fixture); - })); + }); - it('should work when decimalMarker have default value separator.1', fakeAsync(() => { - component.mask = 'separator.3'; - component.thousandSeparator = ','; + it('should work when decimalMarker have default value separator.1', () => { + component.mask.set('separator.3'); + component.thousandSeparator.set(','); fixture.detectChanges(); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); equal('1234', '1,234', fixture); - })); + }); it('should not delete decimalMarker ,', () => { - component.mask = 'separator.2'; - component.decimalMarker = ','; + component.mask.set('separator.2'); + component.decimalMarker.set(','); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '1,23'; @@ -1691,8 +1690,8 @@ describe('Separator: Mask', () => { }); it('should not delete decimalMarker .', () => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; + component.mask.set('separator.2'); + component.decimalMarker.set('.'); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '12.23'; @@ -1712,9 +1711,9 @@ describe('Separator: Mask', () => { }); it('should change position when click backspace thousandSeparator = .', () => { - component.mask = 'separator.2'; - component.decimalMarker = ','; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.decimalMarker.set(','); + component.thousandSeparator.set('.'); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '1.234.567,89'; @@ -1740,9 +1739,9 @@ describe('Separator: Mask', () => { }); it('should change position when click backspace thousandSeparator = ,', () => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.decimalMarker.set('.'); + component.thousandSeparator.set(','); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '1,234,567.89'; @@ -1768,9 +1767,9 @@ describe('Separator: Mask', () => { }); it('should change position when click backspace thousandSeparator = ', () => { - component.mask = 'separator.2'; - component.decimalMarker = '.'; - component.thousandSeparator = ' '; + component.mask.set('separator.2'); + component.decimalMarker.set('.'); + component.thousandSeparator.set(' '); const inputElement = fixture.nativeElement.querySelector('input'); inputElement.value = '1 234 567.89'; @@ -1796,10 +1795,10 @@ describe('Separator: Mask', () => { }); it('should show correct value with separator.9', fakeAsync(() => { - component.mask = 'separator.9'; - component.decimalMarker = '.'; - component.leadZero = true; - component.separatorLimit = '10'; + component.mask.set('separator.9'); + component.decimalMarker.set('.'); + component.leadZero.set(true); + component.separatorLimit.set('10'); fixture.detectChanges(); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); @@ -1816,10 +1815,10 @@ describe('Separator: Mask', () => { })); it('should show correct value with separator.10', fakeAsync(() => { - component.mask = 'separator.10'; - component.decimalMarker = '.'; - component.leadZero = true; - component.separatorLimit = '10'; + component.mask.set('separator.10'); + component.decimalMarker.set('.'); + component.leadZero.set(true); + component.separatorLimit.set('10'); fixture.detectChanges(); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); @@ -1836,7 +1835,7 @@ describe('Separator: Mask', () => { })); it('should support big numbers with separator', () => { - component.mask = 'separator'; + component.mask.set('separator'); equal('12345678910111215', '12 345 678 910 111 215', fixture); expect(component.form.value).toBe('12345678910111215'); @@ -1845,7 +1844,7 @@ describe('Separator: Mask', () => { }); it('should support big numbers with separator 2', () => { - component.mask = 'separator.2'; + component.mask.set('separator.2'); equal('12345678910111215', '12 345 678 910 111 215', fixture); expect(component.form.value).toBe('12345678910111215'); @@ -1854,8 +1853,8 @@ describe('Separator: Mask', () => { }); it('should support big numbers with separator 2 thousand =.', () => { - component.mask = 'separator.2'; - component.thousandSeparator = '.'; + component.mask.set('separator.2'); + component.thousandSeparator.set('.'); equal('12345678910111215', '12.345.678.910.111.215', fixture); expect(component.form.value).toBe('12345678910111215'); @@ -1864,8 +1863,8 @@ describe('Separator: Mask', () => { }); it('should support big numbers with separator 2 thousand =,', () => { - component.mask = 'separator.2'; - component.thousandSeparator = ','; + component.mask.set('separator.2'); + component.thousandSeparator.set(','); equal('12345678910111215', '12,345,678,910,111,215', fixture); expect(component.form.value).toBe('12345678910111215'); diff --git a/projects/ngx-mask-lib/src/test/show-mask-typed.spec.ts b/projects/ngx-mask-lib/src/test/show-mask-typed.spec.ts index 9008dc9d..ac8cce81 100644 --- a/projects/ngx-mask-lib/src/test/show-mask-typed.spec.ts +++ b/projects/ngx-mask-lib/src/test/show-mask-typed.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; import type { DebugElement } from '@angular/core'; import { By } from '@angular/platform-browser'; @@ -24,77 +23,103 @@ describe('Directive: Mask', () => { }); it('should clear if not match the mask!!!!', () => { - component.mask = '(000) 000-0000'; - component.showMaskTyped = true; + component.mask.set('(000) 000-0000'); + component.showMaskTyped.set(true); equal('', '(___) ___-____', fixture); equal('2345678', '(234) 567-8___', fixture); - component.prefix = '+7'; - component.showMaskTyped = true; + component.prefix.set('+7'); + component.showMaskTyped.set(true); equal('', '+7(___) ___-____', fixture); equal('2345678', '+7(234) 567-8___', fixture); }); it('should clear if not match the mask!!!!', () => { - component.mask = 'A{5}-A{2}'; - component.showMaskTyped = true; + component.mask.set('A{5}-A{2}'); + component.showMaskTyped.set(true); equal('', '_____-__', fixture); equal('aaa', 'aaa__-__', fixture); equal('aaaaaaa', 'aaaaa-aa', fixture); }); it('Mask with optional pattern 9999', () => { - component.mask = '(000) 000-0000 ext. 999999'; - component.showMaskTyped = true; - component.specialCharacters = ['e', 'x', 't', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 ext. 999999'); + component.showMaskTyped.set(true); + component.specialCharacters.set(['e', 'x', 't', ' ', '(', ')', '-', '.']); equal('9871234223 ext. 123022', '(987) 123-4223 ext. 123022', fixture); - component.mask = '(000) 000-0000 testing. 999999'; - component.showMaskTyped = true; - component.specialCharacters = ['t', 'e', 's', 't', 'i', 'n', 'g', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 testing. 999999'); + component.showMaskTyped.set(true); + component.specialCharacters.set([ + 't', + 'e', + 's', + 't', + 'i', + 'n', + 'g', + ' ', + '(', + ')', + '-', + '.', + ]); equal('1234567890 testing. 123456', '(123) 456-7890 testing. 123456', fixture); - component.mask = '(000) 000-0000 prefix. 999'; - component.showMaskTyped = true; - component.prefix = '+7'; - component.specialCharacters = ['p', 'r', 'e', 'f', 'i', 'x', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 prefix. 999'); + component.showMaskTyped.set(true); + component.prefix.set('+7'); + component.specialCharacters.set(['p', 'r', 'e', 'f', 'i', 'x', ' ', '(', ')', '-', '.']); equal('1234567890 prefix. 345', '+7(123) 456-7890 prefix. 345', fixture); - component.mask = '(000) 000-0000 cv. 999'; - component.showMaskTyped = true; - component.prefix = 'card. '; - component.specialCharacters = ['c', 'v', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 cv. 999'); + component.showMaskTyped.set(true); + component.prefix.set('card. '); + component.specialCharacters.set(['c', 'v', ' ', '(', ')', '-', '.']); equal('1234567890 cv. 345', 'card. (123) 456-7890 cv. 345', fixture); }); it('Mask with optional pattern 00000', () => { - component.mask = '(000) 000-0000 ext. 000000'; - component.showMaskTyped = true; - component.specialCharacters = ['e', 'x', 't', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 ext. 000000'); + component.showMaskTyped.set(true); + component.specialCharacters.set(['e', 'x', 't', ' ', '(', ')', '-', '.']); equal('9871234223 ext. 123022', '(987) 123-4223 ext. 123022', fixture); - component.mask = '(000) 000-0000 testing. 00000'; - component.showMaskTyped = true; - component.specialCharacters = ['t', 'e', 's', 't', 'i', 'n', 'g', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 testing. 00000'); + component.showMaskTyped.set(true); + component.specialCharacters.set([ + 't', + 'e', + 's', + 't', + 'i', + 'n', + 'g', + ' ', + '(', + ')', + '-', + '.', + ]); equal('1234567890 testing. 12345', '(123) 456-7890 testing. 12345', fixture); - component.mask = '(000) 000-0000 prefix. 000'; - component.showMaskTyped = true; - component.prefix = '+7'; - component.specialCharacters = ['p', 'r', 'e', 'f', 'i', 'x', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 prefix. 000'); + component.showMaskTyped.set(true); + component.prefix.set('+7'); + component.specialCharacters.set(['p', 'r', 'e', 'f', 'i', 'x', ' ', '(', ')', '-', '.']); equal('1234567890 prefix. 345', '+7(123) 456-7890 prefix. 345', fixture); - component.mask = '(000) 000-0000 cv. 000'; - component.showMaskTyped = true; - component.prefix = 'card. '; - component.specialCharacters = ['c', 'v', ' ', '(', ')', '-', '.']; + component.mask.set('(000) 000-0000 cv. 000'); + component.showMaskTyped.set(true); + component.prefix.set('card. '); + component.specialCharacters.set(['c', 'v', ' ', '(', ')', '-', '.']); equal('1234567890 cv. 134', 'card. (123) 456-7890 cv. 134', fixture); }); // TODO(inepipenko) for issue #880 xit('should work right with security input', () => { - component.mask = '000-0X-XXXX'; - component.showMaskTyped = true; + component.mask.set('000-0X-XXXX'); + component.showMaskTyped.set(true); equal('', '___-__-____', fixture); equal('123', '123-__-____', fixture); equal('12345', '123-4*-____', fixture); @@ -106,9 +131,9 @@ describe('Directive: Mask', () => { }); it('showMaskTyped && placeholder XXXXX-YYYY', () => { - component.showMaskTyped = true; - component.placeHolderCharacter = 'XXXXX-YYYY'; - component.mask = '00000-0000'; + component.showMaskTyped.set(true); + component.placeHolderCharacter.set('XXXXX-YYYY'); + component.mask.set('00000-0000'); equal('1', '1XXXX-YYYY', fixture); equal('12', '12XXX-YYYY', fixture); equal('123', '123XX-YYYY', fixture); @@ -121,9 +146,9 @@ describe('Directive: Mask', () => { }); it('showMaskTyped && placeholder 00/00/0000', () => { - component.showMaskTyped = true; - component.placeHolderCharacter = 'dd/mm/yyyy'; - component.mask = '00/00/0000'; + component.showMaskTyped.set(true); + component.placeHolderCharacter.set('dd/mm/yyyy'); + component.mask.set('00/00/0000'); equal('1', '1d/mm/yyyy', fixture); equal('12', '12/mm/yyyy', fixture); equal('123', '12/3m/yyyy', fixture); @@ -135,10 +160,10 @@ describe('Directive: Mask', () => { }); it('should work with showMaskTyped', () => { - component.mask = '000/00000'; - component.prefix = '06'; - component.dropSpecialCharacters = false; - component.showMaskTyped = true; + component.mask.set('000/00000'); + component.prefix.set('06'); + component.dropSpecialCharacters.set(false); + component.showMaskTyped.set(true); equal('', '06___/_____', fixture); equal('1', '061__/_____', fixture); equal('12', '0612_/_____', fixture); @@ -151,8 +176,8 @@ describe('Directive: Mask', () => { }); it('should work with showMaskTyped', () => { - component.mask = '000/00000'; - component.prefix = '06'; + component.mask.set('000/00000'); + component.prefix.set('06'); equal('1', '061', fixture); equal('12', '0612', fixture); equal('123', '06123', fixture); @@ -164,8 +189,8 @@ describe('Directive: Mask', () => { }); it('should work with showMaskTyped 000/00000', async () => { - component.mask = '000/00000'; - component.showMaskTyped = false; + component.mask.set('000/00000'); + component.showMaskTyped.set(false); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -175,7 +200,7 @@ describe('Directive: Mask', () => { equal('12', '12', fixture); equal('123', '123', fixture); expect(inputTarget.selectionStart).toBe(3); - component.showMaskTyped = true; + component.showMaskTyped.set(true); inputTarget.focus(); fixture.detectChanges(); @@ -184,9 +209,9 @@ describe('Directive: Mask', () => { }); it('should work with showMaskTyped 000/00000 with prefix', async () => { - component.mask = '000/00000'; - component.prefix = '+38 '; - component.showMaskTyped = false; + component.mask.set('000/00000'); + component.prefix.set('+38 '); + component.showMaskTyped.set(false); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -196,7 +221,7 @@ describe('Directive: Mask', () => { equal('+38 12', '+38 12', fixture); equal('+38 123', '+38 123', fixture); expect(inputTarget.selectionStart).toBe(7); - component.showMaskTyped = true; + component.showMaskTyped.set(true); inputTarget.focus(); fixture.detectChanges(); diff --git a/projects/ngx-mask-lib/src/test/test-sufix.spec.ts b/projects/ngx-mask-lib/src/test/test-sufix.spec.ts index 89590bde..2d760b4f 100644 --- a/projects/ngx-mask-lib/src/test/test-sufix.spec.ts +++ b/projects/ngx-mask-lib/src/test/test-sufix.spec.ts @@ -5,8 +5,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { provideNgxMask, NgxMaskDirective } from 'ngx-mask'; describe('Directive: Mask (Suffix)', () => { let fixture: ComponentFixture; @@ -23,24 +22,24 @@ describe('Directive: Mask (Suffix)', () => { }); it('should clear if not match the mask!!!!', () => { - component.mask = '0000'; - component.suffix = ' $'; + component.mask.set('0000'); + component.suffix.set(' $'); equal('', '', fixture); equal('123', '123 $', fixture); equal('1234', '1234 $', fixture); }); it('should clear if not match the mask!!!!', () => { - component.mask = '0*.00'; - component.suffix = ' $'; + component.mask.set('0*.00'); + component.suffix.set(' $'); equal('', '', fixture); equal('12345', '12345 $', fixture); equal('12344.44', '12344.44 $', fixture); }); it('should work correct with suffix .com', () => { - component.mask = '0000'; - component.suffix = '.com'; + component.mask.set('0000'); + component.suffix.set('.com'); equal('', '', fixture); equal('12', '12.com', fixture); equal('12344', '1234.com', fixture); @@ -49,15 +48,15 @@ describe('Directive: Mask (Suffix)', () => { }); it('separator should work correct with suffix', () => { - component.mask = 'separator'; - component.suffix = '$'; + component.mask.set('separator'); + component.suffix.set('$'); equal('', '', fixture); equal('123', '123$', fixture); equal('1234', '1 234$', fixture); }); it('should not delete suffix', () => { - component.mask = '0000'; - component.suffix = '$'; + component.mask.set('0000'); + component.suffix.set('$'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -78,8 +77,8 @@ describe('Directive: Mask (Suffix)', () => { expect(inputTarget.selectionStart).toEqual(4); }); it('should delete all if value and part of suffix are deleted', () => { - component.mask = 'A*'; - component.suffix = ' test'; + component.mask.set('A*'); + component.suffix.set(' test'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -96,8 +95,8 @@ describe('Directive: Mask (Suffix)', () => { expect(inputTarget.value).toBe(''); }); it('should not delete suffix', () => { - component.mask = 'A{5}'; - component.suffix = '.com'; + component.mask.set('A{5}'); + component.suffix.set('.com'); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); diff --git a/projects/ngx-mask-lib/src/test/time-mask.spec.ts b/projects/ngx-mask-lib/src/test/time-mask.spec.ts index cf15da40..0c315452 100644 --- a/projects/ngx-mask-lib/src/test/time-mask.spec.ts +++ b/projects/ngx-mask-lib/src/test/time-mask.spec.ts @@ -4,8 +4,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { provideNgxMask, NgxMaskDirective } from 'ngx-mask'; describe('Directive: Mask (Time)', () => { let fixture: ComponentFixture; @@ -22,142 +21,142 @@ describe('Directive: Mask (Time)', () => { }); it('empty', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('', '', fixture); }); it('Hours', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('20', '20', fixture); }); it('Hours', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('03', '03', fixture); }); it('Hours', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('730', '7:30', fixture); }); it('Hours', () => { - component.showMaskTyped = true; - component.mask = 'Hh:m0'; + component.showMaskTyped.set(true); + component.mask.set('Hh:m0'); equal('3__:__', '3_:__', fixture); equal('33:__', '3:3_', fixture); equal('33__:__', '3:3_', fixture); }); it('Hours (lead zero)', () => { - component.showMaskTyped = true; - component.leadZeroDateTime = true; - component.mask = 'Hh:m0'; + component.showMaskTyped.set(true); + component.leadZeroDateTime.set(true); + component.mask.set('Hh:m0'); equal('3__:__', '03:__', fixture); }); it('Minutes', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('1212', '12:12', fixture); }); it('Minutes', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('1207', '12:07', fixture); }); it('Minutes', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('127', '12:7', fixture); }); it('Minutes (lead zero)', () => { - component.leadZeroDateTime = true; - component.mask = 'Hh:m0:s0'; + component.leadZeroDateTime.set(true); + component.mask.set('Hh:m0:s0'); equal('127', '12:07', fixture); }); it('Hours and minutes', () => { - component.mask = 'Hh:m0:s0'; + component.mask.set('Hh:m0:s0'); equal('7712', '7:7:12', fixture); }); it('Seconds (lead zero)', () => { - component.leadZeroDateTime = true; - component.mask = 'Hh:m0:s0'; + component.leadZeroDateTime.set(true); + component.mask.set('Hh:m0:s0'); equal('777', '07:07:07', fixture); }); it('Date', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('321234', '3/2/1234', fixture); }); it('Date', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('3113123', '31/1/3123', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('413234', '4/1/3234', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('01011234', '01/01/1234', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('10101234', '10/10/1234', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('2322123', '23/2/2123', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('23122123', '23/12/2123', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('0314123', '03/1/4123', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('0314123', '03/1/4123', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('414123', '4/1/4123', fixture); }); it('Date ', () => { - component.mask = 'd0/M0/0000'; + component.mask.set('d0/M0/0000'); equal('4121234', '4/12/1234', fixture); }); it('Date (day lead zero)', () => { - component.leadZeroDateTime = true; - component.mask = 'd0/M0/0000'; + component.leadZeroDateTime.set(true); + component.mask.set('d0/M0/0000'); equal('4121234', '04/12/1234', fixture); }); it('Date (month lead zero)', () => { - component.leadZeroDateTime = true; - component.mask = 'd0/M0/0000'; + component.leadZeroDateTime.set(true); + component.mask.set('d0/M0/0000'); equal('421234', '04/02/1234', fixture); }); it('Date (years, month, day , lead zero', () => { - component.mask = '0000.M0.d0'; - component.leadZeroDateTime = true; + component.mask.set('0000.M0.d0'); + component.leadZeroDateTime.set(true); equal('9999999', '9999.09.09', fixture); equal('8888888', '8888.08.08', fixture); equal('7777777', '7777.07.07', fixture); @@ -167,8 +166,8 @@ describe('Directive: Mask (Time)', () => { }); it('Date (years, month, day , lead zero', () => { - component.mask = '0000/M0/d0'; - component.leadZeroDateTime = true; + component.mask.set('0000/M0/d0'); + component.leadZeroDateTime.set(true); equal('9999999', '9999/09/09', fixture); equal('8888888', '8888/08/08', fixture); equal('7777777', '7777/07/07', fixture); @@ -178,7 +177,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (years, month, day mask 0000.M0.d0', () => { - component.mask = '0000.M0.d0'; + component.mask.set('0000.M0.d0'); equal('999999', '9999.9.9', fixture); equal('888888', '8888.8.8', fixture); equal('777777', '7777.7.7', fixture); @@ -191,7 +190,7 @@ describe('Directive: Mask (Time)', () => { equal('202344', '2023.4.4', fixture); }); it('Date (d0-M0-0000', () => { - component.mask = 'd0-M0-0000'; + component.mask.set('d0-M0-0000'); equal('999999', '9-9-9999', fixture); equal('888888', '8-8-8888', fixture); equal('777777', '7-7-7777', fixture); @@ -205,7 +204,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (d0/M0:0000', () => { - component.mask = 'd0/M0:0000'; + component.mask.set('d0/M0:0000'); equal('999999', '9/9:9999', fixture); equal('888888', '8/8:8888', fixture); equal('777777', '7/7:7777', fixture); @@ -219,7 +218,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (m0/d0/0000', () => { - component.mask = 'm0/d0/0000'; + component.mask.set('m0/d0/0000'); equal('999999', '9/9/9999', fixture); equal('888888', '8/8/8888', fixture); equal('777777', '7/7/7777', fixture); @@ -233,7 +232,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (0000-M0-d0', () => { - component.mask = '0000-M0-d0'; + component.mask.set('0000-M0-d0'); equal('999999', '9999-9-9', fixture); equal('888888', '8888-8-8', fixture); equal('777777', '7777-7-7', fixture); @@ -246,7 +245,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0/d0/0000', () => { - component.mask = 'M0/d0/0000'; + component.mask.set('M0/d0/0000'); equal('999999', '9/9/9999', fixture); equal('888888', '8/8/8888', fixture); equal('777777', '7/7/7777', fixture); @@ -259,7 +258,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0+d0+0000', () => { - component.mask = 'M0+d0+0000'; + component.mask.set('M0+d0+0000'); equal('999999', '9+9+9999', fixture); equal('888888', '8+8+8888', fixture); equal('777777', '7+7+7777', fixture); @@ -272,7 +271,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0@d0@0000', () => { - component.mask = 'M0@d0@0000'; + component.mask.set('M0@d0@0000'); equal('999999', '9@9@9999', fixture); equal('888888', '8@8@8888', fixture); equal('777777', '7@7@7777', fixture); @@ -285,7 +284,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0@d0/0000', () => { - component.mask = 'M0@d0/0000'; + component.mask.set('M0@d0/0000'); equal('999999', '9@9/9999', fixture); equal('888888', '8@8/8888', fixture); equal('777777', '7@7/7777', fixture); @@ -298,7 +297,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0:d0/0000', () => { - component.mask = 'M0:d0/0000'; + component.mask.set('M0:d0/0000'); equal('999999', '9:9/9999', fixture); equal('888888', '8:8/8888', fixture); equal('777777', '7:7/7777', fixture); @@ -311,7 +310,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0-d0-0000', () => { - component.mask = 'M0-d0-0000'; + component.mask.set('M0-d0-0000'); equal('999999', '9-9-9999', fixture); equal('888888', '8-8-8888', fixture); equal('777777', '7-7-7777', fixture); @@ -324,7 +323,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (M0.d0.0000', () => { - component.mask = 'M0.d0.0000'; + component.mask.set('M0.d0.0000'); equal('999999', '9.9.9999', fixture); equal('888888', '8.8.8888', fixture); equal('777777', '7.7.7777', fixture); @@ -337,7 +336,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (d0.M0.0000 Hh:m0:s0', () => { - component.mask = 'd0.M0.0000 Hh:m0:s0'; + component.mask.set('d0.M0.0000 Hh:m0:s0'); equal('992023999', '9.9.2023 9:9:9', fixture); equal('882023292030', '8.8.2023 2:9:20', fixture); equal('11111111 2420', '11.11.1111 2:42:0', fixture); @@ -347,7 +346,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date (d0.M0.0000 Hh:m0 - Hh:m0', () => { - component.mask = 'd0.M0.0000 Hh:m0 - Hh:m0'; + component.mask.set('d0.M0.0000 Hh:m0 - Hh:m0'); equal('11111111 1111 1111', '11.11.1111 11:11 - 11:11', fixture); equal('31122023 2359 1211', '31.12.2023 23:59 - 12:11', fixture); equal('1223333 29 299', '12.2.3333 2:9 - 2:9', fixture); @@ -359,8 +358,8 @@ describe('Directive: Mask (Time)', () => { }); it('Date (Hh:m0 apm=true', () => { - component.mask = 'Hh:m0'; - component.apm = true; + component.mask.set('Hh:m0'); + component.apm.set(true); equal('1', '1', fixture); equal('11', '11', fixture); equal('12', '12', fixture); @@ -382,8 +381,8 @@ describe('Directive: Mask (Time)', () => { }); it('Date (Hh:m0:s0 apm=true', () => { - component.mask = 'Hh:m0:s0'; - component.apm = true; + component.mask.set('Hh:m0:s0'); + component.apm.set(true); equal('1323', '1:32:3', fixture); equal('1223', '12:23', fixture); equal('112322', '11:23:22', fixture); @@ -392,8 +391,8 @@ describe('Directive: Mask (Time)', () => { }); it('Date (d0/M0/0000 Hh:m0:s0 apm=true', () => { - component.mask = 'd0/M0/0000 Hh:m0:s0'; - component.apm = true; + component.mask.set('d0/M0/0000 Hh:m0:s0'); + component.apm.set(true); equal('11122023', '11/12/2023', fixture); equal('11122023133456', '11/12/2023 1:33:45', fixture); equal('11/12/2023 13:32:30 ', '11/12/2023 1:33:23', fixture); @@ -401,9 +400,9 @@ describe('Directive: Mask (Time)', () => { }); it('Date (0000-M0-d0 Hh:m0:s0.000', () => { - component.mask = '0000-M0-d0 Hh:m0:s0.000'; - component.leadZeroDateTime = true; - component.showMaskTyped = true; + component.mask.set('0000-M0-d0 Hh:m0:s0.000'); + component.leadZeroDateTime.set(true); + component.showMaskTyped.set(true); equal('2023', '2023-__-__ __:__:__.___', fixture); equal('202309', '2023-09-__ __:__:__.___', fixture); equal('20230931', '2023-09-31 __:__:__.___', fixture); @@ -414,51 +413,51 @@ describe('Directive: Mask (Time)', () => { }); it('Date (0000-M0-d0 leadZero and showMaskTyped', () => { - component.mask = '0000-M0-d0'; - component.leadZeroDateTime = true; - component.showMaskTyped = true; + component.mask.set('0000-M0-d0'); + component.leadZeroDateTime.set(true); + component.showMaskTyped.set(true); equal('2023', '2023-__-__', fixture); equal('202310', '2023-10-__', fixture); equal('20231029', '2023-10-29', fixture); }); it('Date (0000/M0/d0 leadZero and showMaskTyped', () => { - component.mask = '0000/M0/d0'; - component.leadZeroDateTime = true; - component.showMaskTyped = true; + component.mask.set('0000/M0/d0'); + component.leadZeroDateTime.set(true); + component.showMaskTyped.set(true); equal('2023', '2023/__/__', fixture); equal('202312', '2023/12/__', fixture); equal('20231229', '2023/12/29', fixture); }); it('Date (0000.M0.d0 leadZero and showMaskTyped', () => { - component.mask = '0000.M0.d0'; - component.leadZeroDateTime = true; - component.showMaskTyped = true; + component.mask.set('0000.M0.d0'); + component.leadZeroDateTime.set(true); + component.showMaskTyped.set(true); equal('2023', '2023.__.__', fixture); equal('202310', '2023.10.__', fixture); equal('20231031', '2023.10.31', fixture); }); it('Date (0000.M0.d0 leadZero and showMaskTyped', () => { - component.mask = 'M0/d0/0000'; - component.leadZeroDateTime = true; - component.showMaskTyped = true; - component.dropSpecialCharacters = false; + component.mask.set('M0/d0/0000'); + component.leadZeroDateTime.set(true); + component.showMaskTyped.set(true); + component.dropSpecialCharacters.set(false); equal('01', '01/__/____', fixture); equal('0109', '01/09/____', fixture); equal('01/03/2011', '01/03/2011', fixture); }); it('Date (d0/M0/0000 leadZero)', () => { - component.mask = 'M0/d0/0000'; - component.leadZeroDateTime = true; + component.mask.set('M0/d0/0000'); + component.leadZeroDateTime.set(true); equal('4122000', '04/12/2000', fixture); equal('442000', '04/04/2000', fixture); }); it('Date (0000-M0)', () => { - component.mask = '0000-M0'; + component.mask.set('0000-M0'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -467,7 +466,7 @@ describe('Directive: Mask (Time)', () => { equal('123412', '1234-12', fixture); }); it('Date (0000/M0)', () => { - component.mask = '0000/M0'; + component.mask.set('0000/M0'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -476,7 +475,7 @@ describe('Directive: Mask (Time)', () => { equal('123412', '1234/12', fixture); }); it('Date (0000:M0)', () => { - component.mask = '0000:M0'; + component.mask.set('0000:M0'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '123', fixture); @@ -486,7 +485,7 @@ describe('Directive: Mask (Time)', () => { }); it('Date d0/M0', () => { - component.mask = 'd0/M0'; + component.mask.set('d0/M0'); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '12/3', fixture); @@ -495,8 +494,8 @@ describe('Directive: Mask (Time)', () => { }); it('Date d0/M0 with v', () => { - component.mask = 'd0/M0'; - component.leadZeroDateTime = true; + component.mask.set('d0/M0'); + component.leadZeroDateTime.set(true); equal('1', '1', fixture); equal('12', '12', fixture); equal('123', '12/03', fixture); diff --git a/projects/ngx-mask-lib/src/test/trigger-on-mask-change.spec.ts b/projects/ngx-mask-lib/src/test/trigger-on-mask-change.spec.ts index c473484c..b12997f7 100644 --- a/projects/ngx-mask-lib/src/test/trigger-on-mask-change.spec.ts +++ b/projects/ngx-mask-lib/src/test/trigger-on-mask-change.spec.ts @@ -4,8 +4,7 @@ import { TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { ReactiveFormsModule } from '@angular/forms'; import { TestMaskComponent } from './utils/test-component.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; import type { DebugElement } from '@angular/core'; import { equal } from './utils/test-functions.component'; @@ -28,8 +27,8 @@ describe('Directive: Mask (Trigger on mask change)', () => { }); it('should trigger form value update if mask is changed', async () => { - component.mask = ''; - component.triggerOnMaskChange = true; + component.mask.set(''); + component.triggerOnMaskChange.set(true); fixture.detectChanges(); component.form.setValue('7912345678'); @@ -39,7 +38,7 @@ describe('Directive: Mask (Trigger on mask change)', () => { expect(inputEl.nativeElement.value).toEqual('7912345678'); expect(component.form.value).toEqual('7912345678'); - component.mask = '00 000 00 00'; + component.mask.set('00 000 00 00'); fixture.detectChanges(); await fixture.whenStable(); inputEl = fixture.debugElement.query(By.css('input')); @@ -48,8 +47,8 @@ describe('Directive: Mask (Trigger on mask change)', () => { }); it('should trigger form value update if mask is changed', async () => { - component.mask = '00000||00000-0000'; - component.triggerOnMaskChange = true; + component.mask.set('00000||00000-0000'); + component.triggerOnMaskChange.set(true); const debugElement: DebugElement = fixture.debugElement.query(By.css('input')); const inputTarget: HTMLInputElement = debugElement.nativeElement as HTMLInputElement; spyOnProperty(document, 'activeElement').and.returnValue(inputTarget); @@ -59,7 +58,7 @@ describe('Directive: Mask (Trigger on mask change)', () => { expect(inputTarget.value).toEqual('1234'); expect(component.form.value).toBe('1234'); - component.mask = 'S0S 0S0'; + component.mask.set('S0S 0S0'); equal(inputTarget.value, '', fixture, true); expect(component.form.value).toBe(''); }); diff --git a/projects/ngx-mask-lib/src/test/type-number.spec.ts b/projects/ngx-mask-lib/src/test/type-number.spec.ts index 5d0ebc05..82e3a69e 100644 --- a/projects/ngx-mask-lib/src/test/type-number.spec.ts +++ b/projects/ngx-mask-lib/src/test/type-number.spec.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, signal } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import type { ComponentFixture } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing'; @@ -9,12 +9,12 @@ import { equal } from './utils/test-functions.component'; selector: 'jsdaddy-open-source-test', standalone: true, imports: [ReactiveFormsModule, NgxMaskDirective], - template: ` `, + template: ` `, }) // eslint-disable-next-line @angular-eslint/component-class-suffix export class TestTypeNumber { public form: FormControl = new FormControl(''); - public mask = ''; + public mask = signal(''); } describe('Directive: Mask (Trigger on mask change)', () => { @@ -36,7 +36,7 @@ describe('Directive: Mask (Trigger on mask change)', () => { }); it('mask 0* should work with mask 0*', () => { - component.mask = '0*'; + component.mask.set('0*'); equal('1', '1', fixture); equal('12', '12', fixture); @@ -46,7 +46,7 @@ describe('Directive: Mask (Trigger on mask change)', () => { }); it('mask 0000 should work with mask 0000', () => { - component.mask = '0000'; + component.mask.set('0000'); equal('1', '1', fixture); equal('12', '12', fixture); @@ -56,14 +56,14 @@ describe('Directive: Mask (Trigger on mask change)', () => { }); it('mask 0000 should work with mask 0000', () => { - component.mask = 'percent'; + component.mask.set('percent'); equal('100', '100', fixture); equal('99', '99', fixture); }); it('should be editable with empty mask', () => { - component.mask = ''; + component.mask.set(''); equal('100', '100', fixture); equal('99', '99', fixture); diff --git a/projects/ngx-mask-lib/src/test/utils/test-component.component.ts b/projects/ngx-mask-lib/src/test/utils/test-component.component.ts index f231a1cb..c5e5b0c2 100644 --- a/projects/ngx-mask-lib/src/test/utils/test-component.component.ts +++ b/projects/ngx-mask-lib/src/test/utils/test-component.component.ts @@ -1,4 +1,4 @@ -import { Component, inject } from '@angular/core'; +import { Component, inject, signal } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import type { NgxMaskConfig } from 'ngx-mask'; import { NGX_MASK_CONFIG } from 'ngx-mask'; @@ -11,81 +11,77 @@ import { NgxMaskDirective } from 'ngx-mask'; template: ` + [showMaskTyped]="showMaskTyped()" + [placeHolderCharacter]="placeHolderCharacter()" + [separatorLimit]="separatorLimit()" + [hiddenInput]="hiddenInput()" + [allowNegativeNumbers]="allowNegativeNumbers()" + [leadZeroDateTime]="leadZeroDateTime()" + [leadZero]="leadZero()" + [keepCharacterPositions]="keepCharacterPositions()" + [apm]="apm()" + [validation]="validation()" + [inputTransformFn]="inputTransformFn()" + [outputTransformFn]="outputTransformFn()" + [triggerOnMaskChange]="triggerOnMaskChange()" /> `, }) export class TestMaskComponent { - public mask!: string | null | undefined; protected _config = inject(NGX_MASK_CONFIG); public form: FormControl = new FormControl(); - public dropSpecialCharacters: NgxMaskConfig['dropSpecialCharacters'] = - this._config.dropSpecialCharacters; - - public clearIfNotMatch: NgxMaskConfig['clearIfNotMatch'] = this._config.clearIfNotMatch; - - public patterns: NgxMaskConfig['patterns'] = this._config.patterns; - - public prefix: NgxMaskConfig['prefix'] = this._config.prefix; - - public thousandSeparator: NgxMaskConfig['thousandSeparator'] = this._config.thousandSeparator; - - public decimalMarker: NgxMaskConfig['decimalMarker'] = this._config.decimalMarker; - - public suffix: NgxMaskConfig['suffix'] = this._config.suffix; - - public specialCharacters: NgxMaskConfig['specialCharacters'] = this._config.specialCharacters; - - public keepCharacterPositions: NgxMaskConfig['keepCharacterPositions'] = - this._config.keepCharacterPositions; - - public showMaskTyped: NgxMaskConfig['showMaskTyped'] = this._config.showMaskTyped; - - public placeHolderCharacter: NgxMaskConfig['placeHolderCharacter'] = - this._config.placeHolderCharacter; - - public hiddenInput: NgxMaskConfig['hiddenInput'] = this._config.hiddenInput; - - public separatorLimit: NgxMaskConfig['separatorLimit'] = this._config.separatorLimit; - - public allowNegativeNumbers: NgxMaskConfig['allowNegativeNumbers'] = - this._config.allowNegativeNumbers; - - public leadZeroDateTime: NgxMaskConfig['leadZeroDateTime'] = this._config.leadZeroDateTime; - - public leadZero: NgxMaskConfig['leadZero'] = this._config.leadZero; - - public triggerOnMaskChange: NgxMaskConfig['triggerOnMaskChange'] = - this._config.triggerOnMaskChange; - - public validation: NgxMaskConfig['validation'] = this._config.validation; - - public apm: NgxMaskConfig['apm'] = this._config.apm; - - public inputTransformFn: NgxMaskConfig['inputTransformFn'] = this._config.inputTransformFn; - - public outputTransformFn: NgxMaskConfig['outputTransformFn'] = this._config.outputTransformFn; + public mask = signal(''); + + public dropSpecialCharacters = signal( + this._config.dropSpecialCharacters + ); + public hiddenInput = signal(this._config.hiddenInput); + public clearIfNotMatch = signal(this._config.clearIfNotMatch); + public specialCharacters = signal( + this._config.specialCharacters + ); + public patterns = signal(this._config.patterns); + public prefix = signal(this._config.prefix); + public suffix = signal(this._config.suffix); + public thousandSeparator = signal( + this._config.thousandSeparator + ); + public decimalMarker = signal(this._config.decimalMarker); + public showMaskTyped = signal(this._config.showMaskTyped); + public placeHolderCharacter = signal( + this._config.placeHolderCharacter + ); + public validation = signal(this._config.validation); + public separatorLimit = signal(this._config.separatorLimit); + public allowNegativeNumbers = signal( + this._config.allowNegativeNumbers + ); + public leadZeroDateTime = signal( + this._config.leadZeroDateTime + ); + public leadZero = signal(this._config.leadZero); + public apm = signal(this._config.apm); + public inputTransformFn = signal( + this._config.inputTransformFn + ); + public outputTransformFn = signal( + this._config.outputTransformFn + ); + public keepCharacterPositions = signal( + this._config.keepCharacterPositions + ); + public triggerOnMaskChange = signal( + this._config.triggerOnMaskChange + ); } diff --git a/projects/ngx-mask-lib/src/test/validation.spec.ts b/projects/ngx-mask-lib/src/test/validation.spec.ts index 6e566403..29f94fb2 100644 --- a/projects/ngx-mask-lib/src/test/validation.spec.ts +++ b/projects/ngx-mask-lib/src/test/validation.spec.ts @@ -3,8 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { ReactiveFormsModule, Validators } from '@angular/forms'; import { equal } from './utils/test-functions.component'; -import { provideNgxMask } from '../lib/ngx-mask.providers'; -import { NgxMaskDirective } from '../lib/ngx-mask.directive'; +import { NgxMaskDirective, provideNgxMask } from 'ngx-mask'; import { TestMaskComponent } from './utils/test-component.component'; describe('Directive: Mask (Validation)', () => { @@ -22,7 +21,7 @@ describe('Directive: Mask (Validation)', () => { }); it('should be marked as not valid if not valid and validation attribute true', () => { - component.mask = '0000'; + component.mask.set('0000'); component.form.addValidators(Validators.required); equal('12', '12', fixture); @@ -31,7 +30,7 @@ describe('Directive: Mask (Validation)', () => { }); it('should be marked as valid if not valid and validation attribute false', () => { - component.validation = false; + component.validation.set(false); component.form.addValidators(Validators.required); equal('12', '12', fixture); @@ -39,7 +38,7 @@ describe('Directive: Mask (Validation)', () => { }); it('should be marked as valid if valid and validation attribute true', () => { - component.mask = '0000'; + component.mask.set('0000'); component.form.addValidators(Validators.required); equal('1234', '1234', fixture); @@ -47,8 +46,8 @@ describe('Directive: Mask (Validation)', () => { }); it('should be marked as valid if not valid and validation attribute false', () => { - component.validation = false; - component.mask = '0000'; + component.validation.set(false); + component.mask.set('0000'); component.form.addValidators(Validators.required); equal('12', '12', fixture); @@ -56,8 +55,8 @@ describe('Directive: Mask (Validation)', () => { }); it('should be not valid email mask A*@A*.SSS', () => { - component.mask = 'A*@A*.SSS'; - component.dropSpecialCharacters = false; + component.mask.set('A*@A*.SSS'); + component.dropSpecialCharacters.set(false); component.form.addValidators(Validators.required); equal('a', 'a', fixture); @@ -87,8 +86,8 @@ describe('Directive: Mask (Validation)', () => { }); it('should valid email mask A*@A*.SSS', () => { - component.mask = 'A*@A*.SSS'; - component.dropSpecialCharacters = false; + component.mask.set('A*@A*.SSS'); + component.dropSpecialCharacters.set(false); component.form.addValidators(Validators.required); equal('testing@gmail.com', 'testing@gmail.com', fixture); @@ -96,8 +95,8 @@ describe('Directive: Mask (Validation)', () => { }); it('should be not valid mask A*@A*.SS', () => { - component.mask = 'A*@A*.SS'; - component.dropSpecialCharacters = false; + component.mask.set('A*@A*.SS'); + component.dropSpecialCharacters.set(false); component.form.addValidators(Validators.required); equal('d', 'd', fixture); @@ -125,8 +124,8 @@ describe('Directive: Mask (Validation)', () => { }); it('should valid email mask', () => { - component.mask = 'A*@A*.SS'; - component.dropSpecialCharacters = false; + component.mask.set('A*@A*.SS'); + component.dropSpecialCharacters.set(false); component.form.addValidators(Validators.required); equal('testing@some.ua', 'testing@some.ua', fixture); @@ -134,7 +133,7 @@ describe('Directive: Mask (Validation)', () => { }); it('should valid from one digit mask 0*', () => { - component.mask = '0*'; + component.mask.set('0*'); component.form.setValidators([Validators.required, Validators.min(1)]); component.form.updateValueAndValidity(); @@ -151,7 +150,7 @@ describe('Directive: Mask (Validation)', () => { }); it('should valid from one digit mask S*', () => { - component.mask = 'S*'; + component.mask.set('S*'); component.form.setValidators([Validators.required, Validators.min(1)]); component.form.updateValueAndValidity(); @@ -162,7 +161,7 @@ describe('Directive: Mask (Validation)', () => { }); it('should valid from one digit mask A*', () => { - component.mask = 'A*'; + component.mask.set('A*'); component.form.setValidators([Validators.required, Validators.min(1)]); component.form.updateValueAndValidity(); @@ -175,10 +174,7 @@ describe('Directive: Mask (Validation)', () => { }); it('mask with number value should work as expected mask 0*', () => { - // public form: FormControl = new FormControl(44, Validators.required); - // public mask = ''; - // public validate = true; - component.mask = '0*'; + component.mask.set('0*'); component.form.setValidators([Validators.required, Validators.min(1)]); component.form.updateValueAndValidity(); @@ -196,7 +192,7 @@ describe('Directive: Mask (Validation)', () => { }); it('mask with number value should work as expected mask 000.00', () => { - component.mask = '000.00'; + component.mask.set('000.00'); component.form.addValidators(Validators.required); component.form.setValue(''); @@ -226,9 +222,9 @@ describe('Directive: Mask (Validation)', () => { }); it('dropSpecialCharacters is different from specialCharacters', () => { - component.mask = '+000'; - component.specialCharacters = ['+', ' ']; - component.dropSpecialCharacters = [' ']; + component.mask.set('+000'); + component.specialCharacters.set(['+', ' ']); + component.dropSpecialCharacters.set([' ']); component.form.addValidators(Validators.required); equal('+37', '+37', fixture); @@ -237,7 +233,7 @@ describe('Directive: Mask (Validation)', () => { equal('+373', '+373', fixture); expect(component.form.valid).toBe(true); - component.mask = '+000 000 00 000'; + component.mask.set('+000 000 00 000'); equal('+3736000000', '+373 600 00 00', fixture); expect(component.form.valid).toBe(false); @@ -247,8 +243,8 @@ describe('Directive: Mask (Validation)', () => { }); it('email Mask should validated correct', () => { - component.mask = 'A*@A*.A*'; - component.dropSpecialCharacters = false; + component.mask.set('A*@A*.A*'); + component.dropSpecialCharacters.set(false); component.form.addValidators(Validators.required); equal('validate', 'validate', fixture); diff --git a/src/app/options/options.component.html b/src/app/options/options.component.html index 3b2442bd..3ab32158 100644 --- a/src/app/options/options.component.html +++ b/src/app/options/options.component.html @@ -34,7 +34,7 @@ *ngTemplateOutlet=" exampleTmpl; context: { $implicit: cardExamples()?.[i], placeholder: tile.header } - "> + " /> } @@ -45,8 +45,7 @@ *ngTemplateOutlet=" !ex._pipe ? inputTemplate : pipeTemplate; context: { $implicit: ex, placeholder: placeholder } - "> - + " /> diff --git a/src/assets/content/optional.ts b/src/assets/content/optional.ts index 8f7255ce..8c36a860 100644 --- a/src/assets/content/optional.ts +++ b/src/assets/content/optional.ts @@ -84,7 +84,7 @@ export const OptDocs: ComDoc[] = [ export const OptExamples: TExample[] = [ { _placeholder: 'prefix', - _prefix: '+7', + _prefix: '+7 ', _mask: '(00) 000 000', control: { form: new UntypedFormControl(''), model: '' }, }, diff --git a/src/libraries b/src/libraries index 44bebdfb..158eddb9 160000 --- a/src/libraries +++ b/src/libraries @@ -1 +1 @@ -Subproject commit 44bebdfba90c6534af67bf84d5f90f8f1b0b343b +Subproject commit 158eddb9ea79ca05967268021029ecdf096c23bb diff --git a/tsconfig.json b/tsconfig.json index e154a50d..f7422398 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,10 +14,10 @@ "target": "ES2022", "lib": ["ES2022", "dom"], "paths": { - "ngx-mask": ["projects/ngx-mask-lib/src"], - "ngx-mask/*": ["projects/ngx-mask-lib/src"], + "@libraries/*": ["src/libraries/*"], "@open-source/*": ["src/libraries/open-source/*"], - "@libraries/*": ["src/libraries/*"] + "ngx-mask": ["projects/ngx-mask-lib/src"], + "ngx-mask/*": ["projects/ngx-mask-lib/src"] }, "moduleResolution": "node", "forceConsistentCasingInFileNames": true, @@ -50,7 +50,7 @@ "checks": { "invalidBananaInBox": "error", "nullishCoalescingNotNullable": "warning", - "unusedStandaloneImports": "suppress" + "unusedStandaloneImports": "error" }, "defaultCategory": "suppress" }