ripple 0.2.41 → 0.2.43

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.
@@ -70,6 +70,24 @@ describe('basic', () => {
70
70
  expect(container.querySelector('div').textContent).toEqual('Hello Ripple');
71
71
  });
72
72
 
73
+ it('render empty string literal', () => {
74
+ component Basic() {
75
+ <div>{''}</div>
76
+ }
77
+
78
+ render(Basic);
79
+ expect(container.querySelector('div').textContent).toEqual('');
80
+ });
81
+
82
+ it('render empty template literal', () => {
83
+ component Basic() {
84
+ <div>{``}</div>
85
+ }
86
+
87
+ render(Basic);
88
+ expect(container.querySelector('div').textContent).toEqual('');
89
+ });
90
+
73
91
  it('render dynamic class attribute', () => {
74
92
  component Basic() {
75
93
  let $active = false;
@@ -145,6 +163,31 @@ describe('basic', () => {
145
163
  expect(div.style.fontWeight).toBe('bold');
146
164
  });
147
165
 
166
+ it('render spread props without duplication', () => {
167
+ component App() {
168
+ const checkBoxProp = {name:'car'}
169
+
170
+ <div>
171
+ <input {...checkBoxProp} type="checkbox" id="vehicle1" value="Bike" />
172
+ </div>
173
+ }
174
+
175
+ render(App);
176
+
177
+ const input = container.querySelector('input');
178
+ const html = container.innerHTML;
179
+
180
+ expect(input.getAttribute('name')).toBe('car');
181
+ expect(input.getAttribute('type')).toBe('checkbox');
182
+ expect(input.getAttribute('id')).toBe('vehicle1');
183
+ expect(input.getAttribute('value')).toBe('Bike');
184
+
185
+ expect(html).not.toContain('type="checkbox"type="checkbox"');
186
+ expect(html).not.toContain('value="Bike"value="Bike"');
187
+
188
+ expect(container).toMatchSnapshot();
189
+ });
190
+
148
191
  it('render dynamic boolean attributes', () => {
149
192
  component Basic() {
150
193
  let $disabled = false;
@@ -350,7 +393,7 @@ describe('basic', () => {
350
393
  let $focusCount = 0;
351
394
  let $clickCount = 0;
352
395
 
353
- <button
396
+ <button
354
397
  onFocus={() => $focusCount++}
355
398
  onClick={() => $clickCount++}
356
399
  >{'Test Button'}</button>
@@ -465,7 +508,7 @@ describe('basic', () => {
465
508
  it('renders with computed reactive state', () => {
466
509
  component Basic() {
467
510
  let $count = 5;
468
-
511
+
469
512
  <div class='count'>{$count}</div>
470
513
  <div class='doubled'>{$count * 2}</div>
471
514
  <div class='is-even'>{$count % 2 === 0 ? 'Even' : 'Odd'}</div>
@@ -543,7 +586,7 @@ describe('basic', () => {
543
586
 
544
587
  <button onClick={() => $showContent = !$showContent}>{'Toggle Content'}</button>
545
588
  <button onClick={() => $userRole = $userRole === 'guest' ? 'admin' : 'guest'}>{'Toggle Role'}</button>
546
-
589
+
547
590
  <div class='content'>
548
591
  if ($showContent) {
549
592
  if ($userRole === 'admin') {
@@ -655,7 +698,7 @@ describe('basic', () => {
655
698
  <div class='counter'>{$counter}</div>
656
699
  <div class='parity'>{$isEven ? 'Even' : 'Odd'}</div>
657
700
  <div class='history-count'>{$history.length}</div>
658
-
701
+
659
702
  <button class='inc-btn' onClick={handleIncrement}>{'+'}</button>
660
703
  <button class='dec-btn' onClick={handleDecrement}>{'-'}</button>
661
704
  <button class='reset-btn' onClick={handleReset}>{'Reset'}</button>
@@ -918,4 +961,116 @@ describe('basic', () => {
918
961
  expect(divs[3].textContent).toBe('Even numbers: ');
919
962
  expect(logs).toEqual(['0, 0', '1, 0', 'arr includes 1', '1, 1']);
920
963
  });
964
+
965
+ it('it retains this context with bracketed prop functions and keeps original chaining', () => {
966
+ component App() {
967
+ const SYMBOL_PROP = Symbol();
968
+ let $hasError = false;
969
+ const obj = {
970
+ $count: 0,
971
+ increment() {
972
+ this.$count++;
973
+ },
974
+ [SYMBOL_PROP]() {
975
+ this.$count++;
976
+ },
977
+ arr: [() => obj.$count++, () => obj.$count--],
978
+ };
979
+
980
+ const obj2 = null;
981
+
982
+ <button onClick={() => obj['increment']()}>{'Increment'}</button>
983
+ <button onClick={() => obj[SYMBOL_PROP]()}>{'Increment'}</button>
984
+ <button
985
+ onClick={() => {
986
+ $hasError = false;
987
+ try {
988
+ obj['nonexistent']();
989
+ } catch {
990
+ $hasError = true;
991
+ }
992
+ }}
993
+ >{'Nonexistent'}</button>
994
+ <button
995
+ onClick={() => {
996
+ $hasError = false;
997
+ try {
998
+ obj['nonexistent']?.();
999
+ } catch {
1000
+ $hasError = true;
1001
+ }
1002
+ }}
1003
+ >{'Nonexistent chaining'}</button>
1004
+ <button
1005
+ onClick={() => {
1006
+ $hasError = false;
1007
+ try {
1008
+ obj2['nonexistent']();
1009
+ } catch {
1010
+ $hasError = true;
1011
+ }
1012
+ }}
1013
+ >{'Object null'}</button>
1014
+ <button
1015
+ onClick={() => {
1016
+ $hasError = false;
1017
+ try {
1018
+ obj2?.['nonexistent']?.();
1019
+ } catch {
1020
+ $hasError = true;
1021
+ }
1022
+ }}
1023
+ >{'Object null chained'}</button>
1024
+ <button onClick={() => obj.arr[obj.arr.length - 1]()}>{'BinaryExpression prop'}</button>
1025
+
1026
+ <span>{obj.$count}</span>
1027
+ <span>{$hasError}</span>
1028
+ }
1029
+
1030
+ render(App);
1031
+
1032
+ const button1 = container.querySelectorAll('button')[0];
1033
+ const button2 = container.querySelectorAll('button')[1];
1034
+ const button3 = container.querySelectorAll('button')[2];
1035
+ const button4 = container.querySelectorAll('button')[3];
1036
+ const button5 = container.querySelectorAll('button')[4];
1037
+ const button6 = container.querySelectorAll('button')[5];
1038
+ const button7 = container.querySelectorAll('button')[6];
1039
+
1040
+ const countSpan = container.querySelectorAll('span')[0];
1041
+ const errorSpan = container.querySelectorAll('span')[1];
1042
+
1043
+ expect(countSpan.textContent).toBe('0');
1044
+ expect(errorSpan.textContent).toBe('false');
1045
+
1046
+ button1.click();
1047
+ flushSync();
1048
+
1049
+ expect(countSpan.textContent).toBe('1');
1050
+
1051
+ button2.click();
1052
+ flushSync();
1053
+
1054
+ expect(countSpan.textContent).toBe('2');
1055
+
1056
+ button3.click();
1057
+ flushSync();
1058
+ expect(errorSpan.textContent).toBe('true');
1059
+
1060
+ button4.click();
1061
+ flushSync();
1062
+ expect(errorSpan.textContent).toBe('false');
1063
+
1064
+ button5.click();
1065
+ flushSync();
1066
+ expect(errorSpan.textContent).toBe('true');
1067
+
1068
+ button6.click();
1069
+ flushSync();
1070
+ expect(errorSpan.textContent).toBe('false');
1071
+
1072
+ button7.click();
1073
+ flushSync();
1074
+ expect(countSpan.textContent).toBe('1');
1075
+ });
921
1076
  });
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
2
  import { mount, RippleArray } from 'ripple';
3
+ import { parse } from 'ripple/compiler'
3
4
 
4
5
  describe('compiler success tests', () => {
5
6
  let container;
@@ -20,6 +21,30 @@ describe('compiler success tests', () => {
20
21
  container = null;
21
22
  });
22
23
 
24
+
25
+ it('Parses style content correctly', () => {
26
+ const source = `export component App() {
27
+ <div id="myid" class="myclass">{"Hello World"}</div>
28
+
29
+ <style>#style</style>
30
+ }`;
31
+ const style1 = '.myid {color: green }';
32
+ const style2 = '#myid {color: green }';
33
+ const style3 = 'div {color: green }';
34
+
35
+ let input = source.replace('#style', style1);
36
+ let ast = parse(input);
37
+ expect(ast.body[0].declaration.css.source).toEqual(style1);
38
+
39
+ input = source.replace('#style', style2);
40
+ ast = parse(input);
41
+ expect(ast.body[0].declaration.css.source).toEqual(style2);
42
+
43
+ input = source.replace('#style', style3);
44
+ ast = parse(input);
45
+ expect(ast.body[0].declaration.css.source).toEqual(style3);
46
+ });
47
+
23
48
  it('renders without crashing', () => {
24
49
  component App() {
25
50
  let foo;
@@ -153,4 +178,34 @@ describe('compiler success tests', () => {
153
178
  124, 123, 124, 123, 124, 123, 124, 123
154
179
  ]);
155
180
  });
156
- });
181
+
182
+ it('renders without crashing using mapped types', () => {
183
+ component App() {
184
+ type RecordKey = 'test';
185
+ type RecordValue = { a: string, b: number };
186
+
187
+ const config: Record<RecordKey, RecordValue> = {
188
+ test: {
189
+ a: 'test',
190
+ b: 1
191
+ },
192
+ };
193
+
194
+ const config2: { [key in RecordKey]: RecordValue } = {
195
+ test: {
196
+ a: 'test2',
197
+ b: 2
198
+ }
199
+ }
200
+
201
+ const config3: { [key: RecordKey]: RecordValue } = {
202
+ test: {
203
+ a: 'test3',
204
+ b: 3
205
+ }
206
+ }
207
+ }
208
+
209
+ render(App);
210
+ });
211
+ });