@3t-transform/threeteeui 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/cjs/app-globals-3a1e7e63.js +5 -0
  2. package/dist/cjs/css-shim-211819bc.js +6 -0
  3. package/dist/cjs/dom-9deb26c8.js +75 -0
  4. package/dist/cjs/index-11cfdabe.js +3297 -0
  5. package/dist/cjs/{index-b3010e55.js → index-451f61dd.js} +1 -3
  6. package/dist/cjs/loader.cjs.js +18 -2
  7. package/dist/cjs/shadow-css-bf3843d2.js +389 -0
  8. package/dist/cjs/tttx-button.cjs.entry.js +1 -1
  9. package/dist/cjs/tttx-form.cjs.entry.js +1 -1
  10. package/dist/cjs/tttx-icon.cjs.entry.js +1 -1
  11. package/dist/cjs/tttx-keyvalue-block.cjs.entry.js +1 -1
  12. package/dist/cjs/tttx-list.cjs.entry.js +34 -4
  13. package/dist/cjs/tttx-loading-spinner.cjs.entry.js +1 -1
  14. package/dist/cjs/tttx-standalone-input.cjs.entry.js +1 -1
  15. package/dist/cjs/tttx-toolbar.cjs.entry.js +20 -0
  16. package/dist/cjs/tttx.cjs.js +116 -4
  17. package/dist/collection/collection-manifest.json +2 -1
  18. package/dist/collection/components/atoms/tttx-button/test/tttx-button.e2e.js +9 -0
  19. package/dist/collection/components/atoms/tttx-button/test/tttx-button.spec.js +83 -0
  20. package/dist/collection/components/atoms/tttx-icon/test/tttx-icon.e2e.js +9 -0
  21. package/dist/collection/components/atoms/tttx-icon/test/tttx-icon.spec.js +16 -0
  22. package/dist/collection/components/atoms/tttx-keyvalue-block/test/tttx-keyvalue-block.spec.js +216 -0
  23. package/dist/collection/components/atoms/tttx-loading-spinner/Test/tttx-loading-spinner.spec.js +64 -0
  24. package/dist/collection/components/molecules/tttx-form/lib/setErrorState.spec.js +38 -0
  25. package/dist/collection/components/molecules/tttx-form/lib/validityCheck.spec.js +214 -0
  26. package/dist/collection/components/molecules/tttx-form/test/tttx-form.e2e.js +9 -0
  27. package/dist/collection/components/molecules/tttx-form/test/tttx-form.spec.js +232 -0
  28. package/dist/collection/components/molecules/tttx-list/test/ttttx-list.spec.e2e.js +26 -0
  29. package/dist/collection/components/molecules/tttx-list/test/tttx-list.spec.js +183 -0
  30. package/dist/collection/components/molecules/tttx-standalone-input/test/tttx-standalone-input.e2e.js +9 -0
  31. package/dist/collection/components/molecules/tttx-standalone-input/test/tttx-standalone-input.spec.js +219 -0
  32. package/dist/collection/components/molecules/tttx-toolbar/test/tttx-toolbar.test.js +0 -0
  33. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.css +30 -0
  34. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.js +44 -0
  35. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.stories.js +20 -0
  36. package/dist/collection/shared/test/domsanitiser.options.spec.js +23 -0
  37. package/dist/components/index.d.ts +1 -0
  38. package/dist/components/index.js +5 -0
  39. package/dist/components/tttx-list.js +33 -3
  40. package/dist/components/tttx-toolbar.d.ts +11 -0
  41. package/dist/components/tttx-toolbar.js +36 -0
  42. package/dist/esm/app-globals-0f993ce5.js +3 -0
  43. package/dist/esm/css-shim-9d54a2f2.js +4 -0
  44. package/dist/esm/dom-6be6f662.js +73 -0
  45. package/dist/esm/{index-31631990.js → index-0350f122.js} +1 -3
  46. package/dist/esm/index-dbe25028.js +3262 -0
  47. package/dist/esm/loader.js +18 -2
  48. package/dist/esm/shadow-css-ed4599f8.js +387 -0
  49. package/dist/esm/tttx-button.entry.js +1 -1
  50. package/dist/esm/tttx-form.entry.js +1 -1
  51. package/dist/esm/tttx-icon.entry.js +1 -1
  52. package/dist/esm/tttx-keyvalue-block.entry.js +1 -1
  53. package/dist/esm/tttx-list.entry.js +34 -4
  54. package/dist/esm/tttx-loading-spinner.entry.js +1 -1
  55. package/dist/esm/tttx-standalone-input.entry.js +1 -1
  56. package/dist/esm/tttx-toolbar.entry.js +16 -0
  57. package/dist/esm/tttx.js +116 -4
  58. package/dist/tttx/app-globals-0f993ce5.js +3 -0
  59. package/dist/tttx/css-shim-9d54a2f2.js +4 -0
  60. package/dist/tttx/dom-6be6f662.js +73 -0
  61. package/dist/tttx/index-dbe25028.js +3262 -0
  62. package/dist/tttx/index.esm.js +1 -0
  63. package/dist/tttx/p-0a85dda4.entry.js +1 -0
  64. package/dist/tttx/{p-1f3d39fc.entry.js → p-1b015a9d.entry.js} +1 -1
  65. package/dist/tttx/{p-2e7f486e.entry.js → p-4f3958fa.entry.js} +1 -1
  66. package/dist/tttx/{p-14270585.entry.js → p-5cae1beb.entry.js} +1 -1
  67. package/dist/tttx/{p-0c6a665d.js → p-62869344.js} +1 -1
  68. package/dist/tttx/{p-979ebe65.entry.js → p-92465671.entry.js} +1 -1
  69. package/dist/tttx/{p-84d90779.entry.js → p-a0179cb1.entry.js} +1 -1
  70. package/dist/tttx/{p-263d093c.entry.js → p-cc6644c9.entry.js} +1 -1
  71. package/dist/tttx/{p-39f991c3.entry.js → p-cd1565e0.entry.js} +1 -1
  72. package/dist/tttx/shadow-css-ed4599f8.js +387 -0
  73. package/dist/tttx/tttx-button.entry.js +30 -0
  74. package/dist/tttx/tttx-form.entry.js +373 -0
  75. package/dist/tttx/tttx-icon.entry.js +17 -0
  76. package/dist/tttx/tttx-keyvalue-block.entry.js +63 -0
  77. package/dist/tttx/tttx-list.entry.js +1730 -0
  78. package/dist/tttx/tttx-loading-spinner.entry.js +22 -0
  79. package/dist/tttx/tttx-standalone-input.entry.js +66 -0
  80. package/dist/tttx/tttx-toolbar.entry.js +16 -0
  81. package/dist/tttx/tttx.esm.js +129 -1
  82. package/dist/types/components/atoms/tttx-button/test/tttx-button.e2e.d.ts +1 -0
  83. package/dist/types/components/atoms/tttx-button/test/tttx-button.spec.d.ts +1 -0
  84. package/dist/types/components/atoms/tttx-icon/test/tttx-icon.e2e.d.ts +1 -0
  85. package/dist/types/components/atoms/tttx-icon/test/tttx-icon.spec.d.ts +1 -0
  86. package/dist/types/components/atoms/tttx-keyvalue-block/test/tttx-keyvalue-block.spec.d.ts +1 -0
  87. package/dist/types/components/atoms/tttx-loading-spinner/Test/tttx-loading-spinner.spec.d.ts +1 -0
  88. package/dist/types/components/molecules/tttx-form/lib/setErrorState.spec.d.ts +1 -0
  89. package/dist/types/components/molecules/tttx-form/lib/validityCheck.spec.d.ts +1 -0
  90. package/dist/types/components/molecules/tttx-form/test/tttx-form.e2e.d.ts +1 -0
  91. package/dist/types/components/molecules/tttx-form/test/tttx-form.spec.d.ts +1 -0
  92. package/dist/types/components/molecules/tttx-list/test/ttttx-list.spec.e2e.d.ts +1 -0
  93. package/dist/types/components/molecules/tttx-list/test/tttx-list.spec.d.ts +1 -0
  94. package/dist/types/components/molecules/tttx-standalone-input/test/tttx-standalone-input.e2e.d.ts +1 -0
  95. package/dist/types/components/molecules/tttx-standalone-input/test/tttx-standalone-input.spec.d.ts +1 -0
  96. package/dist/types/components/molecules/tttx-toolbar/test/tttx-toolbar.test.d.ts +0 -0
  97. package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.d.ts +4 -0
  98. package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.stories.d.ts +13 -0
  99. package/dist/types/components.d.ts +15 -0
  100. package/dist/types/shared/test/domsanitiser.options.spec.d.ts +1 -0
  101. package/package.json +1 -1
