From 6778cf6d381e28a9659ca3c0d60c5ecce2af2c9c Mon Sep 17 00:00:00 2001 From: Jamie Burchell Date: Fri, 12 Dec 2025 11:05:10 +0000 Subject: [PATCH 1/4] Fix checkbox toggle functionality --- assets/src/js/_acf-field-checkbox.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/assets/src/js/_acf-field-checkbox.js b/assets/src/js/_acf-field-checkbox.js index 3ade175a..1ff5e605 100644 --- a/assets/src/js/_acf-field-checkbox.js +++ b/assets/src/js/_acf-field-checkbox.js @@ -77,14 +77,12 @@ onClickToggle: function ( e, $el ) { // Vars. - const inputs = this.$inputs(); - const hasUnchecked = $inputs.not( ':checked' ).length > 0; - inputs.each( function () { - $inputs.each( function () { - jQuery( this ) - .prop( 'checked', hasUnchecked ) - .trigger( 'change' ); - } ); + var $inputs = this.$inputs(); + var hasUnchecked = $inputs.not( ':checked' ).length > 0; + $inputs.each( function () { + $( this ) + .prop( 'checked', hasUnchecked ) + .trigger( 'change' ); } ); $el.prop( 'checked', hasUnchecked ); }, From ab589f4c6af61e3a0e61f8b8d28cfa12c0b987c9 Mon Sep 17 00:00:00 2001 From: Jamie Burchell Date: Fri, 12 Dec 2025 11:14:40 +0000 Subject: [PATCH 2/4] Simplify checkbox toggle logic --- assets/src/js/_acf-field-checkbox.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/assets/src/js/_acf-field-checkbox.js b/assets/src/js/_acf-field-checkbox.js index 1ff5e605..3a1add32 100644 --- a/assets/src/js/_acf-field-checkbox.js +++ b/assets/src/js/_acf-field-checkbox.js @@ -79,11 +79,7 @@ // Vars. var $inputs = this.$inputs(); var hasUnchecked = $inputs.not( ':checked' ).length > 0; - $inputs.each( function () { - $( this ) - .prop( 'checked', hasUnchecked ) - .trigger( 'change' ); - } ); + $inputs.prop( 'checked', hasUnchecked ).trigger( 'change' ); $el.prop( 'checked', hasUnchecked ); }, From d0b6112c60b2dbdc7cf9490308c7e0724242d3d5 Mon Sep 17 00:00:00 2001 From: Jamie Burchell Date: Fri, 12 Dec 2025 11:23:47 +0000 Subject: [PATCH 3/4] Further simplification of toggle logic --- assets/src/js/_acf-field-checkbox.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/assets/src/js/_acf-field-checkbox.js b/assets/src/js/_acf-field-checkbox.js index 3a1add32..50021f8f 100644 --- a/assets/src/js/_acf-field-checkbox.js +++ b/assets/src/js/_acf-field-checkbox.js @@ -76,11 +76,9 @@ }, onClickToggle: function ( e, $el ) { - // Vars. var $inputs = this.$inputs(); - var hasUnchecked = $inputs.not( ':checked' ).length > 0; - $inputs.prop( 'checked', hasUnchecked ).trigger( 'change' ); - $el.prop( 'checked', hasUnchecked ); + var checked = $el.prop( 'checked' ); + $inputs.prop( 'checked', checked ).trigger( 'change' ); }, onClickCustom: function ( e, $el ) { From a0042e442eee17db5a04bac228f1ace34dcd37bf Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Tue, 16 Dec 2025 15:50:43 +0100 Subject: [PATCH 4/4] Add unit tests --- tests/js/fields/checkbox.test.js | 82 ++++++++++++++++++++++++++++++++ tests/js/setup-tests.js | 8 ++++ 2 files changed, 90 insertions(+) create mode 100644 tests/js/fields/checkbox.test.js diff --git a/tests/js/fields/checkbox.test.js b/tests/js/fields/checkbox.test.js new file mode 100644 index 00000000..3f9c5db4 --- /dev/null +++ b/tests/js/fields/checkbox.test.js @@ -0,0 +1,82 @@ +/** + * Unit tests for checkbox field type + */ + +describe( 'Checkbox Field', () => { + let fieldDefinition; + let mockField; + + beforeEach( () => { + // Reset mocks + fieldDefinition = null; + + // Mock acf.Field.extend to capture the field definition + global.acf = { + Field: { + extend: jest.fn( ( definition ) => { + fieldDefinition = definition; + return definition; + } ), + }, + registerFieldType: jest.fn(), + }; + + // Load the checkbox field module (this will call acf.Field.extend) + jest.isolateModules( () => { + require( '../../../assets/src/js/_acf-field-checkbox.js' ); + } ); + + // Create a mock field instance with the captured definition + mockField = { + ...fieldDefinition, + $: jest.fn(), + }; + } ); + + afterEach( () => { + delete global.acf; + } ); + + describe( 'onClickToggle', () => { + it( 'should check all inputs when toggle is checked', () => { + // Mock $inputs with chainable jQuery methods + const mockInputs = { + prop: jest.fn().mockReturnThis(), + trigger: jest.fn().mockReturnThis(), + }; + + // Mock $el (the toggle checkbox) as checked + const mockToggle = { + prop: jest.fn().mockReturnValue( true ), + }; + + // Mock this.$inputs() to return our mock + mockField.$inputs = jest.fn().mockReturnValue( mockInputs ); + + // Call the method + fieldDefinition.onClickToggle.call( mockField, {}, mockToggle ); + + // Verify all inputs were checked + expect( mockInputs.prop ).toHaveBeenCalledWith( 'checked', true ); + expect( mockInputs.trigger ).toHaveBeenCalledWith( 'change' ); + } ); + + it( 'should uncheck all inputs when toggle is unchecked', () => { + const mockInputs = { + prop: jest.fn().mockReturnThis(), + trigger: jest.fn().mockReturnThis(), + }; + + const mockToggle = { + prop: jest.fn().mockReturnValue( false ), + }; + + mockField.$inputs = jest.fn().mockReturnValue( mockInputs ); + + fieldDefinition.onClickToggle.call( mockField, {}, mockToggle ); + + expect( mockInputs.prop ).toHaveBeenCalledWith( 'checked', false ); + expect( mockInputs.trigger ).toHaveBeenCalledWith( 'change' ); + } ); + } ); +} ); diff --git a/tests/js/setup-tests.js b/tests/js/setup-tests.js index 2c57f35d..1c576833 100644 --- a/tests/js/setup-tests.js +++ b/tests/js/setup-tests.js @@ -17,6 +17,14 @@ global.jQuery = jest.fn( ( html ) => { } ); global.$ = global.jQuery; +// Mock ACF global for field type tests +global.acf = { + Field: { + extend: jest.fn( ( def ) => def ), + }, + registerFieldType: jest.fn(), +}; + // Mock WordPress packages that are externalized jest.mock( '@wordpress/data',