UNPKG

rxmask

Version:

Simple, but advanced mask parser for html input or parsing provided string directly

681 lines (645 loc) 25.4 kB
// eslint-disable-next-line spaced-comment /// <reference types="cypress" /> // No way to test true text pasting aside from maybe this: https://github.com/cypress-io/cypress/issues/2752 // Also no way to select text in input for deleting multiple symbols ('should correctly parse multiple deleted characters') except maybe this: https://gist.github.com/erquhart/37bf2d938ab594058e0572ed17d3837a before(() => { cy.visit('http://127.0.0.1:5501/example/example.html'); }); describe('Simple input with values restricted to numbers', () => { afterEach(() => { cy.get('input.simple').clear(); }); it('should correctly apply mask for typed characters', () => { cy.get('input.simple') .should('have.value', '') .type('123') .should('have.value', '123-') .and('have.prop', 'selectionStart', 4) .type('4') .should('have.value', '123-4') .and('have.prop', 'selectionStart', 5) .type('5') .should('have.value', '123-45-') .and('have.prop', 'selectionStart', 7) .type('6') .should('have.value', '123-45-6') .and('have.prop', 'selectionStart', 8) .type('7') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9); }); it('should correctly apply mask for deleted characters', () => { cy.get('input.simple') .type('1234567') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9) .type('{backspace}') .should('have.value', '123-45-6') .and('have.prop', 'selectionStart', 8) .type('{backspace}') .should('have.value', '123-45') .and('have.prop', 'selectionStart', 6) .type('{backspace}') .should('have.value', '123-4') .and('have.prop', 'selectionStart', 5) .type('{backspace}') .should('have.value', '123') .and('have.prop', 'selectionStart', 3) .type('{backspace}{backspace}') .should('have.value', '1') .and('have.prop', 'selectionStart', 1); }); it('should correctly apply mask for typed characters if some characters are present after cursor', () => { cy.get('input.simple') .type('12') .should('have.value', '12') .and('have.prop', 'selectionStart', 2) .type('{leftarrow}{leftarrow}3') .should('have.value', '312-') .and('have.prop', 'selectionStart', 1) .type('4') .should('have.value', '341-2') .and('have.prop', 'selectionStart', 2) .type('56') .should('have.value', '345-61-2') .and('have.prop', 'selectionStart', 5) .type('7') .should('have.value', '345-67-12') .and('have.prop', 'selectionStart', 7); }); it('should correctly apply mask for deleted characters if some characters are present after cursor', () => { cy.get('input.simple') .type('1234567{leftarrow}{leftarrow}{leftarrow}{leftarrow}') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 5) .type('{backspace}') .should('have.value', '123-56-7') .and('have.prop', 'selectionStart', 3) .type('{backspace}') .should('have.value', '125-67') .and('have.prop', 'selectionStart', 2) .type('{backspace}') .should('have.value', '156-7') .and('have.prop', 'selectionStart', 1) .type('{del}') .should('have.value', '167') .and('have.prop', 'selectionStart', 1) .type('{del}') .should('have.value', '17') .and('have.prop', 'selectionStart', 1) .type('{del}') .should('have.value', '1') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', '') .and('have.prop', 'selectionStart', 0); }); it('should correctly parse multiple pasted characters', () => { cy.get('input.simple') .invoke('val', '123') .trigger('input') .should('have.value', '123-') .and('have.prop', 'selectionStart', 4) .clear() .invoke('val', '1234567') .trigger('input') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9) .clear() .invoke('val', '123-45-67') .trigger('input') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9) .clear() .invoke('val', '123-456-7') .trigger('input') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9) .clear() .invoke('val', '-a-12-3&-45$6-G7') .trigger('input') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9); }); it('should not allow to add more characters after mask is complete', () => { cy.get('input.simple') .type('123456') .should('have.value', '123-45-6') .and('have.prop', 'selectionStart', 8) .type('71') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 9) .type('{leftarrow}1') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 8) .type('{leftarrow}{leftarrow}1') .should('have.value', '123-45-67') .and('have.prop', 'selectionStart', 7) .clear() .invoke('val', '87654321') .trigger('input') .should('have.value', '876-54-32') .and('have.prop', 'selectionStart', 9); }); it('should not allow to paste unsupported symbols', () => { cy.get('input.simple') .type('1') .should('have.value', '1') .and('have.prop', 'selectionStart', 1) .type('a') .should('have.value', '1') .and('have.prop', 'selectionStart', 1) .type('2c3&4') .should('have.value', '123-4') .and('have.prop', 'selectionStart', 5) .type('{leftarrow}{leftarrow}{leftarrow}c5G') .should('have.value', '125-34-') .and('have.prop', 'selectionStart', 4); }); }); describe('Input with maxMaskLength', () => { afterEach(() => { cy.get('input.maxMaskLength').clear(); }); it('should correctly apply mask for typed characters', () => { cy.get('input.maxMaskLength') .should('have.value', '+_ (___) ___-__-__') .type('123') .should('have.value', '+1 (23_) ___-__-__') .and('have.prop', 'selectionStart', 6) .type('4') .should('have.value', '+1 (234) ___-__-__') .and('have.prop', 'selectionStart', 9) .type('567') .should('have.value', '+1 (234) 567-__-__') .and('have.prop', 'selectionStart', 13) .type('89') .should('have.value', '+1 (234) 567-89-__') .and('have.prop', 'selectionStart', 16) .type('01') .should('have.value', '+1 (234) 567-89-01') .and('have.prop', 'selectionStart', 18); }); it('should correctly apply mask for deleted characters', () => { cy.get('input.maxMaskLength') .should('have.value', '+_ (___) ___-__-__') .type('12345678901') .should('have.value', '+1 (234) 567-89-01') .and('have.prop', 'selectionStart', 18) .type('{backspace}') .should('have.value', '+1 (234) 567-89-0_') .and('have.prop', 'selectionStart', 17) .type('{backspace}') .should('have.value', '+1 (234) 567-89-__') .and('have.prop', 'selectionStart', 15) .type('{backspace}{backspace}{backspace}{backspace}') .should('have.value', '+1 (234) 5__-__-__') .and('have.prop', 'selectionStart', 10) .type('{backspace}') .should('have.value', '+1 (234) ___-__-__') .and('have.prop', 'selectionStart', 7) .type('{backspace}{backspace}') .should('have.value', '+1 (2__) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('{backspace}') .should('have.value', '+1 (___) ___-__-__') .and('have.prop', 'selectionStart', 2) .type('{backspace}') .should('have.value', '+_ (___) ___-__-__') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', '+_ (___) ___-__-__') .and('have.prop', 'selectionStart', 1); }); it('should correctly apply mask for typed characters if some characters are present after cursor', () => { cy.get('input.maxMaskLength') .should('have.value', '+_ (___) ___-__-__') .type('123') .should('have.value', '+1 (23_) ___-__-__') .and('have.prop', 'selectionStart', 6) .type('{leftarrow}{leftarrow}4') .should('have.value', '+1 (423) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('56') .should('have.value', '+1 (456) 23_-__-__') .and('have.prop', 'selectionStart', 9) .type('78') .should('have.value', '+1 (456) 782-3_-__') .and('have.prop', 'selectionStart', 11) .type('9') .should('have.value', '+1 (456) 789-23-__') .and('have.prop', 'selectionStart', 13) .type('01') .should('have.value', '+1 (456) 789-01-23') .and('have.prop', 'selectionStart', 16); }); it('should correctly apply mask for deleted characters if some characters are present after cursor', () => { cy.get('input.maxMaskLength') .should('have.value', '+_ (___) ___-__-__') .type('12345678901') .should('have.value', '+1 (234) 567-89-01') .and('have.prop', 'selectionStart', 18) .type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}{backspace}') .should('have.value', '+1 (234) 567-90-1_') .and('have.prop', 'selectionStart', 12) .type('{backspace}') .should('have.value', '+1 (234) 569-01-__') .and('have.prop', 'selectionStart', 11) .type('{backspace}{backspace}{backspace}{backspace}') .should('have.value', '+1 (290) 1__-__-__') .and('have.prop', 'selectionStart', 5) .type('{del}') .should('have.value', '+1 (201) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('{del}{del}{del}') .should('have.value', '+1 (2__) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('{backspace}{backspace}{backspace}') .should('have.value', '+_ (___) ___-__-__') .and('have.prop', 'selectionStart', 1); }); }); describe('Input with maxMaskLength and allowed mask symbols', () => { afterEach(() => { cy.get('input.maxMaskLengthSymbols').clear(); }); it('should correctly apply mask for typed characters', () => { cy.get('input.maxMaskLengthSymbols') .should('have.value', '+_ (___) ___-__-__') .type('+ ') .should('have.value', '++ ( __) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('())(') .should('have.value', '++ ( ()) )(_-__-__') .and('have.prop', 'selectionStart', 11) .type('--+ -') .should('have.value', '++ ( ()) )(---+- -') .and('have.prop', 'selectionStart', 18); }); it('should correctly apply mask for deleted characters', () => { cy.get('input.maxMaskLengthSymbols') .should('have.value', '+_ (___) ___-__-__') .type('+ ())(--+ -') .should('have.value', '++ ( ()) )(---+- -') .and('have.prop', 'selectionStart', 18) .type('{backspace}') .should('have.value', '++ ( ()) )(---+- _') .and('have.prop', 'selectionStart', 17) .type('{backspace}') .should('have.value', '++ ( ()) )(---+-__') .and('have.prop', 'selectionStart', 15) .type('{backspace}{backspace}{backspace}{backspace}') .should('have.value', '++ ( ()) )__-__-__') .and('have.prop', 'selectionStart', 10) .type('{backspace}') .should('have.value', '++ ( ()) ___-__-__') .and('have.prop', 'selectionStart', 7) .type('{backspace}{backspace}') .should('have.value', '++ ( __) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('{backspace}') .should('have.value', '++ (___) ___-__-__') .and('have.prop', 'selectionStart', 2) .type('{backspace}') .should('have.value', '+_ (___) ___-__-__') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', '+_ (___) ___-__-__') .and('have.prop', 'selectionStart', 1); }); it('should correctly apply mask for typed characters if some characters are present after cursor', () => { cy.get('input.maxMaskLengthSymbols') .should('have.value', '+_ (___) ___-__-__') .type('+ (') .should('have.value', '++ ( (_) ___-__-__') .and('have.prop', 'selectionStart', 6) .type('{leftarrow}{leftarrow})') .should('have.value', '++ () () ___-__-__') .and('have.prop', 'selectionStart', 5) .type(')(') .should('have.value', '++ ())() (_-__-__') .and('have.prop', 'selectionStart', 9) .type('(-') .should('have.value', '++ ())() (- -(_-__') .and('have.prop', 'selectionStart', 11) .type('-') .should('have.value', '++ ())() (--- (-__') .and('have.prop', 'selectionStart', 13) .type(' -') .should('have.value', '++ ())() (--- -- (') .and('have.prop', 'selectionStart', 16); }); it('should correctly apply mask for deleted characters if some characters are present after cursor', () => { cy.get('input.maxMaskLengthSymbols') .should('have.value', '+_ (___) ___-__-__') .type('+ ())(--+ -') .should('have.value', '++ ( ()) )(---+- -') .and('have.prop', 'selectionStart', 18) .type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}{backspace}') .should('have.value', '++ ( ()) )(--+ --_') .and('have.prop', 'selectionStart', 12) .type('{backspace}') .should('have.value', '++ ( ()) )(+- --__') .and('have.prop', 'selectionStart', 11) .type('{backspace}{backspace}{backspace}{backspace}') .should('have.value', '++ ( + ) -__-__-__') .and('have.prop', 'selectionStart', 5) .type('{del}') .should('have.value', '++ ( -) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('{del}{del}{del}') .should('have.value', '++ ( __) ___-__-__') .and('have.prop', 'selectionStart', 5) .type('{backspace}{backspace}{backspace}') .should('have.value', '+_ (___) ___-__-__') .and('have.prop', 'selectionStart', 1); }); }); describe('Input with partial maxMaskLength and allowed mask symbols', () => { afterEach(() => { cy.get('input.maxMaskLengthPart').clear(); }); it('should correctly apply mask for typed characters', () => { cy.get('input.maxMaskLengthPart') .should('have.value', ' _ [___]') .type('a') .should('have.value', ' a [___]') .and('have.prop', 'selectionStart', 4) .type('12') .should('have.value', ' a [12_]') .and('have.prop', 'selectionStart', 6) .type('3') .should('have.value', ' a [123] [') .and('have.prop', 'selectionStart', 10) .type('$% ') .should('have.value', ' a [123] [$% ] [') .and('have.prop', 'selectionStart', 16) .type('[]') .should('have.value', ' a [123] [$% ] [[]]') .and('have.prop', 'selectionStart', 19); }); it('should correctly apply mask for deleted characters', () => { cy.get('input.maxMaskLengthPart') .should('have.value', ' _ [___]') .type('a123$% []') .should('have.value', ' a [123] [$% ] [[]]') .and('have.prop', 'selectionStart', 19) .type('{backspace}') .should('have.value', ' a [123] [$% ] [[]') .and('have.prop', 'selectionStart', 18) .type('{backspace}') .should('have.value', ' a [123] [$% ] [[') .and('have.prop', 'selectionStart', 17) .type('{backspace}') .should('have.value', ' a [123] [$% ') .and('have.prop', 'selectionStart', 13) .type('{backspace}{backspace}') .should('have.value', ' a [123] [$') .and('have.prop', 'selectionStart', 11) .type('{backspace}') .should('have.value', ' a [123]') .and('have.prop', 'selectionStart', 7) .type('{backspace}{backspace}') .should('have.value', ' a [1__]') .and('have.prop', 'selectionStart', 5) .type('{backspace}') .should('have.value', ' a [___]') .and('have.prop', 'selectionStart', 2) .type('{backspace}') .should('have.value', ' _ [___]') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', ' _ [___]') .and('have.prop', 'selectionStart', 1); }); it('should correctly apply mask for typed characters if some characters are present after cursor', () => { cy.get('input.maxMaskLengthPart') .should('have.value', ' _ [___]') .type('a12') .should('have.value', ' a [12_]') .and('have.prop', 'selectionStart', 6) .type('{leftarrow}{leftarrow}3') .should('have.value', ' a [312] [') .and('have.prop', 'selectionStart', 5) .type('$% ') .should('have.value', ' a [3$%] [ 12] [') .and('have.prop', 'selectionStart', 11) .type('[]') .should('have.value', ' a [3$%] [ []] [12]') .and('have.prop', 'selectionStart', 16); }); it('should correctly apply mask for deleted characters if some characters are present after cursor', () => { cy.get('input.maxMaskLengthPart') .should('have.value', ' _ [___]') .type('a123$% []') .should('have.value', ' a [123] [$% ] [[]]') .and('have.prop', 'selectionStart', 19) .type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{backspace}') .should('have.value', ' a [123] [% [] []') .and('have.prop', 'selectionStart', 7) .type('{backspace}') .should('have.value', ' a [12%] [ []') .and('have.prop', 'selectionStart', 6) .type('{del}{del}') .should('have.value', ' a [12[] []') .and('have.prop', 'selectionStart', 6) .type('{del}') .should('have.value', ' a [12]]') .and('have.prop', 'selectionStart', 6) .type('{del}') .should('have.value', ' a [12_]') .and('have.prop', 'selectionStart', 6) .type('{backspace}{backspace}{backspace}{backspace}') .should('have.value', ' _ [___]') .and('have.prop', 'selectionStart', 1); }); }); describe('Input with partial maxMaskLength, allowed mask symbols and trailing is disabled', () => { afterEach(() => { cy.get('input.maxMaskLengthPartNoTrailing').clear(); }); it('should correctly apply mask for typed characters', () => { cy.get('input.maxMaskLengthPartNoTrailing') .should('have.value', ' _ [___]') .type('a') .should('have.value', ' a [___]') .and('have.prop', 'selectionStart', 2) .type('12') .should('have.value', ' a [12_]') .and('have.prop', 'selectionStart', 6) .type('3') .should('have.value', ' a [123]') .and('have.prop', 'selectionStart', 7) .type('$% ') .should('have.value', ' a [123] [$% ') .and('have.prop', 'selectionStart', 13) .type('[]') .should('have.value', ' a [123] [$% ] [[]]') .and('have.prop', 'selectionStart', 18); }); it('should correctly apply mask for deleted characters', () => { cy.get('input.maxMaskLengthPartNoTrailing') .should('have.value', ' _ [___]') .type('a123$% []') .should('have.value', ' a [123] [$% ] [[]]') .and('have.prop', 'selectionStart', 18) .type('{backspace}') .should('have.value', ' a [123] [$% ] [[') .and('have.prop', 'selectionStart', 17) .type('{backspace}') .should('have.value', ' a [123] [$% ') .and('have.prop', 'selectionStart', 13) .type('{backspace}{backspace}') .should('have.value', ' a [123] [$') .and('have.prop', 'selectionStart', 11) .type('{backspace}') .should('have.value', ' a [123]') .and('have.prop', 'selectionStart', 7) .type('{backspace}{backspace}') .should('have.value', ' a [1__]') .and('have.prop', 'selectionStart', 5) .type('{backspace}') .should('have.value', ' a [___]') .and('have.prop', 'selectionStart', 2) .type('{backspace}') .should('have.value', ' _ [___]') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', ' _ [___]') .and('have.prop', 'selectionStart', 1); }); it('should correctly apply mask for typed characters if some characters are present after cursor', () => { cy.get('input.maxMaskLengthPartNoTrailing') .should('have.value', ' _ [___]') .type('a12') .should('have.value', ' a [12_]') .and('have.prop', 'selectionStart', 6) .type('{leftarrow}{leftarrow}3') .should('have.value', ' a [312]') .and('have.prop', 'selectionStart', 5) .type('$% ') .should('have.value', ' a [3$%] [ 12') .and('have.prop', 'selectionStart', 11) .type('[]') .should('have.value', ' a [3$%] [ []] [12]') .and('have.prop', 'selectionStart', 13); }); it('should correctly apply mask for deleted characters if some characters are present after cursor', () => { cy.get('input.maxMaskLengthPartNoTrailing') .should('have.value', ' _ [___]') .type('a123$% []') .should('have.value', ' a [123] [$% ] [[]]') .and('have.prop', 'selectionStart', 18) .type('{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{leftarrow}{backspace}') .should('have.value', ' a [123] [% [] []') .and('have.prop', 'selectionStart', 7) .type('{backspace}') .should('have.value', ' a [12%] [ []') .and('have.prop', 'selectionStart', 6) .type('{del}{del}') .should('have.value', ' a [12[] []') .and('have.prop', 'selectionStart', 6) .type('{del}') .should('have.value', ' a [12]]') .and('have.prop', 'selectionStart', 6) .type('{del}') .should('have.value', ' a [12_]') .and('have.prop', 'selectionStart', 6) .type('{backspace}{backspace}{backspace}{backspace}') .should('have.value', ' _ [___]') .and('have.prop', 'selectionStart', 1); }); }); describe('Input with maxMaskLength and regex mask', () => { afterEach(() => { cy.get('input.regex').clear(); }); it('should correctly apply mask for typed characters', () => { cy.get('input.regex') .should('have.value', '** ***-**') .type('1A') .should('have.value', 'A* ***-**') .and('have.prop', 'selectionStart', 1) .type('bB54') .should('have.value', 'AB 4**-**') .and('have.prop', 'selectionStart', 4) .type('5a6') .should('have.value', 'AB 456-**') .and('have.prop', 'selectionStart', 7) .type('1Aa1') .should('have.value', 'AB 456-a1') .and('have.prop', 'selectionStart', 9); }); it('should correctly apply mask for deleted characters', () => { cy.get('input.regex') .should('have.value', '** ***-**') .type('AB456a1') .should('have.value', 'AB 456-a1') .and('have.prop', 'selectionStart', 9) .type('{backspace}') .should('have.value', 'AB 456-a*') .and('have.prop', 'selectionStart', 8) .type('{backspace}') .should('have.value', 'AB 456-**') .and('have.prop', 'selectionStart', 6) .type('{backspace}{backspace}') .should('have.value', 'AB 4**-**') .and('have.prop', 'selectionStart', 4) .type('{backspace}') .should('have.value', 'AB ***-**') .and('have.prop', 'selectionStart', 2) .type('{backspace}') .should('have.value', 'A* ***-**') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', '** ***-**') .and('have.prop', 'selectionStart', 0) .type('{backspace}') .should('have.value', '** ***-**') .and('have.prop', 'selectionStart', 0); }); it('should correctly apply mask for typed characters if some characters are present after cursor', () => { cy.get('input.regex') .should('have.value', '** ***-**') .type('1A') .should('have.value', 'A* ***-**') .and('have.prop', 'selectionStart', 1) .type('bB54') .should('have.value', 'AB 4**-**') .and('have.prop', 'selectionStart', 4) .type('{leftarrow}{leftarrow}5a61') .should('have.value', 'AB 14*-**') .and('have.prop', 'selectionStart', 4) .type('2Aa3') .should('have.value', 'AB 123-**') .and('have.prop', 'selectionStart', 7) .type('a1') .should('have.value', 'AB 123-a1') .and('have.prop', 'selectionStart', 9); }); it('should correctly apply mask for deleted characters if some characters are present after cursor', () => { cy.get('input.regex') .should('have.value', '** ***-**') .type('AB456a1') .should('have.value', 'AB 456-a1') .and('have.prop', 'selectionStart', 9) .type('{backspace}') .should('have.value', 'AB 456-a*') .and('have.prop', 'selectionStart', 8) .type('{backspace}') .should('have.value', 'AB 456-**') .and('have.prop', 'selectionStart', 6) .type('{leftarrow}{leftarrow}{del}') .should('have.value', 'AB 46*-**') .and('have.prop', 'selectionStart', 4) .type('{leftarrow}{leftarrow}{leftarrow}{del}') .should('have.value', 'A* ***-**') .and('have.prop', 'selectionStart', 1) .type('{backspace}') .should('have.value', '** ***-**') .and('have.prop', 'selectionStart', 0) .type('{backspace}') .should('have.value', '** ***-**') .and('have.prop', 'selectionStart', 0); }); });