@@ -0,0 +1,214 @@
1
+ import validityCheck from './validityCheck';
2
+ // badInput
3
+ // customError
4
+ // patternMismatch
5
+ // rangeOverflow
6
+ // rangeUnderflow
7
+ // stepMismatch
8
+ // tooLong
9
+ // tooShort
10
+ // typeMismatch
11
+ // valid
12
+ // valueMissing
13
+ describe('validityCheck', () => {
14
+ it('should return a valid response when there are no validation issues', async () => {
15
+ const preventDefault = jest.fn();
16
+ const event = {
17
+ target: {
18
+ value: 'test',
19
+ validity: {
20
+ valid: true
21
+ },
22
+ dataset: {}
23
+ },
24
+ preventDefault
25
+ };
26
+ const result = validityCheck(event);
27
+ expect(preventDefault).toHaveBeenCalledTimes(1);
28
+ expect(result).toStrictEqual({
29
+ "errorMessage": "",
30
+ "hasError": false,
31
+ "target": event.target
32
+ });
33
+ });
34
+ it('should return the required property when there is a value missing', async () => {
35
+ const preventDefault = jest.fn();
36
+ const event = {
37
+ target: {
38
+ dataset: {
39
+ required: 'This is required'
40
+ },
41
+ value: 'test',
42
+ validity: {
43
+ valid: false,
44
+ valueMissing: true
45
+ }
46
+ },
47
+ preventDefault
48
+ };
49
+ const result = validityCheck(event);
50
+ expect(preventDefault).toHaveBeenCalledTimes(1);
51
+ expect(result).toStrictEqual({
52
+ "errorMessage": "This is required",
53
+ "hasError": true,
54
+ "target": event.target
55
+ });
56
+ });
57
+ it('should return a default error message property when there is a value missing', async () => {
58
+ const preventDefault = jest.fn();
59
+ const event = {
60
+ target: {
61
+ dataset: {},
62
+ value: 'test',
63
+ validity: {
64
+ valid: false,
65
+ valueMissing: true
66
+ }
67
+ },
68
+ preventDefault
69
+ };
70
+ const result = validityCheck(event);
71
+ expect(preventDefault).toHaveBeenCalledTimes(1);
72
+ expect(result).toStrictEqual({
73
+ "errorMessage": 'This field is required',
74
+ "hasError": true,
75
+ "target": event.target
76
+ });
77
+ });
78
+ it('should return the pattern property when there is a patternMismatch', async () => {
79
+ const preventDefault = jest.fn();
80
+ const event = {
81
+ target: {
82
+ dataset: {
83
+ pattern: 'Incorrect format CUSTOM'
84
+ },
85
+ value: 'test',
86
+ validity: {
87
+ valid: false,
88
+ patternMismatch: true
89
+ }
90
+ },
91
+ preventDefault
92
+ };
93
+ const result = validityCheck(event);
94
+ expect(preventDefault).toHaveBeenCalledTimes(1);
95
+ expect(result).toStrictEqual({
96
+ "errorMessage": "Incorrect format CUSTOM",
97
+ "hasError": true,
98
+ "target": event.target
99
+ });
100
+ });
101
+ it('should return the a default error message when there is a patternMismatch', async () => {
102
+ const preventDefault = jest.fn();
103
+ const event = {
104
+ target: {
105
+ dataset: {},
106
+ value: 'test',
107
+ validity: {
108
+ valid: false,
109
+ patternMismatch: true
110
+ }
111
+ },
112
+ preventDefault
113
+ };
114
+ const result = validityCheck(event);
115
+ expect(preventDefault).toHaveBeenCalledTimes(1);
116
+ expect(result).toStrictEqual({
117
+ "errorMessage": 'Incorrect format',
118
+ "hasError": true,
119
+ "target": event.target
120
+ });
121
+ });
122
+ it('should return the badinput error message property when there is a badInput', async () => {
123
+ const preventDefault = jest.fn();
124
+ const event = {
125
+ target: {
126
+ dataset: {
127
+ badinput: 'There is a bad input'
128
+ },
129
+ value: 'test',
130
+ validity: {
131
+ valid: false,
132
+ badInput: true
133
+ }
134
+ },
135
+ preventDefault
136
+ };
137
+ const result = validityCheck(event);
138
+ expect(preventDefault).toHaveBeenCalledTimes(1);
139
+ expect(result).toStrictEqual({
140
+ "errorMessage": "There is a bad input",
141
+ "hasError": true,
142
+ "target": event.target
143
+ });
144
+ });
145
+ it('should return a default error message property when there is a badInput', async () => {
146
+ const preventDefault = jest.fn();
147
+ const event = {
148
+ target: {
149
+ value: 'test',
150
+ validity: {
151
+ valid: false,
152
+ badInput: true
153
+ },
154
+ dataset: {}
155
+ },
156
+ preventDefault
157
+ };
158
+ const result = validityCheck(event);
159
+ expect(preventDefault).toHaveBeenCalledTimes(1);
160
+ expect(result).toStrictEqual({
161
+ "errorMessage": 'Wrong input type',
162
+ "hasError": true,
163
+ "target": event.target
164
+ });
165
+ });
166
+ it('should return a message for an item out of range (underflow) with custom message', async () => {
167
+ const preventDefault = jest.fn();
168
+ const event = {
169
+ target: {
170
+ value: '0',
171
+ validity: {
172
+ valid: false,
173
+ rangeOverflow: true
174
+ },
175
+ dataset: {
176
+ range: 'Value is out of range'
177
+ }
178
+ },
179
+ preventDefault
180
+ };
181
+ const result = validityCheck(event);
182
+ expect(preventDefault).toHaveBeenCalledTimes(1);
183
+ expect(result).toStrictEqual({
184
+ "errorMessage": "Value is out of range",
185
+ "hasError": true,
186
+ "target": event.target
187
+ });
188
+ });
189
+ it('should return a message for an item out of range (underflow)', async () => {
190
+ const preventDefault = jest.fn();
191
+ const event = {
192
+ target: {
193
+ value: '0',
194
+ validity: {
195
+ valid: false,
196
+ rangeOverflow: true
197
+ },
198
+ dataset: {}
199
+ },
200
+ preventDefault
201
+ };
202
+ const result = validityCheck(event);
203
+ expect(preventDefault).toHaveBeenCalledTimes(1);
204
+ expect(result).toStrictEqual({
205
+ "errorMessage": "Invalid value",
206
+ "hasError": true,
207
+ "target": event.target
208
+ });
209
+ });
210
+ // it('target.validity.rangeOverflow', async () => {
211
+ // });
212
+ // it('target.validity.rangeUnderflow', async () => {
213
+ // });
214
+ });
@@ -0,0 +1,9 @@
1
+ import { newE2EPage } from '@stencil/core/testing';
2
+ describe('tttx-form', () => {
3
+ it('renders', async () => {
4
+ const page = await newE2EPage();
5
+ await page.setContent('<tttx-form></tttx-form>');
6
+ const element = await page.find('tttx-form');
7
+ expect(element).toHaveClass('hydrated');
8
+ });
9
+ });
@@ -0,0 +1,232 @@
1
+ import { h } from '@stencil/core';
2
+ import { newSpecPage } from '@stencil/core/testing';
3
+ import { TttxForm } from '../tttx-form';
4
+ describe('tttx-form', () => {
5
+ it('renders', async () => {
6
+ const page = await newSpecPage({
7
+ components: [TttxForm],
8
+ html: '<tttx-form></tttx-form>',
9
+ });
10
+ expect(page.root).toEqualHtml(`
11
+ <tttx-form>
12
+ <mock:shadow-root>
13
+ <form>
14
+ <fieldset></fieldset>
15
+ </form>
16
+ </mock:shadow-root>
17
+ </tttx-form>
18
+ `);
19
+ });
20
+ it('renders a single form item', async () => {
21
+ const singleFormItemSchema = {
22
+ properties: {
23
+ input: {
24
+ type: 'string',
25
+ format: 'string',
26
+ form: {
27
+ type: 'text',
28
+ label: 'Input Field',
29
+ validation: {
30
+ required: {
31
+ message: 'Please enter something'
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ };
38
+ const page = await newSpecPage({
39
+ components: [TttxForm],
40
+ html: `<tttx-form formschema='${JSON.stringify(singleFormItemSchema)}'></tttx-form>`,
41
+ });
42
+ expect(page.root).toEqualHtml(`
43
+ <tttx-form formschema='${JSON.stringify(singleFormItemSchema)}'>
44
+ <mock:shadow-root>
45
+ <form>
46
+ <fieldset>
47
+ <label class="inputBlock">
48
+ Input Field
49
+ <input autocomplete="off" data-required="Please enter something" name="input" placeholder="" required="" type="text" />
50
+ <div class="errorBubble"></div>
51
+ </label>
52
+ <input class="button primary-blue" type="submit" value="Save">
53
+ </fieldset>
54
+ </form>
55
+ </mock:shadow-root>
56
+ </tttx-form>
57
+ `);
58
+ });
59
+ it('renders without validation', async () => {
60
+ const singleFormItemSchema = {
61
+ properties: {
62
+ input: {
63
+ type: 'string',
64
+ format: 'string',
65
+ form: {
66
+ type: 'text',
67
+ label: 'Input Field'
68
+ }
69
+ }
70
+ }
71
+ };
72
+ const page = await newSpecPage({
73
+ components: [TttxForm],
74
+ html: `<tttx-form formschema='${JSON.stringify(singleFormItemSchema)}'></tttx-form>`,
75
+ });
76
+ expect(page.root).toEqualHtml(`
77
+ <tttx-form formschema='${JSON.stringify(singleFormItemSchema)}'>
78
+ <mock:shadow-root>
79
+ <form>
80
+ <fieldset>
81
+ <label class="inputBlock">
82
+ Input Field
83
+ <span class="optional">
84
+ (optional)
85
+ </span>
86
+ <input autocomplete="off" name="input" placeholder="" type="text" />
87
+ <div class="errorBubble"></div>
88
+ </label>
89
+ <input class="button primary-blue" type="submit" value="Save">
90
+ </fieldset>
91
+ </form>
92
+ </mock:shadow-root>
93
+ </tttx-form>
94
+ `);
95
+ });
96
+ it('renders a complex form', async () => {
97
+ const formSchema = {
98
+ properties: {
99
+ title: {
100
+ type: 'string',
101
+ format: 'string',
102
+ form: {
103
+ type: 'text',
104
+ placeholder: 'Mr, Mrs, Dr, Hon Rev',
105
+ label: 'Title',
106
+ },
107
+ },
108
+ forename: {
109
+ type: 'string',
110
+ format: 'string',
111
+ form: {
112
+ type: 'text',
113
+ placeholder: 'John',
114
+ label: 'Forename',
115
+ validation: {
116
+ required: {
117
+ message: 'Please enter your forename',
118
+ },
119
+ },
120
+ },
121
+ },
122
+ surname: {
123
+ type: 'string',
124
+ format: 'string',
125
+ form: {
126
+ type: 'text',
127
+ placeholder: 'Doe',
128
+ label: 'Surname',
129
+ validation: {
130
+ required: {
131
+ message: 'Please enter your surname',
132
+ },
133
+ },
134
+ },
135
+ },
136
+ postcode: {
137
+ type: 'string',
138
+ format: 'string',
139
+ form: {
140
+ type: 'text',
141
+ placeholder: 'AB10',
142
+ label: 'Start of postcode',
143
+ validation: {
144
+ required: {
145
+ message: 'Please enter the beginning of your postcode',
146
+ },
147
+ pattern: {
148
+ pattern: '^([A-Za-z][0-9])$|^([A-Za-z][0-9]{2})$|^([A-Za-z]{2}[0-9])$|^([A-Za-z]{2}[0-9]{2})$|^([A-Za-z][0-9][A-Za-z])$|^([A-Za-z]{2}[0-9][A-Za-z])$|^(GIR|BF|BX|XX)$',
149
+ message: 'Please enter the first half of your postcode. EG: ZZ99',
150
+ },
151
+ maxlength: 4,
152
+ },
153
+ },
154
+ },
155
+ age: {
156
+ type: 'number',
157
+ format: 'number',
158
+ form: {
159
+ type: 'number',
160
+ placeholder: '',
161
+ label: 'Age',
162
+ validation: {
163
+ required: {
164
+ message: 'Please enter your age',
165
+ },
166
+ badInput: {
167
+ message: 'Please enter a number',
168
+ },
169
+ },
170
+ },
171
+ },
172
+ dob: {
173
+ type: 'string',
174
+ format: 'date-time',
175
+ form: {
176
+ type: 'date',
177
+ placeholder: '',
178
+ label: 'Date of birth',
179
+ validation: {
180
+ required: {
181
+ message: 'Please enter your date of birth',
182
+ },
183
+ minmax: {
184
+ min: '1900-01-01',
185
+ max: '2100-12-31',
186
+ message: 'Please enter a date between 1900 and 2100',
187
+ },
188
+ },
189
+ },
190
+ },
191
+ },
192
+ };
193
+ const page = await newSpecPage({
194
+ components: [TttxForm],
195
+ template: () => (h("tttx-form", { formschema: formSchema })),
196
+ });
197
+ expect(page.root).toEqualHtml(`
198
+ <tttx-form>
199
+ <mock:shadow-root>
200
+ <form>
201
+ <fieldset>
202
+ <label class="inputBlock">Title<span class="optional">&nbsp;(optional)</span>
203
+ <input autocomplete="off" name="title" placeholder="Mr, Mrs, Dr, Hon Rev" type="text" />
204
+ <div class="errorBubble"></div>
205
+ </label>
206
+ <label class="inputBlock">Forename
207
+ <input autocomplete="off" data-required="Please enter your forename" name="forename" placeholder="John" required="" type="text"/>
208
+ <div class="errorBubble"></div>
209
+ </label>
210
+ <label class="inputBlock">Surname
211
+ <input autocomplete="off" data-required="Please enter your surname" name="surname" placeholder="Doe" required="" type="text">
212
+ <div class="errorBubble"></div>
213
+ </label>
214
+ <label class="inputBlock">Start of postcode
215
+ <input autocomplete="off" data-pattern="Please enter the first half of your postcode. EG: ZZ99" data-required="Please enter the beginning of your postcode" maxlength="4" name="postcode" pattern="^([A-Za-z][0-9])$|^([A-Za-z][0-9]{2})$|^([A-Za-z]{2}[0-9])$|^([A-Za-z]{2}[0-9]{2})$|^([A-Za-z][0-9][A-Za-z])$|^([A-Za-z]{2}[0-9][A-Za-z])$|^(GIR|BF|BX|XX)$" placeholder="AB10" required="" type="text">
216
+ <div class="errorBubble"></div>
217
+ </label>
218
+ <label class="inputBlock">Age
219
+ <input autocomplete="off" data-badinput="Please enter a number" data-required="Please enter your age" name="age" placeholder="" required="" type="number">
220
+ <div class="errorBubble"></div>
221
+ </label>
222
+ <label class="inputBlock">Date of birth
223
+ <input autocomplete="off" data-range="Please enter a date between 1900 and 2100" data-required="Please enter your date of birth" max="2100-12-31" min="1900-01-01" name="dob" placeholder="" required="" type="date">
224
+ <div class="errorBubble"></div>
225
+ </label>
226
+ <input type="submit" class="button primary-blue" value="Save"></fieldset>
227
+ </form>
228
+ </mock:shadow-root>
229
+ </tttx-form>
230
+ `);
231
+ });
232
+ });
@@ -0,0 +1,26 @@
1
+ import { newE2EPage } from '@stencil/core/testing';
2
+ describe('tttx-list', () => {
3
+ it('sanitises the html of the element property', async () => {
4
+ const page = await newE2EPage();
5
+ await page.setContent('<tttx-list></tttx-list>');
6
+ await page.$eval('tttx-list', (elm) => {
7
+ elm.data = [{ element: '<span><tttx-icon icon="egg" color="blue"></tttx-icon></span>Test<script>alert(4)</script>' }];
8
+ });
9
+ await page.waitForChanges();
10
+ const element = await page.find('tttx-list');
11
+ expect(element).toEqualHtml(`
12
+ <tttx-list class="hydrated">
13
+ <mock:shadow-root>
14
+ <ul class="list">
15
+ <li class="item">
16
+ <span class="item-content">
17
+ <span><tttx-icon class="hydrated" icon="egg" color="blue"></tttx-icon></span>
18
+ Test
19
+ </span>
20
+ </li>
21
+ </ul>
22
+ </mock:shadow-root>
23
+ </tttx-list>
24
+ `);
25
+ });
26
+ });
@@ -0,0 +1,183 @@
1
+ import { newSpecPage } from '@stencil/core/testing';
2
+ import { TttxList } from '../tttx-list';
3
+ describe('tttx-list', () => {
4
+ it('renders data using JS objects (with icon, clickable)', async () => {
5
+ const page = await newSpecPage({
6
+ components: [TttxList],
7
+ html: '<tttx-list></tttx-list>',
8
+ });
9
+ page.rootInstance.data = [{ icon: 'info', element: '<span><tttx-icon icon="egg" color="blue" /></span> Test', clickable: true }];
10
+ await page.waitForChanges();
11
+ expect(page.root).toEqualHtml(`
12
+ <tttx-list>
13
+ <mock:shadow-root>
14
+ <ul class="list">
15
+ <li class="item clickable">
16
+ <span class="item-content">
17
+ <span><tttx-icon icon="egg" color="blue"></tttx-icon></span>
18
+ Test
19
+ </span>
20
+ <tttx-icon class="align-right" icon="info"></tttx-icon>
21
+ </li>
22
+ </ul>
23
+ </mock:shadow-root>
24
+ </tttx-list>
25
+ `);
26
+ });
27
+ it('renders data using JS objects (with icon, clickable:false)', async () => {
28
+ const page = await newSpecPage({
29
+ components: [TttxList],
30
+ html: '<tttx-list></tttx-list>',
31
+ });
32
+ page.rootInstance.data = [{ icon: 'info', element: '<span><tttx-icon icon="egg" color="blue" /></span> Test' }];
33
+ await page.waitForChanges();
34
+ expect(page.root).toEqualHtml(`
35
+ <tttx-list>
36
+ <mock:shadow-root>
37
+ <ul class="list">
38
+ <li class="item">
39
+ <span class="item-content">
40
+ <span><tttx-icon icon="egg" color="blue"></tttx-icon></span>
41
+ Test
42
+ </span>
43
+ <tttx-icon class="align-right" icon="info"></tttx-icon>
44
+ </li>
45
+ </ul>
46
+ </mock:shadow-root>
47
+ </tttx-list>
48
+ `);
49
+ });
50
+ it('renders data using JS objects (without icon, clickable)', async () => {
51
+ const page = await newSpecPage({
52
+ components: [TttxList],
53
+ html: '<tttx-list></tttx-list>',
54
+ });
55
+ page.rootInstance.data = [{ element: '<span><tttx-icon icon="egg" color="blue" /></span> Test', clickable: true }];
56
+ await page.waitForChanges();
57
+ expect(page.root).toEqualHtml(`
58
+ <tttx-list>
59
+ <mock:shadow-root>
60
+ <ul class="list">
61
+ <li class="item clickable">
62
+ <span class="item-content">
63
+ <span><tttx-icon icon="egg" color="blue"></tttx-icon></span>
64
+ Test
65
+ </span>
66
+ </li>
67
+ </ul>
68
+ </mock:shadow-root>
69
+ </tttx-list>
70
+ `);
71
+ });
72
+ it('renders data using JS objects (without icon, clickable:false)', async () => {
73
+ const page = await newSpecPage({
74
+ components: [TttxList],
75
+ html: '<tttx-list></tttx-list>',
76
+ });
77
+ page.rootInstance.data = [{ element: '<span><tttx-icon icon="egg" color="blue" /></span> Test' }];
78
+ await page.waitForChanges();
79
+ expect(page.root).toEqualHtml(`
80
+ <tttx-list>
81
+ <mock:shadow-root>
82
+ <ul class="list">
83
+ <li class="item">
84
+ <span class="item-content">
85
+ <span><tttx-icon icon="egg" color="blue"></tttx-icon></span>
86
+ Test
87
+ </span>
88
+ </li>
89
+ </ul>
90
+ </mock:shadow-root>
91
+ </tttx-list>
92
+ `);
93
+ });
94
+ it('renders data using JSON', async () => {
95
+ const data = '[{ "icon": "info", "element": "<span><tttx-icon icon=\\"egg\\" color=\\"blue\\" /></span> Test", "clickable": true }]';
96
+ const page = await newSpecPage({
97
+ components: [TttxList],
98
+ html: `<tttx-list data='${data}'></tttx-list>`,
99
+ });
100
+ await page.waitForChanges();
101
+ expect(page.root).toEqualHtml(`
102
+ <tttx-list data="[{ &quot;icon&quot;: &quot;info&quot;, &quot;element&quot;: &quot;<span><tttx-icon icon=\\&quot;egg\\&quot; color=\\&quot;blue\\&quot; /></span> Test&quot;, &quot;clickable&quot;: true }]">
103
+ <mock:shadow-root>
104
+ <ul class="list">
105
+ <li class="item clickable">
106
+ <span class="item-content">
107
+ <span><tttx-icon icon="egg" color="blue"></tttx-icon></span>
108
+ Test
109
+ </span>
110
+ <tttx-icon class="align-right" icon="info"></tttx-icon>
111
+ </li>
112
+ </ul>
113
+ </mock:shadow-root>
114
+ </tttx-list>
115
+ `);
116
+ });
117
+ it('renders nothing when there is no data', async () => {
118
+ const page = await newSpecPage({
119
+ components: [TttxList],
120
+ html: '<tttx-list></tttx-list>',
121
+ });
122
+ page.rootInstance.data = [];
123
+ await page.waitForChanges();
124
+ expect(page.root).toEqualHtml(`
125
+ <tttx-list>
126
+ <mock:shadow-root>
127
+ <ul class="list">
128
+ </ul>
129
+ </mock:shadow-root>
130
+ </tttx-list>
131
+ `);
132
+ });
133
+ it('emits listRowClick event when a clickable row is clicked', async () => {
134
+ const page = await newSpecPage({
135
+ components: [TttxList],
136
+ html: '<tttx-list name="test-list"></tttx-list>',
137
+ });
138
+ const eventSpy = jest.fn();
139
+ page.doc.addEventListener('listRowClick', eventSpy);
140
+ page.rootInstance.data = [
141
+ { element: '<div>Item 1</div>', clickable: true, rowData: 'Item 1' },
142
+ { element: '<div>Item 2</div>', clickable: false, rowData: 'Item 2' },
143
+ ];
144
+ await page.waitForChanges();
145
+ const clickableItem = page.root.shadowRoot.querySelector('.clickable');
146
+ clickableItem.dispatchEvent(new Event('click'));
147
+ expect(eventSpy).toHaveBeenCalledWith(expect.objectContaining({
148
+ detail: { name: 'test-list', data: 'Item 1' },
149
+ }));
150
+ });
151
+ it('does not emit listRowClick event when a non-clickable row is clicked', async () => {
152
+ const page = await newSpecPage({
153
+ components: [TttxList],
154
+ html: '<tttx-list></tttx-list>',
155
+ });
156
+ const eventSpy = jest.fn();
157
+ page.doc.addEventListener('listRowClick', eventSpy);
158
+ page.rootInstance.data = [
159
+ { element: '<div>Item 1</div>', clickable: true, rowData: 'Item 1' },
160
+ { element: '<div>Item 2</div>', clickable: false, rowData: 'Item 2' },
161
+ ];
162
+ await page.waitForChanges();
163
+ const nonClickableItem = page.root.shadowRoot.querySelector(':not(.clickable)');
164
+ await nonClickableItem.dispatchEvent(new Event('click'));
165
+ expect(eventSpy).not.toHaveBeenCalled();
166
+ });
167
+ it('does not emit listRowClick event when a row without rowData is clicked', async () => {
168
+ const page = await newSpecPage({
169
+ components: [TttxList],
170
+ html: '<tttx-list></tttx-list>',
171
+ });
172
+ const eventSpy = jest.fn();
173
+ page.doc.addEventListener('listRowClick', eventSpy);
174
+ page.rootInstance.data = [
175
+ { element: '<div>Item 1</div>', clickable: true },
176
+ { element: '<div>Item 2</div>', clickable: false },
177
+ ];
178
+ await page.waitForChanges();
179
+ const nonClickableItem = page.root.shadowRoot.querySelector('.clickable');
180
+ await nonClickableItem.dispatchEvent(new Event('click'));
181
+ expect(eventSpy).not.toHaveBeenCalled();
182
+ });
183
+ });
@@ -0,0 +1,9 @@
1
+ import { newE2EPage } from '@stencil/core/testing';
2
+ describe('tttx-standalone-input', () => {
3
+ it('renders', async () => {
4
+ const page = await newE2EPage();
5
+ await page.setContent('<tttx-standalone-input></tttx-standalone-input>');
6
+ const element = await page.find('tttx-standalone-input');
7
+ expect(element).toHaveClass('hydrated');
8
+ });
9
+ });