From 85d280ab838b9edf5ecf9d378d8eae277a590c4a Mon Sep 17 00:00:00 2001 From: Michael Rigsby Date: Sun, 22 Mar 2026 19:56:16 -0400 Subject: [PATCH 1/7] ValidationService logic modifcation and tests --- models/Component.cfc | 6 +- models/services/ValidationService.cfc | 8 +- test-harness/models/validationTest.cfc | 21 +++++ .../unit/services/ValidationServiceSpec.cfc | 80 ++++++++++++++++++- 4 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 test-harness/models/validationTest.cfc diff --git a/models/Component.cfc b/models/Component.cfc index 606bf24..9912825 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -360,7 +360,7 @@ component output="true" accessors="true" { // Determine if component should be lazy loaded // If lazy parameter is explicitly provided, use that value // Otherwise, use the component's lazy preference - local.shouldLazyLoad = isNull( arguments.lazy ) ? + local.shouldLazyLoad = isNull( arguments.lazy ) ? local.instance._getLazyLoad() : // Use component's preference if no explicit parameter arguments.lazy; // Use explicit parameter value @@ -1115,7 +1115,9 @@ component output="true" accessors="true" { function _getConstraints(){ if ( variables.keyExists( "constraints" ) ) { return variables.constraints; - } + }else if ( structKeyExists( this, "constraints" ) ) { + return this.constraints; + } return [:]; } diff --git a/models/services/ValidationService.cfc b/models/services/ValidationService.cfc index 81b2dc2..0894415 100644 --- a/models/services/ValidationService.cfc +++ b/models/services/ValidationService.cfc @@ -45,8 +45,12 @@ component accessors="true" singleton { * @return ValidationResult The result of the validation operation. */ function validate( wire, target, fields, constraints, locale, excludeFields, includeFields, profiles ){ - arguments.target = isNull( arguments.target ) ? arguments.wire._getDataProperties() : arguments.target; - arguments.constraints = isNull( arguments.constraints ) ? arguments.wire._getConstraints() : arguments.constraints; + if( isNull( arguments.target ) ){ + // if no target is provided, default to the wire's data properties + arguments.target = arguments.wire._getDataProperties(); + // use the wire's constraints if explicit constraints are not provided + arguments.constraints = isNull( arguments.constraints ) ? arguments.wire._getConstraints() : arguments.constraints + } return getManager().validate( argumentCollection = arguments ); } diff --git a/test-harness/models/validationTest.cfc b/test-harness/models/validationTest.cfc new file mode 100644 index 0000000..d172f17 --- /dev/null +++ b/test-harness/models/validationTest.cfc @@ -0,0 +1,21 @@ +component accessors="true" { + + property name="FirstName"; + property name="LastName"; + + this.constraints = { + FirstName : { + required : true, + requiredMessage : "First name is required", + size : "2..50", + sizeMessage : "First name must be 2-50 characters" + }, + LastName : { + required : true, + requiredMessage : "Last name is required", + size : "2..50", + sizeMessage : "Last name must be 2-50 characters" + } + }; + +} \ No newline at end of file diff --git a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc index 559acf2..6275177 100644 --- a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc +++ b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc @@ -40,7 +40,8 @@ component extends="coldbox.system.testing.BaseTestCase" { }); describe( "validate()", function() { - it( "should validate with given target and constraints", function() { + + it( "should validate with given target and constraints", function() { var wire = {}; var target = { "foo": "bar" }; var constraints = { "foo": { "required": true } }; @@ -61,6 +62,83 @@ component extends="coldbox.system.testing.BaseTestCase" { var result = validationService.validate( wire ); expect( result ).toHaveKey( "ok" ); }); + + it( "shoud validate an object other than the wire itself", function() { + var oValidationTest = getInstance( "validationTest" ); + var wire = prepareMock( createStub() ); + wire.$( "_getDataProperties", { "bar": "baz" } ); + wire.$( "_getConstraints", { "bar": { "required": true } } ); + // mock the validate method to return the arguments passed to it so that + // we can validate that the correct mutation of the arguments is occurring + // in the validate() method of the service + mockValidationManager.$( + method = "validate", + callback = function() { + return arguments; + } + ); + var result = validationService.validate( wire=wire, target=oValidationTest ); + // validate that we do not have the wires constraints and that there + // are no constraints passed to validate() method so that the constraints + // from the object will be used + expect( result ).notToHaveKey( "constraints" ); + // validate that we have a target passed into the validate method + expect( result ).toHaveKey( "target" ); + // validate that the target contains the constraints from the object + expect( result.target ).toHaveKey( "constraints" ); + expect( result.target.constraints ).toBeTypeOf( "struct" ); + expect( result.target.constraints ).toHaveLength( 2 ); + expect( result.target.constraints ).toHaveKey( "firstname" ); + expect( result.target.constraints ).toHaveKey( "lastname" ); + expect( result.target.constraints ).notToHaveKey( "bar" ); + // get the metadata of the target to validate that it is the correct object and not the wire + var resultTargetMetaData = getMetadata( result.target ); + // validate that the target metadata contains the name of the component (validationTest) + expect( resultTargetMetaData ).toHaveKey( "name" ); + expect( resultTargetMetaData.name ).toInclude( "validationTest" ); + }); + + it( "shoud validate an object other than the wire itself with custom validation constraints", function() { + var oValidationTest = getInstance( "validationTest" ); + var wire = prepareMock( createStub() ); + wire.$( "_getDataProperties", { "bar": "baz" } ); + wire.$( "_getConstraints", { "bar": { "required": true } } ); + var customConstraints = { + password : { + required : true, + requiredMessage : "Password is required", + size : "8..50", + sizeMessage : "Password name must be 2-50 characters" + } + }; + // mock the validate method to return the arguments passed to it so that + // we can validate that the correct mutation of the arguments is occurring + // in the validate() method of the service + mockValidationManager.$( + method = "validate", + callback = function() { + return arguments; + } + ); + var result = validationService.validate( wire=wire, target=oValidationTest, constraints=customConstraints ); + // validate that we do not have the wires constraints and that the constraints + // passed to the validate() method are the custom constraints and not the objects + // or wires constraints + expect( result ).toHaveKey( "constraints" ); + expect( result.constraints ).toBeTypeOf( "struct" ); + expect( result.constraints ).toHaveLength( 1 ); + expect( result.constraints ).toHaveKey( "password" ); + expect( result.constraints ).notToHaveKey( "lastname" ); + expect( result.constraints ).notToHaveKey( "bar" ); + // validate that we have a target passed into the validate method + expect( result ).toHaveKey( "target" ); + // get the metadata of the target to validate that it is the correct object and not the wire + var resultTargetMetaData = getMetadata( result.target ); + // validate that the target metadata contains the name of the component (validationTest) + expect( resultTargetMetaData ).toHaveKey( "name" ); + expect( resultTargetMetaData.name ).toInclude( "validationTest" ); + }); + }); describe( "validateOrFail()", function() { From 756f0c42f039825b000ccf6970d739e0bcc23052 Mon Sep 17 00:00:00 2001 From: Michael Rigsby Date: Sun, 22 Mar 2026 20:41:09 -0400 Subject: [PATCH 2/7] add tests for this.constraints= verses constraints= --- test-harness/tests/specs/CBWIRESpec.cfc | 27 +++++++++++++++---- .../test/validation/validateConstraints1.cfc | 20 ++++++++++++++ .../test/validation/validateConstraints1.cfm | 6 +++++ .../test/validation/validateConstraints2.cfc | 20 ++++++++++++++ .../test/validation/validateConstraints2.cfm | 6 +++++ 5 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 test-harness/wires/test/validation/validateConstraints1.cfc create mode 100644 test-harness/wires/test/validation/validateConstraints1.cfm create mode 100644 test-harness/wires/test/validation/validateConstraints2.cfc create mode 100644 test-harness/wires/test/validation/validateConstraints2.cfm diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc index 5c5aafe..7fd2dd7 100644 --- a/test-harness/tests/specs/CBWIRESpec.cfc +++ b/test-harness/tests/specs/CBWIRESpec.cfc @@ -577,6 +577,23 @@ component extends="coldbox.system.testing.BaseTestCase" { expect( renderedHtml ).toInclude( 'Some&##x20;text&##x20;with&##x20;&##x5c;"quotes' ); }); + it("should get constraints when set using this.constraints= ", function() { + var testValidationComponent = getInstance("wires.test.validation.validateConstraints1"); + var constraints = testValidationComponent._getConstraints(); + expect( constraints ).toBeTypeOf( "struct" ); + expect( constraints ).toHaveLength( 1 ); + expect( constraints ).toHaveKey( "firstname" ); + }); + + it("should get constraints when set using constraints= ", function() { + var testValidationComponent = getInstance("wires.test.validation.validateConstraints2"); + var constraints = testValidationComponent._getConstraints(); + expect( constraints ).toBeTypeOf( "struct" ); + expect( constraints ).toHaveLength( 1 ); + expect( constraints ).toHaveKey( "firstname" ); + }); + + }); describe("Incoming Requests", function() { @@ -727,7 +744,7 @@ component extends="coldbox.system.testing.BaseTestCase" { var settings = getInstance( "coldbox:modulesettings:cbwire" ); var originalSetting = settings.csrfEnabled; settings.csrfEnabled = false; - + var payload = incomingRequest( memo = { "name": "TestComponent", @@ -747,12 +764,12 @@ component extends="coldbox.system.testing.BaseTestCase" { updates = {}, csrfToken = "badToken" ); - + // Should not throw an error even with bad token when CSRF is disabled var response = cbwireController.handleRequest( payload, event ); expect( isStruct( response ) ).toBeTrue(); expect( response.components[1].effects.html ).toInclude( "CBWIRE Slays!" ); - + // Restore original setting settings.csrfEnabled = originalSetting; } ); @@ -761,10 +778,10 @@ component extends="coldbox.system.testing.BaseTestCase" { var settings = getInstance( "coldbox:modulesettings:cbwire" ); var originalSetting = settings.csrfEnabled; settings.csrfEnabled = false; - + var token = cbwireController.generateCSRFToken(); expect( token ).toBe( "" ); - + // Restore original setting settings.csrfEnabled = originalSetting; } ); diff --git a/test-harness/wires/test/validation/validateConstraints1.cfc b/test-harness/wires/test/validation/validateConstraints1.cfc new file mode 100644 index 0000000..03a5aaa --- /dev/null +++ b/test-harness/wires/test/validation/validateConstraints1.cfc @@ -0,0 +1,20 @@ +component extends="cbwire.models.Component" { + + data = { + "firstname": "sdfsad", + "lastname": "" + } + /* + This components DOES use this.constraints= + + The cbwire documentation states that you can define constraints using constraints= + https://cbwire.ortusbooks.com/features/form-validation + + CBValidation documentation states that you define constraints using this.constraints= + https://coldbox-validation.ortusbooks.com/overview/declaring-constraints/domain-object + */ + this.constraints = { + "firstname": { required: true } + }; + +} \ No newline at end of file diff --git a/test-harness/wires/test/validation/validateConstraints1.cfm b/test-harness/wires/test/validation/validateConstraints1.cfm new file mode 100644 index 0000000..3534b82 --- /dev/null +++ b/test-harness/wires/test/validation/validateConstraints1.cfm @@ -0,0 +1,6 @@ + +
+ + +
+
\ No newline at end of file diff --git a/test-harness/wires/test/validation/validateConstraints2.cfc b/test-harness/wires/test/validation/validateConstraints2.cfc new file mode 100644 index 0000000..f2da217 --- /dev/null +++ b/test-harness/wires/test/validation/validateConstraints2.cfc @@ -0,0 +1,20 @@ +component extends="cbwire.models.Component" { + + data = { + "firstname": "sdfsad", + "lastname": "" + } + /* + This components DOES use constraints= + + The cbwire documentation states that you can define constraints using constraints= + https://cbwire.ortusbooks.com/features/form-validation + + CBValidation documentation states that you define constraints using this.constraints= + https://coldbox-validation.ortusbooks.com/overview/declaring-constraints/domain-object + */ + constraints = { + "firstname": { required: true } + }; + +} \ No newline at end of file diff --git a/test-harness/wires/test/validation/validateConstraints2.cfm b/test-harness/wires/test/validation/validateConstraints2.cfm new file mode 100644 index 0000000..3534b82 --- /dev/null +++ b/test-harness/wires/test/validation/validateConstraints2.cfm @@ -0,0 +1,6 @@ + +
+ + +
+
\ No newline at end of file From c90d36d229f908221801ae38c8b793b7d40da57b Mon Sep 17 00:00:00 2001 From: Grant Copley Date: Mon, 23 Mar 2026 10:52:23 -0500 Subject: [PATCH 3/7] Update test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tests/specs/unit/services/ValidationServiceSpec.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc index 6275177..795c945 100644 --- a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc +++ b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc @@ -108,7 +108,7 @@ component extends="coldbox.system.testing.BaseTestCase" { required : true, requiredMessage : "Password is required", size : "8..50", - sizeMessage : "Password name must be 2-50 characters" + sizeMessage : "Password must be 8-50 characters" } }; // mock the validate method to return the arguments passed to it so that From a53389f83e92a72283187283bb87d0ca3a99c279 Mon Sep 17 00:00:00 2001 From: Grant Copley Date: Mon, 23 Mar 2026 10:52:38 -0500 Subject: [PATCH 4/7] Update test-harness/wires/test/validation/validateConstraints1.cfc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- test-harness/wires/test/validation/validateConstraints1.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-harness/wires/test/validation/validateConstraints1.cfc b/test-harness/wires/test/validation/validateConstraints1.cfc index 03a5aaa..70d89dd 100644 --- a/test-harness/wires/test/validation/validateConstraints1.cfc +++ b/test-harness/wires/test/validation/validateConstraints1.cfc @@ -3,7 +3,7 @@ component extends="cbwire.models.Component" { data = { "firstname": "sdfsad", "lastname": "" - } + }; /* This components DOES use this.constraints= From fcfa313b244c14c73b93125a732bd7800f0efc9d Mon Sep 17 00:00:00 2001 From: Grant Copley Date: Mon, 23 Mar 2026 10:52:57 -0500 Subject: [PATCH 5/7] Update test-harness/wires/test/validation/validateConstraints2.cfc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- test-harness/wires/test/validation/validateConstraints2.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-harness/wires/test/validation/validateConstraints2.cfc b/test-harness/wires/test/validation/validateConstraints2.cfc index f2da217..2955ebe 100644 --- a/test-harness/wires/test/validation/validateConstraints2.cfc +++ b/test-harness/wires/test/validation/validateConstraints2.cfc @@ -3,7 +3,7 @@ component extends="cbwire.models.Component" { data = { "firstname": "sdfsad", "lastname": "" - } + }; /* This components DOES use constraints= From 8498e2ebc59529bd36dbe40673f3f2dd6e9fbbfd Mon Sep 17 00:00:00 2001 From: Grant Copley Date: Mon, 23 Mar 2026 10:53:17 -0500 Subject: [PATCH 6/7] Update test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../tests/specs/unit/services/ValidationServiceSpec.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc index 795c945..83f9b5b 100644 --- a/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc +++ b/test-harness/tests/specs/unit/services/ValidationServiceSpec.cfc @@ -63,7 +63,7 @@ component extends="coldbox.system.testing.BaseTestCase" { expect( result ).toHaveKey( "ok" ); }); - it( "shoud validate an object other than the wire itself", function() { + it( "should validate an object other than the wire itself", function() { var oValidationTest = getInstance( "validationTest" ); var wire = prepareMock( createStub() ); wire.$( "_getDataProperties", { "bar": "baz" } ); From 68676fa9fba8c17484f8a4f525014e2a5f4c395a Mon Sep 17 00:00:00 2001 From: Grant Copley Date: Mon, 23 Mar 2026 10:54:26 -0500 Subject: [PATCH 7/7] Update test-harness/tests/specs/CBWIRESpec.cfc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- test-harness/tests/specs/CBWIRESpec.cfc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc index 7fd2dd7..a90b7ea 100644 --- a/test-harness/tests/specs/CBWIRESpec.cfc +++ b/test-harness/tests/specs/CBWIRESpec.cfc @@ -575,26 +575,26 @@ component extends="coldbox.system.testing.BaseTestCase" { ); expect( renderedHtml ).toInclude( 'Some&##x20;text&##x20;with&##x20;&##x5c;"quotes' ); - }); + } ); - it("should get constraints when set using this.constraints= ", function() { + it( "should get constraints when set using this.constraints=", function() { var testValidationComponent = getInstance("wires.test.validation.validateConstraints1"); var constraints = testValidationComponent._getConstraints(); expect( constraints ).toBeTypeOf( "struct" ); expect( constraints ).toHaveLength( 1 ); expect( constraints ).toHaveKey( "firstname" ); - }); + } ); - it("should get constraints when set using constraints= ", function() { + it( "should get constraints when set using constraints=", function() { var testValidationComponent = getInstance("wires.test.validation.validateConstraints2"); var constraints = testValidationComponent._getConstraints(); expect( constraints ).toBeTypeOf( "struct" ); expect( constraints ).toHaveLength( 1 ); expect( constraints ).toHaveKey( "firstname" ); - }); + } ); - }); + } ); describe("Incoming Requests", function() {