@@ -176,14 +176,20 @@ describe("react-to-web-component 1", () => {
176176 } )
177177
178178 it ( "options.props can specify and will convert the String attribute value into Number, Boolean, Array, and/or Object" , async ( ) => {
179- expect . assertions ( 12 )
179+ expect . assertions ( 18 )
180180
181181 type CastinProps = {
182182 stringProp : string
183183 numProp : number
184184 floatProp : number
185- trueProp : boolean
186- falseProp : boolean
185+ truePropWithValueTrue : boolean ,
186+ truePropWithValueYes : boolean ,
187+ truePropWithValueOne : boolean ,
188+ truePropWithValueFive : boolean ,
189+ truePropWithValueNine : boolean ,
190+ falsePropWithValueFalse : boolean ,
191+ falsePropWithValueNo : boolean ,
192+ falsePropWithValueZero : boolean ,
187193 arrayProp : any [ ]
188194 objProp : object
189195 }
@@ -194,17 +200,29 @@ describe("react-to-web-component 1", () => {
194200 stringProp,
195201 numProp,
196202 floatProp,
197- trueProp,
198- falseProp,
203+ truePropWithValueTrue,
204+ truePropWithValueYes,
205+ truePropWithValueOne,
206+ truePropWithValueFive,
207+ truePropWithValueNine,
208+ falsePropWithValueFalse,
209+ falsePropWithValueNo,
210+ falsePropWithValueZero,
199211 arrayProp,
200212 objProp,
201213 } : CastinProps ) {
202214 global . castedValues = {
203215 stringProp,
204216 numProp,
205217 floatProp,
206- trueProp,
207- falseProp,
218+ truePropWithValueTrue,
219+ truePropWithValueYes,
220+ truePropWithValueOne,
221+ truePropWithValueFive,
222+ truePropWithValueNine,
223+ falsePropWithValueFalse,
224+ falsePropWithValueNo,
225+ falsePropWithValueZero,
208226 arrayProp,
209227 objProp,
210228 }
@@ -217,8 +235,14 @@ describe("react-to-web-component 1", () => {
217235 stringProp : "string" ,
218236 numProp : "number" ,
219237 floatProp : "number" ,
220- trueProp : "boolean" ,
221- falseProp : "boolean" ,
238+ truePropWithValueTrue : "boolean" ,
239+ truePropWithValueYes : "boolean" ,
240+ truePropWithValueOne : "boolean" ,
241+ truePropWithValueFive : "boolean" ,
242+ truePropWithValueNine : "boolean" ,
243+ falsePropWithValueFalse : "boolean" ,
244+ falsePropWithValueNo : "boolean" ,
245+ falsePropWithValueZero : "boolean" ,
222246 arrayProp : "json" ,
223247 objProp : "json" ,
224248 } ,
@@ -238,8 +262,14 @@ describe("react-to-web-component 1", () => {
238262 string-prop="iloveyou"
239263 num-prop="360"
240264 float-prop="0.5"
241- true-prop="true"
242- false-prop="false"
265+ true-prop-with-value-true="true"
266+ true-prop-with-value-yes="yes"
267+ true-prop-with-value-one="1"
268+ true-prop-with-value-five="5"
269+ true-prop-with-value-nine="9"
270+ false-prop-with-value-false="false"
271+ false-prop-with-value-no="no"
272+ false-prop-with-value-zero="0"
243273 array-prop='[true, 100.25, "👽", { "aliens": "welcome" }]'
244274 obj-prop='{ "very": "object", "such": "wow!" }'
245275 ></attr-type-casting>
@@ -250,16 +280,28 @@ describe("react-to-web-component 1", () => {
250280 stringProp,
251281 numProp,
252282 floatProp,
253- trueProp,
254- falseProp,
283+ truePropWithValueTrue,
284+ truePropWithValueYes,
285+ truePropWithValueOne,
286+ truePropWithValueFive,
287+ truePropWithValueNine,
288+ falsePropWithValueFalse,
289+ falsePropWithValueNo,
290+ falsePropWithValueZero,
255291 arrayProp,
256292 objProp,
257293 } = global . castedValues
258294 expect ( stringProp ) . toEqual ( "iloveyou" )
259295 expect ( numProp ) . toEqual ( 360 )
260296 expect ( floatProp ) . toEqual ( 0.5 )
261- expect ( trueProp ) . toEqual ( true )
262- expect ( falseProp ) . toEqual ( false )
297+ expect ( truePropWithValueTrue ) . toEqual ( true )
298+ expect ( truePropWithValueYes ) . toEqual ( true )
299+ expect ( truePropWithValueOne ) . toEqual ( true )
300+ expect ( truePropWithValueFive ) . toEqual ( true )
301+ expect ( truePropWithValueNine ) . toEqual ( true )
302+ expect ( falsePropWithValueFalse ) . toEqual ( false )
303+ expect ( falsePropWithValueNo ) . toEqual ( false )
304+ expect ( falsePropWithValueZero ) . toEqual ( false )
263305 expect ( arrayProp . length ) . toEqual ( 4 )
264306 expect ( arrayProp [ 0 ] ) . toEqual ( true )
265307 expect ( arrayProp [ 1 ] ) . toEqual ( 100.25 )
@@ -269,6 +311,102 @@ describe("react-to-web-component 1", () => {
269311 expect ( objProp . such ) . toEqual ( "wow!" )
270312 } )
271313
314+ it ( "options.props handles HTML Boolean" , async ( ) => {
315+ expect . assertions ( 11 )
316+
317+ type CastinProps = {
318+ truePropPresent : boolean ,
319+ truePropEmptyString : boolean ,
320+ truePropWithValueEqualToName : boolean ,
321+ falsePropAbsent : boolean ,
322+ }
323+
324+ const global = window as any
325+
326+ function OptionsPropsTypeCasting ( {
327+ truePropPresent,
328+ truePropEmptyString,
329+ truePropWithValueEqualToName,
330+ falsePropAbsent,
331+ } : CastinProps ) {
332+ global . castedValues = {
333+ truePropPresent,
334+ truePropEmptyString,
335+ truePropWithValueEqualToName,
336+ falsePropAbsent,
337+ }
338+
339+ return < > </ >
340+ }
341+
342+ const WebOptionsPropsTypeCasting = r2wc ( OptionsPropsTypeCasting , {
343+ props : {
344+ truePropPresent : "boolean" ,
345+ truePropEmptyString : "boolean" ,
346+ truePropWithValueEqualToName : "boolean" ,
347+ falsePropAbsent : "boolean" ,
348+ } ,
349+ } )
350+
351+ customElements . define ( "html-boolean-attr-type-casting" , WebOptionsPropsTypeCasting )
352+
353+ const body = document . body
354+
355+ console . error = function ( ...messages ) {
356+ // propTypes will throw if any of the types passed into the underlying react component are wrong or missing
357+ expect ( "propTypes should not have thrown" ) . toEqual ( messages . join ( "" ) )
358+ }
359+
360+ body . innerHTML = `
361+ <html-boolean-attr-type-casting
362+ true-prop-present
363+ true-prop-empty-string=""
364+ true-prop-with-value-equal-to-name="true-html-prop-with-value-equal-to-name"
365+ ></html-boolean-attr-type-casting>
366+ `
367+
368+ await flushPromises ( )
369+
370+ expect ( global . castedValues . truePropPresent ,
371+ 'Prop without value is cast to true on mount' ) . toEqual ( true )
372+ expect ( global . castedValues . truePropEmptyString ,
373+ 'Prop with value equal to empty string is cast to true on mount' ) . toEqual ( true )
374+ expect ( global . castedValues . truePropWithValueEqualToName ,
375+ 'Prop with value equal to attribute name is considered true on mount' ) . toEqual ( true )
376+ expect ( global . castedValues . falsePropAbsent ,
377+ 'Lack of prop is cast to false on mount' ) . toEqual ( false )
378+
379+ const element = body . querySelector ( 'html-boolean-attr-type-casting' ) !
380+ expect ( element ) . toBeVisible ( ) ;
381+
382+ element . removeAttribute ( 'true-prop-present' ) ;
383+ element . removeAttribute ( 'true-prop-empty-string' ) ;
384+ element . removeAttribute ( 'true-prop-with-value-equal-to-name' ) ;
385+ element . setAttribute ( 'false-prop-absent' , '' ) ;
386+
387+ await flushPromises ( ) ;
388+
389+ expect ( global . castedValues . truePropPresent ,
390+ 'Prop without value is cast to false when attribute is removed' ) . toEqual ( false )
391+ expect ( global . castedValues . truePropEmptyString ,
392+ 'Prop with value equal to empty string is cast to false when attribute is removed' ) . toEqual ( false )
393+ expect ( global . castedValues . truePropWithValueEqualToName ,
394+ 'Prop with value equal to attribute name is cast to false when attribute is removed' ) . toEqual ( false )
395+ expect ( global . castedValues . falsePropAbsent ,
396+ 'Prop which attribute was absent on mount is cast to true when it appears' ) . toEqual ( true )
397+
398+ // @ts -ignore
399+ element . falsePropAbsent = false ;
400+
401+ await flushPromises ( ) ;
402+
403+ expect ( element ,
404+ 'Attribute of custom element is removed when property of custom element was set to false from outside' ) . not . toHaveAttribute ( 'false-prop-absent' )
405+ expect ( global . castedValues . falsePropAbsent ,
406+ 'Prop of React component is set to false when property of custom element was set to false from outside' ) . toEqual ( false )
407+ } )
408+
409+
272410 it ( "Props typed as Function convert the string value of attribute into global fn calls bound to the webcomponent instance" , async ( ) => {
273411 expect . assertions ( 2 )
274412
0 commit comments