diff --git a/src/mask-input.ts b/src/mask-input.ts index 8f86d22..7d643dd 100644 --- a/src/mask-input.ts +++ b/src/mask-input.ts @@ -144,6 +144,12 @@ export class MaskInput { value = mask.masked(value) + const detail = { + masked: mask.masked(value), + unmasked: mask.unmasked(value), + completed: mask.completed(value) + } + if (this.options.postProcess != null) { value = this.options.postProcess(value) } @@ -151,12 +157,6 @@ export class MaskInput { input.value = value input.dataset.maskaValue = value - const detail = { - masked: mask.masked(value), - unmasked: mask.unmasked(value), - completed: mask.completed(value) - } - if (this.options.onMaska != null) { if (Array.isArray(this.options.onMaska)) { this.options.onMaska.forEach((f) => f(detail)) diff --git a/test/mask-input.test.ts b/test/mask-input.test.ts index 7dece3b..dc11e01 100644 --- a/test/mask-input.test.ts +++ b/test/mask-input.test.ts @@ -1,4 +1,13 @@ -import { afterEach, beforeAll, describe, expect, test, vi } from 'vitest' +import { + afterEach, + beforeAll, + beforeEach, + describe, + expect, + SpyInstance, + test, + vi +} from 'vitest' import userEvent from '@testing-library/user-event' import { MaskInput, MaskInputOptions } from '../src/mask-input' @@ -83,33 +92,6 @@ describe('test init', () => { ) }) - test('test hooks', async () => { - document.body.innerHTML = `` - const input = document.getElementById('input') - - const hooks = { - preProcess: (value: string) => value.toUpperCase(), - postProcess: (value: string) => value.toLowerCase() - } - const preProcess: any = vi.spyOn(hooks, 'preProcess') - const postProcess: any = vi.spyOn(hooks, 'postProcess') - - new MaskInput(input, { preProcess, postProcess }) - - await user.type(input, 'ab') - - expect(input).toHaveValue('a-b') - - expect(preProcess).toHaveBeenCalledTimes(2) - expect(postProcess).toHaveBeenCalledTimes(2) - - expect(preProcess).toHaveBeenLastCalledWith('ab') - expect(preProcess).toHaveLastReturnedWith('AB') - - expect(postProcess).toHaveBeenLastCalledWith('A-B') - expect(postProcess).toHaveLastReturnedWith('a-b') - }) - test('init with element list', async () => { document.body.innerHTML = `` const inputs = >( @@ -140,6 +122,231 @@ describe('test init', () => { }) }) +interface HooksTestContext { + onMaska: SpyInstance + preProcess: SpyInstance + postProcess: SpyInstance +} + +describe('test hooks', () => { + beforeEach((context) => { + document.body.innerHTML = `` + input = document.getElementById('input') + + const hooks = { + onMaska: (value) => value, + preProcess: (value: string) => value.replace(/[$,]/g, ''), + postProcess: (value: string) => { + if (!value) return '' + + const parts = value.split('.') + const sub = parts.length === 1 ? 3 : 2 - parts[1].length + const result = Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD' + }) + .formatToParts(Number(value)) + .map((v) => v.value) + .join('') + + return result.substring(0, result.length - sub) + } + } + + context.onMaska = vi.spyOn(hooks, 'onMaska') + context.preProcess = vi.spyOn(hooks, 'preProcess') + context.postProcess = vi.spyOn(hooks, 'postProcess') + + new MaskInput(input, { + onMaska: context.onMaska as any, + preProcess: context.preProcess as any, + postProcess: context.postProcess as any + }) + }) + + test('input 1', async (context) => { + await user.type(input, '1') + expect(input).toHaveValue('$1') + + expect(context.preProcess).toHaveBeenCalledOnce() + expect(context.postProcess).toHaveBeenCalledOnce() + + expect(context.onMaska).toHaveBeenCalledOnce() + expect(context.onMaska).toHaveBeenCalledWith({ + completed: false, + masked: '1', + unmasked: '1' + }) + }) + + test('input 123', async (context) => { + await user.type(input, '123') + expect(input).toHaveValue('$123') + + expect(context.preProcess).toHaveBeenCalledTimes(3) + expect(context.postProcess).toHaveBeenCalledTimes(3) + + expect(context.onMaska).toHaveBeenCalledTimes(3) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: false, + masked: '123', + unmasked: '123' + }) + }) + + test('input 1234', async (context) => { + await user.type(input, '1234') + expect(input).toHaveValue('$1,234') + + expect(context.preProcess).toHaveBeenCalledTimes(4) + expect(context.postProcess).toHaveBeenCalledTimes(4) + + expect(context.onMaska).toHaveBeenCalledTimes(4) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234', + unmasked: '1234' + }) + }) + + test('input 1234567', async (context) => { + await user.type(input, '1234567') + expect(input).toHaveValue('$1,234,567') + + expect(context.preProcess).toHaveBeenCalledTimes(7) + expect(context.postProcess).toHaveBeenCalledTimes(7) + + expect(context.onMaska).toHaveBeenCalledTimes(7) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234567', + unmasked: '1234567' + }) + }) + + test('input 123.4', async (context) => { + await user.type(input, '123.4') + expect(input).toHaveValue('$123.4') + + expect(context.preProcess).toHaveBeenCalledTimes(5) + expect(context.postProcess).toHaveBeenCalledTimes(5) + + expect(context.onMaska).toHaveBeenCalledTimes(5) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '123.4', + unmasked: '1234' + }) + }) + + test('input 123.45', async (context) => { + await user.type(input, '123.45') + expect(input).toHaveValue('$123.45') + + expect(context.preProcess).toHaveBeenCalledTimes(6) + expect(context.postProcess).toHaveBeenCalledTimes(6) + + expect(context.onMaska).toHaveBeenCalledTimes(6) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '123.45', + unmasked: '12345' + }) + }) + + test('input 123.456', async (context) => { + await user.type(input, '123.456') + expect(input).toHaveValue('$123.45') + + expect(context.preProcess).toHaveBeenCalledTimes(7) + expect(context.postProcess).toHaveBeenCalledTimes(7) + + expect(context.onMaska).toHaveBeenCalledTimes(7) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '123.45', + unmasked: '12345' + }) + }) + + test('input 1234.567', async (context) => { + await user.type(input, '1234.567') + expect(input).toHaveValue('$1,234.56') + + expect(context.preProcess).toHaveBeenCalledTimes(8) + expect(context.postProcess).toHaveBeenCalledTimes(8) + + expect(context.onMaska).toHaveBeenCalledTimes(8) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234.56', + unmasked: '123456' + }) + }) + + test('input $1234.56', async (context) => { + await user.type(input, '$1234.56') + expect(input).toHaveValue('$1,234.56') + + expect(context.preProcess).toHaveBeenCalledTimes(8) + expect(context.postProcess).toHaveBeenCalledTimes(8) + + expect(context.onMaska).toHaveBeenCalledTimes(8) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234.56', + unmasked: '123456' + }) + }) + + test('input 1234.56 and {backspace}', async (context) => { + await user.type(input, '1234.56{backspace}') + expect(input).toHaveValue('$1,234.5') + + expect(context.preProcess).toHaveBeenCalledTimes(8) + expect(context.postProcess).toHaveBeenCalledTimes(8) + + expect(context.onMaska).toHaveBeenCalledTimes(8) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234.5', + unmasked: '12345' + }) + }) + + test('input 1234.56 and {backspace}×2', async (context) => { + await user.type(input, '1234.56{backspace}{backspace}') + expect(input).toHaveValue('$1,234.') + + expect(context.preProcess).toHaveBeenCalledTimes(9) + expect(context.postProcess).toHaveBeenCalledTimes(9) + + expect(context.onMaska).toHaveBeenCalledTimes(9) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234.', + unmasked: '1234' + }) + }) + + test('input 1234.56 and {backspace}×3', async (context) => { + await user.type(input, '1234.56{backspace}{backspace}{backspace}') + expect(input).toHaveValue('$1,234') + + expect(context.preProcess).toHaveBeenCalledTimes(10) + expect(context.postProcess).toHaveBeenCalledTimes(10) + + expect(context.onMaska).toHaveBeenCalledTimes(10) + expect(context.onMaska).toHaveBeenLastCalledWith({ + completed: true, + masked: '1234', + unmasked: '1234' + }) + }) +}) + describe('test data-attr', () => { function prepareMaskWithHtml(html: string) { document.body.innerHTML = html