Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forms: add date validation in all browsers #41698

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed

Forms: updates the way that we valdate date info by removing jquery
11 changes: 5 additions & 6 deletions projects/packages/forms/src/contact-form/js/accessible-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* (multiple radio buttons) or Multiple Choice fields (multiple checkboxes).
*/

import { validateDate } from './validate-helper';

document.addEventListener( 'DOMContentLoaded', () => {
initAllForms();
} );
Expand Down Expand Up @@ -264,15 +266,12 @@ const isMultipleChoiceFieldValid = fieldset => {
const isDateFieldValid = input => {
const format = input.getAttribute( 'data-format' );
const value = input.value;
const $ = window.jQuery;

if ( value && format && typeof $ !== 'undefined' ) {
try {
$.datepicker.parseDate( format, value );
if ( value && format ) {
if ( validateDate( value, format ) ) {
input.setCustomValidity( '' );
} catch {
} else {
input.setCustomValidity( L10N.invalidDate );

return false;
}
}
Expand Down
38 changes: 38 additions & 0 deletions projects/packages/forms/src/contact-form/js/validate-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Validate the date Value based on the format of the date field.
*
* @param {string} value Date value
* @param {string} format Date format
*
* @returns {boolean}
*/
export const validateDate = ( value, format ) => {
let year, month, day;

if ( ! value ) {
return false;
}
switch ( format ) {
case 'mm/dd/yy':
[ month, day, year ] = value.split( '/' ).map( Number );
break;

case 'dd/mm/yy':
[ day, month, year ] = value.split( '/' ).map( Number );
break;

case 'yy-mm-dd':
[ year, month, day ] = value.split( '-' ).map( Number );
break;

default:
return false;
}
if ( isNaN( year ) || isNaN( month ) || isNaN( day ) ) {
return false;
}

const date = new Date( year, month - 1, day );

return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Add these mocks at the top of your test file
import { validateDate } from '../../../src/contact-form/js/validate-helper';

describe( 'validateDate', () => {
// Test mm/dd/yy format
describe( 'mm/dd/yy format', () => {
const format = 'mm/dd/yy';

test( 'validates correct dates', () => {
expect( validateDate( '12/31/2023', format ) ).toBe( true );
expect( validateDate( '01/01/2024', format ) ).toBe( true );
expect( validateDate( '02/29/2024', format ) ).toBe( true ); // leap year
} );

test( 'invalidates incorrect dates', () => {
expect( validateDate( '13/01/2023', format ) ).toBe( false ); // invalid month
expect( validateDate( '00/01/2023', format ) ).toBe( false ); // invalid month
expect( validateDate( '12/32/2023', format ) ).toBe( false ); // invalid day
expect( validateDate( '12/00/2023', format ) ).toBe( false ); // invalid day
expect( validateDate( '02/29/2023', format ) ).toBe( false ); // not a leap year
} );

test( 'invalidates malformed inputs', () => {
expect( validateDate( '12-31-2023', format ) ).toBe( false ); // wrong separator
expect( validateDate( '12/31/', format ) ).toBe( false ); // incomplete
expect( validateDate( 'abc', format ) ).toBe( false ); // nonsense input
} );
} );

// Test dd/mm/yy format
describe( 'dd/mm/yy format', () => {
const format = 'dd/mm/yy';

test( 'validates correct dates', () => {
expect( validateDate( '31/12/2023', format ) ).toBe( true );
expect( validateDate( '01/01/2024', format ) ).toBe( true );
expect( validateDate( '29/02/2024', format ) ).toBe( true ); // leap year
} );

test( 'invalidates incorrect dates', () => {
expect( validateDate( '32/12/2023', format ) ).toBe( false ); // invalid day
expect( validateDate( '00/12/2023', format ) ).toBe( false ); // invalid day
expect( validateDate( '31/13/2023', format ) ).toBe( false ); // invalid month
expect( validateDate( '31/00/2023', format ) ).toBe( false ); // invalid month
expect( validateDate( '29/02/2023', format ) ).toBe( false ); // not a leap year
} );

test( 'invalidates malformed inputs', () => {
expect( validateDate( '31-12-2023', format ) ).toBe( false ); // wrong separator
expect( validateDate( '31/12/', format ) ).toBe( false ); // incomplete
expect( validateDate( 'abc', format ) ).toBe( false ); // nonsense input
} );
} );

// Test yy-mm-dd format
describe( 'yy-mm-dd format', () => {
const format = 'yy-mm-dd';

test( 'validates correct dates', () => {
expect( validateDate( '2023-12-31', format ) ).toBe( true );
expect( validateDate( '2024-01-01', format ) ).toBe( true );
expect( validateDate( '2024-02-29', format ) ).toBe( true ); // leap year
} );

test( 'invalidates incorrect dates', () => {
expect( validateDate( '2023-13-01', format ) ).toBe( false ); // invalid month
expect( validateDate( '2023-00-01', format ) ).toBe( false ); // invalid month
expect( validateDate( '2023-12-32', format ) ).toBe( false ); // invalid day
expect( validateDate( '2023-12-00', format ) ).toBe( false ); // invalid day
expect( validateDate( '2023-02-29', format ) ).toBe( false ); // not a leap year
} );

test( 'invalidates malformed inputs', () => {
expect( validateDate( '2023/12/31', format ) ).toBe( false ); // wrong separator
expect( validateDate( '2023-12-', format ) ).toBe( false ); // incomplete
expect( validateDate( 'abc', format ) ).toBe( false ); // nonsense input
} );
} );

// Test invalid format
test( 'returns false for invalid format', () => {
expect( validateDate( '12/31/2023', 'invalid-format' ) ).toBe( false );
} );

// Test empty/null inputs
test( 'handles empty/null inputs', () => {
expect( validateDate( '', 'mm/dd/yy' ) ).toBe( false );
expect( validateDate( null, 'mm/dd/yy' ) ).toBe( false );
expect( validateDate( undefined, 'mm/dd/yy' ) ).toBe( false );
} );
} );
8 changes: 8 additions & 0 deletions projects/packages/forms/tests/js/contact-form/wp-mocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
global.wp = {
i18n: {
__: jest.fn().mockImplementation( str => str ),
_n: jest
.fn()
.mockImplementation( ( single, plural, number ) => ( number === 1 ? single : plural ) ),
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: other

not useful since it doesn't completly remove jquery from the front end
Loading