@@ -4,9 +4,22 @@ import {attr} from '../src/attr.js'
44
55describe ( 'Attr' , ( ) => {
66 @controller
7+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
78 class InitializeAttrTest extends HTMLElement {
89 @attr foo = 'hello'
910 bar = 1
11+
12+ getCount = 0
13+ setCount = 0
14+ #baz = 'world'
15+ get baz ( ) {
16+ this . getCount += 1
17+ return this . #baz
18+ }
19+ @attr set baz ( value : string ) {
20+ this . setCount += 1
21+ this . #baz = value
22+ }
1023 }
1124
1225 let instance
@@ -18,108 +31,101 @@ describe('Attr', () => {
1831 document . createElement ( 'initialize-attr-test' )
1932 } )
2033
21- it ( 'marks attrs as observedAttributes' , ( ) => {
22- expect ( InitializeAttrTest . observedAttributes ) . to . eql ( [ 'data-foo' ] )
23- } )
24-
25- it ( 'creates a getter/setter pair for each given attr name' , ( ) => {
26- expect ( instance . foo ) . to . equal ( 'hello' )
27- expect ( instance ) . to . have . ownPropertyDescriptor ( 'foo' )
34+ it ( 'does not alter field values from their initial value' , ( ) => {
35+ expect ( instance ) . to . have . property ( 'foo' , 'hello' )
36+ expect ( instance ) . to . have . property ( 'bar' , 1 )
37+ expect ( instance ) . to . have . property ( 'baz' , 'world' )
2838 } )
2939
30- it ( 'sets the attribute to a previously defined value on the key ' , ( ) => {
31- expect ( instance . foo ) . to . equal ( 'hello' )
32- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo ' )
33- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( 'hello ')
40+ it ( 'reflects the initial value as an attribute, if not present ' , ( ) => {
41+ expect ( instance ) . to . have . attribute ( 'data-foo' , 'hello' )
42+ expect ( instance ) . to . not . have . attribute ( 'data-bar ' )
43+ expect ( instance ) . to . have . attribute ( 'data-baz' , 'world ')
3444 } )
3545
36- it ( 'reflects the `data-*` attribute name of the given key' , ( ) => {
37- expect ( instance . foo ) . to . equal ( 'hello' )
38- instance . foo = 'bar'
39- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo' )
40- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( 'bar' )
41- instance . setAttribute ( 'data-foo' , 'baz' )
42- expect ( instance . foo ) . to . equal ( 'baz' )
46+ it ( 'prioritises the value in the attribute over the property' , async ( ) => {
47+ instance = await fixture ( html `< initialize-attr-test data-foo ="goodbye " data-baz ="universe " /> ` )
48+ expect ( instance ) . to . have . property ( 'foo' , 'goodbye' )
49+ expect ( instance ) . to . have . attribute ( 'data-foo' , 'goodbye' )
50+ expect ( instance ) . to . have . property ( 'baz' , 'universe' )
51+ expect ( instance ) . to . have . attribute ( 'data-baz' , 'universe' )
4352 } )
4453
45- it ( 'sets the attribute to a previously defined value on the key' , ( ) => {
46- instance . foo = 'hello'
47- expect ( instance . foo ) . to . equal ( 'hello' )
48- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo' )
49- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( 'hello' )
54+ it ( 'changes the property when the attribute changes' , async ( ) => {
55+ instance . setAttribute ( 'data-foo' , 'goodbye' )
56+ await Promise . resolve ( )
57+ expect ( instance ) . to . have . property ( 'foo' , 'goodbye' )
58+ instance . setAttribute ( 'data-baz' , 'universe' )
59+ await Promise . resolve ( )
60+ expect ( instance ) . to . have . property ( 'baz' , 'universe' )
5061 } )
5162
52- it ( 'prioritises the value in the attribute over the property' , async ( ) => {
53- instance = await fixture ( html ` < initialize-attr-test data-foo =" goodbye " /> ` )
54- expect ( instance . foo ) . to . equal ( 'goodbye' )
55- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo' )
56- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( 'goodbye ')
63+ it ( 'changes the attribute when the property changes' , ( ) => {
64+ instance . foo = ' goodbye'
65+ expect ( instance ) . to . have . attribute ( 'data-foo' , 'goodbye' )
66+ instance . baz = 'universe'
67+ expect ( instance ) . to . have . attribute ( 'data-baz' , 'universe ')
5768 } )
5869
5970 describe ( 'types' , ( ) => {
60- it ( 'infers number types from property and casts as number always' , async ( ) => {
61- @controller
62- class NumberAttrTest extends HTMLElement {
63- @attr foo = 1
64- }
65- expect ( NumberAttrTest ) . to . have . property ( 'observedAttributes' ) . include ( 'data-foo' )
66- instance = await fixture ( html `< number-attr-test /> ` )
67- expect ( instance . foo ) . to . equal ( 1 )
68- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo' )
69- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( '1' )
70- instance . setAttribute ( 'data-foo' , '7' )
71- expect ( instance . foo ) . to . equal ( 7 )
72- instance . setAttribute ( 'data-foo' , '-3.14' )
73- expect ( instance . foo ) . to . equal ( - 3.14 )
74- instance . setAttribute ( 'data-foo' , 'Not a Number' )
75- expect ( Number . isNaN ( instance . foo ) ) . to . equal ( true )
76- instance . removeAttribute ( 'data-foo' )
77- expect ( instance . foo ) . to . equal ( 0 )
78- instance . foo = 3.14
79- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( '3.14' )
80- } )
81-
8271 it ( 'infers boolean types from property and uses has/toggleAttribute' , async ( ) => {
8372 @controller
73+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
8474 class BooleanAttrTest extends HTMLElement {
8575 @attr foo = false
8676 }
87- expect ( BooleanAttrTest ) . to . have . property ( 'observedAttributes' ) . include ( 'data-foo' )
77+
8878 instance = await fixture ( html `< boolean-attr-test /> ` )
89- expect ( instance . foo ) . to . equal ( false )
90- expect ( instance . getAttributeNames ( ) ) . to . not . include ( 'data- foo')
91- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( null )
79+
80+ expect ( instance ) . to . have . property ( ' foo', false )
81+ expect ( instance ) . to . not . have . attribute ( 'data-foo' )
9282 instance . setAttribute ( 'data-foo' , '7' )
93- expect ( instance . foo ) . to . equal ( true )
83+ await Promise . resolve ( )
84+ expect ( instance ) . to . have . property ( 'foo' , true )
9485 instance . setAttribute ( 'data-foo' , 'hello' )
95- expect ( instance . foo ) . to . equal ( true )
86+ await Promise . resolve ( )
87+ expect ( instance ) . to . have . property ( 'foo' , true )
9688 instance . setAttribute ( 'data-foo' , 'false' )
97- expect ( instance . foo ) . to . equal ( true )
89+ await Promise . resolve ( )
90+ expect ( instance ) . to . have . property ( 'foo' , true )
9891 instance . removeAttribute ( 'data-foo' )
99- expect ( instance . foo ) . to . equal ( false )
100- instance . foo = '1'
101- expect ( instance . foo ) . to . equal ( true )
102- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo' )
103- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( '' )
92+ await Promise . resolve ( )
93+ expect ( instance ) . to . have . property ( 'foo' , false )
94+ instance . foo = true
95+ expect ( instance ) . to . have . attribute ( 'data-foo' , '' )
10496 instance . foo = false
105- expect ( instance . getAttributeNames ( ) ) . to . not . include ( 'data-foo' )
97+ expect ( instance ) . to . not . have . attribute ( 'data-foo' )
98+ instance . removeAttribute ( 'data-foo' )
99+ await Promise . resolve ( )
100+ expect ( instance ) . to . have . property ( 'foo' , false )
106101 } )
107102
108- it ( 'defaults to inferring string type for non-boolean non-number types ' , async ( ) => {
103+ it ( 'avoids infinite loops ' , async ( ) => {
109104 @controller
110- class RegExpAttrTest extends HTMLElement {
111- @attr foo = / ^ a r e g e x p $ /
105+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
106+ class LoopAttrTest extends HTMLElement {
107+ count = 0
108+ @attr
109+ get foo ( ) {
110+ return ++ this . count
111+ }
112+ set foo ( value ) {
113+ this . count += 1
114+ }
112115 }
113- expect ( RegExpAttrTest ) . to . have . property ( 'observedAttributes' ) . include ( 'data-foo' )
114- instance = await fixture ( html `< reg-exp-attr-test /> ` )
115- expect ( instance . foo ) . to . equal ( '/^a regexp$/' )
116- expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo' )
117- expect ( instance . getAttribute ( 'data-foo' ) ) . to . equal ( '/^a regexp$/' )
116+ instance = await fixture ( html `< loop-attr-test /> ` )
117+
118+ expect ( instance ) . to . have . property ( 'foo' )
119+ instance . foo = 1
120+ instance . setAttribute ( 'data-foo' , '2' )
121+ instance . foo = 3
122+ instance . setAttribute ( 'data-foo' , '4' )
118123 } )
119124 } )
120125
121126 describe ( 'naming' , ( ) => {
122127 @controller
128+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
123129 class NamingAttrTest extends HTMLElement {
124130 @attr fooBarBazBing = 'a'
125131 @attr URLBar = 'b'
@@ -131,21 +137,18 @@ describe('Attr', () => {
131137 } )
132138
133139 it ( 'converts camel cased property names to their HTML dasherized equivalents' , async ( ) => {
134- expect ( NamingAttrTest ) . to . have . property ( 'observedAttributes' ) . include ( 'data-foo-bar-baz-bing' )
135140 expect ( instance . fooBarBazBing ) . to . equal ( 'a' )
136141 instance . fooBarBazBing = 'bar'
137142 expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-foo-bar-baz-bing' )
138143 } )
139144
140145 it ( 'will intuitively dasherize acryonyms' , async ( ) => {
141- expect ( NamingAttrTest ) . to . have . property ( 'observedAttributes' ) . include ( 'data-url-bar' )
142146 expect ( instance . URLBar ) . to . equal ( 'b' )
143147 instance . URLBar = 'bar'
144148 expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-url-bar' )
145149 } )
146150
147151 it ( 'dasherizes cap suffixed names correctly' , async ( ) => {
148- expect ( NamingAttrTest ) . to . have . property ( 'observedAttributes' ) . include ( 'data-clip-x' )
149152 expect ( instance . ClipX ) . to . equal ( 'c' )
150153 instance . ClipX = 'bar'
151154 expect ( instance . getAttributeNames ( ) ) . to . include ( 'data-clip-x' )
0 commit comments