1+ /*
2+ * Copyright (c) 2026, WSO2 LLC. (http://www.wso2.org) All Rights Reserved.
3+ *
4+ * WSO2 LLC. licenses this file to you under the Apache License,
5+ * Version 2.0 (the "License"); you may not use this file except
6+ * in compliance with the License.
7+ * You may obtain a copy of the License at
8+ *
9+ * http://www.apache.org/licenses/LICENSE-2.0
10+ *
11+ * Unless required by applicable law or agreed to in writing,
12+ * software distributed under the License is distributed on an
13+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+ * KIND, either express or implied. See the License for the
15+ * specific language governing permissions and limitations
16+ * under the License.
17+ */
18+
19+ import validateConstraint , { VALIDATOR_TYPES , getConstraintHint } from 'AppComponents/Shared/AppsAndKeys/constraintValidator' ;
20+
21+ const mockIntl = {
22+ formatMessage : ( msg , values ) => {
23+ let { defaultMessage } = msg ;
24+ if ( values ) {
25+ Object . keys ( values ) . forEach ( ( key ) => {
26+ defaultMessage = defaultMessage . replace ( `{${ key } }` , values [ key ] ) ;
27+ } ) ;
28+ }
29+ return defaultMessage ;
30+ } ,
31+ } ;
32+ const mockMessages = {
33+ rangeMin : { defaultMessage : 'Value must be at least {min}' } ,
34+ rangeMax : { defaultMessage : 'Value must be at most {max}' } ,
35+ rangeInvalid : { defaultMessage : 'Value must be a number between {min} and {max}' } ,
36+ regexInvalid : { defaultMessage : 'Value must match the required pattern: {pattern}' } ,
37+ } ;
38+
39+ describe ( 'constraintValidator' , ( ) => {
40+ describe ( 'validateConstraint' , ( ) => {
41+ describe ( 'MIN validation' , ( ) => {
42+ const constraint = {
43+ type : VALIDATOR_TYPES . MIN ,
44+ value : { min : 10 } ,
45+ } ;
46+
47+ it ( 'should return valid for value greater than min' , ( ) => {
48+ const result = validateConstraint ( '15' , constraint , mockIntl , mockMessages ) ;
49+ expect ( result . valid ) . toBe ( true ) ;
50+ } ) ;
51+
52+ it ( 'should return valid for value equal to min' , ( ) => {
53+ const result = validateConstraint ( '10' , constraint , mockIntl , mockMessages ) ;
54+ expect ( result . valid ) . toBe ( true ) ;
55+ } ) ;
56+
57+ it ( 'should return invalid for value less than min' , ( ) => {
58+ const result = validateConstraint ( '5' , constraint , mockIntl , mockMessages ) ;
59+ expect ( result . valid ) . toBe ( false ) ;
60+ expect ( result . message ) . toBe ( 'Value must be at least 10' ) ;
61+ } ) ;
62+
63+ it ( 'should return invalid for non-numeric value' , ( ) => {
64+ const result = validateConstraint ( 'abc' , constraint , mockIntl , mockMessages ) ;
65+ expect ( result . valid ) . toBe ( false ) ;
66+ } ) ;
67+
68+ it ( 'should return invalid for empty value' , ( ) => {
69+ const result = validateConstraint ( '' , constraint , mockIntl , mockMessages ) ;
70+ expect ( result . valid ) . toBe ( false ) ;
71+ } ) ;
72+
73+ it ( 'should handle negative numbers correctly' , ( ) => {
74+ const negConstraint = { type : VALIDATOR_TYPES . MIN , value : { min : - 5 } } ;
75+ expect ( validateConstraint ( '-3' , negConstraint , mockIntl , mockMessages ) . valid ) . toBe ( true ) ;
76+ expect ( validateConstraint ( '-10' , negConstraint , mockIntl , mockMessages ) . valid ) . toBe ( false ) ;
77+ } ) ;
78+
79+ it ( 'should handle decimal numbers correctly' , ( ) => {
80+ const decConstraint = { type : VALIDATOR_TYPES . MIN , value : { min : 5.5 } } ;
81+ expect ( validateConstraint ( '5.6' , decConstraint , mockIntl , mockMessages ) . valid ) . toBe ( true ) ;
82+ expect ( validateConstraint ( '5.4' , decConstraint , mockIntl , mockMessages ) . valid ) . toBe ( false ) ;
83+ } ) ;
84+ } ) ;
85+
86+ describe ( 'MAX validation' , ( ) => {
87+ const constraint = {
88+ type : VALIDATOR_TYPES . MAX ,
89+ value : { max : 100 } ,
90+ } ;
91+
92+ it ( 'should return valid for value less than max' , ( ) => {
93+ const result = validateConstraint ( '50' , constraint , mockIntl , mockMessages ) ;
94+ expect ( result . valid ) . toBe ( true ) ;
95+ } ) ;
96+
97+ it ( 'should return valid for value equal to max' , ( ) => {
98+ const result = validateConstraint ( '100' , constraint , mockIntl , mockMessages ) ;
99+ expect ( result . valid ) . toBe ( true ) ;
100+ } ) ;
101+
102+ it ( 'should return invalid for value greater than max' , ( ) => {
103+ const result = validateConstraint ( '150' , constraint , mockIntl , mockMessages ) ;
104+ expect ( result . valid ) . toBe ( false ) ;
105+ expect ( result . message ) . toBe ( 'Value must be at most 100' ) ;
106+ } ) ;
107+
108+ it ( 'should handle zero correctly' , ( ) => {
109+ const zeroConstraint = { type : VALIDATOR_TYPES . MAX , value : { max : 0 } } ;
110+ expect ( validateConstraint ( '-1' , zeroConstraint , mockIntl , mockMessages ) . valid ) . toBe ( true ) ;
111+ expect ( validateConstraint ( '0' , zeroConstraint , mockIntl , mockMessages ) . valid ) . toBe ( true ) ;
112+ expect ( validateConstraint ( '1' , zeroConstraint , mockIntl , mockMessages ) . valid ) . toBe ( false ) ;
113+ } ) ;
114+ } ) ;
115+
116+ describe ( 'RANGE validation' , ( ) => {
117+ const constraint = {
118+ type : VALIDATOR_TYPES . RANGE ,
119+ value : { min : 10 , max : 20 } ,
120+ } ;
121+
122+ it ( 'should return valid for value within range' , ( ) => {
123+ const result = validateConstraint ( '15' , constraint , mockIntl , mockMessages ) ;
124+ expect ( result . valid ) . toBe ( true ) ;
125+ } ) ;
126+
127+ it ( 'should return valid for value at min bound' , ( ) => {
128+ const result = validateConstraint ( '10' , constraint , mockIntl , mockMessages ) ;
129+ expect ( result . valid ) . toBe ( true ) ;
130+ } ) ;
131+
132+ it ( 'should return valid for value at max bound' , ( ) => {
133+ const result = validateConstraint ( '20' , constraint , mockIntl , mockMessages ) ;
134+ expect ( result . valid ) . toBe ( true ) ;
135+ } ) ;
136+
137+ it ( 'should return invalid for value below min' , ( ) => {
138+ const result = validateConstraint ( '5' , constraint , mockIntl , mockMessages ) ;
139+ expect ( result . valid ) . toBe ( false ) ;
140+ expect ( result . message ) . toBe ( 'Value must be a number between 10 and 20' ) ;
141+ } ) ;
142+
143+ it ( 'should return invalid for value above max' , ( ) => {
144+ const result = validateConstraint ( '25' , constraint , mockIntl , mockMessages ) ;
145+ expect ( result . valid ) . toBe ( false ) ;
146+ expect ( result . message ) . toBe ( 'Value must be a number between 10 and 20' ) ;
147+ } ) ;
148+
149+ it ( 'should return invalid for non-numeric value' , ( ) => {
150+ const result = validateConstraint ( 'abc' , constraint , mockIntl , mockMessages ) ;
151+ expect ( result . valid ) . toBe ( false ) ;
152+ } ) ;
153+ } ) ;
154+
155+ describe ( 'REGEX validation' , ( ) => {
156+ const constraint = {
157+ type : VALIDATOR_TYPES . REGEX ,
158+ value : { pattern : '^[0-9]+$' } ,
159+ } ;
160+
161+ it ( 'should return valid for matching value' , ( ) => {
162+ const result = validateConstraint ( '123' , constraint , mockIntl , mockMessages ) ;
163+ expect ( result . valid ) . toBe ( true ) ;
164+ } ) ;
165+
166+ it ( 'should return invalid for non-matching value' , ( ) => {
167+ const result = validateConstraint ( 'abc' , constraint , mockIntl , mockMessages ) ;
168+ expect ( result . valid ) . toBe ( false ) ;
169+ expect ( result . message ) . toBe ( 'Value must match the required pattern: ^[0-9]+$' ) ;
170+ } ) ;
171+
172+ it ( 'should return valid if regex pattern is invalid (to prevent app crash)' , ( ) => {
173+ const badConstraint = { type : VALIDATOR_TYPES . REGEX , value : { pattern : '[' } } ;
174+ const result = validateConstraint ( 'any' , badConstraint , mockIntl , mockMessages ) ;
175+ expect ( result . valid ) . toBe ( true ) ;
176+ } ) ;
177+ } ) ;
178+
179+ describe ( 'Edge Cases' , ( ) => {
180+ it ( 'should return valid if no constraint is provided' , ( ) => {
181+ const result = validateConstraint ( 'val' , null , mockIntl , mockMessages ) ;
182+ expect ( result . valid ) . toBe ( true ) ;
183+ } ) ;
184+
185+ it ( 'should return valid if constraint type is unknown' , ( ) => {
186+ const result = validateConstraint ( 'val' , { type : 'UNKNOWN' } , mockIntl , mockMessages ) ;
187+ expect ( result . valid ) . toBe ( true ) ;
188+ } ) ;
189+ } ) ;
190+ } ) ;
191+
192+ describe ( 'getConstraintHint' , ( ) => {
193+ it ( 'should return empty string for missing arguments' , ( ) => {
194+ expect ( getConstraintHint ( null , mockIntl , mockMessages ) ) . toBe ( '' ) ;
195+ expect ( getConstraintHint ( { } , mockIntl , mockMessages ) ) . toBe ( '' ) ;
196+ } ) ;
197+
198+ it ( 'should return correct hint for MIN' , ( ) => {
199+ const constraint = { type : VALIDATOR_TYPES . MIN , value : { min : 5 } } ;
200+ expect ( getConstraintHint ( constraint , mockIntl , mockMessages ) ) . toBe ( 'Value must be at least 5' ) ;
201+ } ) ;
202+
203+ it ( 'should return correct hint for MAX' , ( ) => {
204+ const constraint = { type : VALIDATOR_TYPES . MAX , value : { max : 50 } } ;
205+ expect ( getConstraintHint ( constraint , mockIntl , mockMessages ) ) . toBe ( 'Value must be at most 50' ) ;
206+ } ) ;
207+
208+ it ( 'should return correct hint for RANGE' , ( ) => {
209+ const constraint = { type : VALIDATOR_TYPES . RANGE , value : { min : 5 , max : 10 } } ;
210+ expect ( getConstraintHint ( constraint , mockIntl , mockMessages ) ) . toBe ( 'Value must be a number between 5 and 10' ) ;
211+ } ) ;
212+
213+ it ( 'should return correct hint for REGEX' , ( ) => {
214+ const constraint = { type : VALIDATOR_TYPES . REGEX , value : { pattern : '.*' } } ;
215+ expect ( getConstraintHint ( constraint , mockIntl , mockMessages ) ) . toBe ( 'Value must match the required pattern: .*' ) ;
216+ } ) ;
217+
218+ it ( 'should return empty string for unknown type' , ( ) => {
219+ const constraint = { type : 'UNKNOWN' , value : { some : 'val' } } ;
220+ expect ( getConstraintHint ( constraint , mockIntl , mockMessages ) ) . toBe ( '' ) ;
221+ } ) ;
222+ } ) ;
223+ } ) ;
0 commit comments