1#[cfg(test)]
2mod stylex_create_theme {
3
4 use indexmap::IndexMap;
5 use swc_core::ecma::ast::PropOrSpread;
6
7 use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
8 use crate::shared::structures::state_manager::StateManager;
9 use crate::shared::structures::types::InjectableStylesMap;
10 use crate::shared::transformers::stylex_create_theme::stylex_create_theme;
11 use crate::shared::utils::ast::convertors::create_string_expr;
12 use stylex_ast::ast::factories::{
13 create_key_value_prop, create_nested_object_prop, create_object_expression,
14 create_string_key_value_prop,
15 };
16 use stylex_types::structures::injectable_style::InjectableStyle;
17
18 fn default_vars_factory(args: &[(&str, &str)]) -> EvaluateResultValue {
19 let props = args
20 .iter()
21 .map(|(key, value)| create_string_key_value_prop(key, value))
22 .collect::<Vec<PropOrSpread>>();
23
24 EvaluateResultValue::Expr(create_object_expression(props))
25 }
26
27 fn exprected_result_factory(injected_styles: &[(&str, (&str, f64))]) -> InjectableStylesMap {
28 let mut expected_injected_styles = IndexMap::new();
29
30 for injected_style in injected_styles {
31 let (key, value) = injected_style;
32 expected_injected_styles.insert(
33 key.to_string(),
34 InjectableStyle::regular(value.0.to_string(), Some(value.1)),
35 );
36 }
37 expected_injected_styles
38 }
39
40 type StyleObjectFactoryArgs<'a> = [(
41 &'a str,
42 &'a [(&'a str, &'a str)],
43 &'a [(&'a str, &'a [(&'a str, &'a str)])],
44 )];
45
46 fn style_object_factory(
47 args: &StyleObjectFactoryArgs,
48 str_args: &[(&str, &str)],
49 ) -> EvaluateResultValue {
50 let mut props = args
51 .iter()
52 .map(|(key, values, nested_values)| {
53 let mut props = values
54 .iter()
55 .map(|(key, value)| create_key_value_prop(key, create_string_expr(value)))
56 .collect::<Vec<PropOrSpread>>();
57
58 let nested_props = nested_values
59 .iter()
60 .map(|val| {
61 let props = val
62 .1
63 .iter()
64 .map(|(key, value)| create_key_value_prop(key, create_string_expr(value)))
65 .collect::<Vec<PropOrSpread>>();
66
67 create_key_value_prop(val.0, create_object_expression(props))
68 })
69 .collect::<Vec<PropOrSpread>>();
70
71 props.extend(nested_props);
72
73 create_nested_object_prop(key, props)
74 })
75 .collect::<Vec<PropOrSpread>>();
76
77 for (key, value) in str_args.iter() {
78 props.push(create_string_key_value_prop(key, value));
79 }
80
81 EvaluateResultValue::Expr(create_object_expression(props))
82 }
83
84 #[test]
85 fn overrides_set_of_vars_with_css_class() {
86 let export_id = "TestTheme.stylex.js//buttonTheme";
87
88 let mut default_vars = default_vars_factory(&[
89 ("__varGroupHash__", export_id),
90 ("bgColor", "var(--xgck17p)"),
91 ("bgColorDisabled", "var(--xpegid5)"),
92 ("cornerRadius", "var(--xrqfjmn)"),
93 ("fgColor", "var(--x4y59db)"),
94 ]);
95
96 let created_theme = style_object_factory(
97 &[
98 (
99 "bgColor",
100 &[
101 ("default", "green"),
102 ("@media (prefers-color-scheme: dark)", "lightgreen"),
103 ("@media print", "transparent"),
104 ],
105 &[],
106 ),
107 (
108 "bgColorDisabled",
109 &[
110 ("default", "antiquewhite"),
111 ("@media (prefers-color-scheme: dark)", "floralwhite"),
112 ],
113 &[],
114 ),
115 ("cornerRadius", &[("default", "6px")], &[]),
116 ],
117 &[("fgColor", "coral")],
118 );
119
120 let (class_name_output, css_output) = stylex_create_theme(
121 &mut default_vars,
122 &created_theme,
123 &mut StateManager::default(),
124 &mut IndexMap::default(),
125 );
126
127 let key = class_name_output
128 .get(export_id)
129 .unwrap()
130 .as_string()
131 .unwrap()
132 .split(' ')
133 .next()
134 .unwrap();
135
136 let injectable_rule = css_output.get(key).unwrap();
137
138 assert_eq!(
139 injectable_rule,
140 exprected_result_factory(&[(
141 export_id,
142 (
143 ".xtrlmmh, .xtrlmmh:root{--xgck17p:green;--xpegid5:antiquewhite;--xrqfjmn:6px;--x4y59db:coral;}",
144 0.5
145 )
146 )])
147 .get(export_id)
148 .unwrap()
149 )
150 }
151
152 #[test]
153 fn overrides_set_of_literal_vars_with_css_class() {
154 let export_id = "TestTheme.stylex.js//buttonTheme";
155
156 let mut default_vars = default_vars_factory(&[
157 ("__varGroupHash__", export_id),
158 ("--bgColor", "var(--bgColor)"),
159 ("--bgColorDisabled", "var(--bgColorDisabled)"),
160 ("--cornerRadius", "var(--cornerRadius)"),
161 ("--fgColor", "var(--fgColor)"),
162 ]);
163
164 let created_theme = style_object_factory(
165 &[
166 (
167 "--bgColor",
168 &[
169 ("default", "green"),
170 ("@media (prefers-color-scheme: dark)", "lightgreen"),
171 ("@media print", "transparent"),
172 ],
173 &[],
174 ),
175 (
176 "--bgColorDisabled",
177 &[
178 ("default", "antiquewhite"),
179 ("@media (prefers-color-scheme: dark)", "floralwhite"),
180 ],
181 &[],
182 ),
183 ("--cornerRadius", &[("default", "6px")], &[]),
184 ],
185 &[("--fgColor", "coral")],
186 );
187
188 let (class_name_output, css_output) = stylex_create_theme(
189 &mut default_vars,
190 &created_theme,
191 &mut StateManager::default(),
192 &mut IndexMap::default(),
193 );
194
195 let key = class_name_output
196 .get(export_id)
197 .unwrap()
198 .as_string()
199 .unwrap()
200 .split(' ')
201 .next()
202 .unwrap();
203
204 let injectable_rule = css_output.get(key).unwrap();
205
206 assert_eq!(
207 injectable_rule,
208 exprected_result_factory(&[(
209 export_id,
210 (
211 ".x4znj40, .x4znj40:root{--bgColor:green;--bgColorDisabled:antiquewhite;--cornerRadius:6px;--fgColor:coral;}",
212 0.5
213 )
214 )])
215 .get(export_id)
216 .unwrap()
217 )
218 }
219
220 #[test]
221 fn variables_order_does_not_change_the_hash() {
222 let export_id = "TestTheme.stylex.js//buttonTheme";
223
224 let mut default_vars = default_vars_factory(&[
225 ("__varGroupHash__", export_id),
226 ("bgColor", "var(--xgck17p)"),
227 ("bgColorDisabled", "var(--xpegid5)"),
228 ("cornerRadius", "var(--xrqfjmn)"),
229 ("fgColor", "var(--x4y59db)"),
230 ]);
231
232 let created_theme = style_object_factory(
233 &[
234 (
235 "bgColor",
236 &[
237 ("default", "green"),
238 ("@media (prefers-color-scheme: dark)", "lightgreen"),
239 ("@media print", "transparent"),
240 ],
241 &[],
242 ),
243 (
244 "bgColorDisabled",
245 &[
246 ("default", "antiquewhite"),
247 ("@media (prefers-color-scheme: dark)", "floralwhite"),
248 ],
249 &[],
250 ),
251 ("cornerRadius", &[("default", "6px")], &[]),
252 ],
253 &[("fgColor", "coral")],
254 );
255
256 let created_theme_2 = style_object_factory(
257 &[
258 ("cornerRadius", &[("default", "6px")], &[]),
259 (
260 "bgColorDisabled",
261 &[
262 ("default", "antiquewhite"),
263 ("@media (prefers-color-scheme: dark)", "floralwhite"),
264 ],
265 &[],
266 ),
267 (
268 "bgColor",
269 &[
270 ("default", "green"),
271 ("@media (prefers-color-scheme: dark)", "lightgreen"),
272 ("@media print", "transparent"),
273 ],
274 &[],
275 ),
276 ],
277 &[("fgColor", "coral")],
278 );
279
280 let (class_name_output, css_output) = stylex_create_theme(
281 &mut default_vars,
282 &created_theme,
283 &mut StateManager::default(),
284 &mut IndexMap::default(),
285 );
286
287 let (class_name_output_2, css_output_2) = stylex_create_theme(
288 &mut default_vars,
289 &created_theme_2,
290 &mut StateManager::default(),
291 &mut IndexMap::default(),
292 );
293
294 assert_eq!(class_name_output, class_name_output_2);
295
296 let key = class_name_output
297 .get(export_id)
298 .unwrap()
299 .as_string()
300 .unwrap()
301 .split(' ')
302 .next()
303 .unwrap();
304
305 let key_2 = class_name_output_2
306 .get(export_id)
307 .unwrap()
308 .as_string()
309 .unwrap()
310 .split(' ')
311 .next()
312 .unwrap();
313
314 let injectable_rule = css_output.get(key).unwrap();
315 let injectable_rule_2 = css_output_2.get(key_2).unwrap();
316
317 assert_eq!(injectable_rule, injectable_rule_2);
318 }
319
320 #[test]
321 fn adding_an_at_rule_changes_the_hash() {
322 let export_id = "TestTheme.stylex.js//buttonTheme";
323
324 let mut default_vars = default_vars_factory(&[
325 ("__varGroupHash__", export_id),
326 ("bgColor", "var(--xgck17p)"),
327 ]);
328
329 let created_theme = style_object_factory(&[], &[("bgColor", "green")]);
330
331 let created_theme_2 = style_object_factory(
332 &[(
333 "bgColor",
334 &[
335 ("default", "green"),
336 ("@media (prefers-color-scheme: dark)", "lightgreen"),
337 ],
338 &[],
339 )],
340 &[],
341 );
342
343 let (class_name_output, css_output) = stylex_create_theme(
344 &mut default_vars,
345 &created_theme,
346 &mut StateManager::default(),
347 &mut IndexMap::default(),
348 );
349
350 let (class_name_output_2, css_output_2) = stylex_create_theme(
351 &mut default_vars,
352 &created_theme_2,
353 &mut StateManager::default(),
354 &mut IndexMap::default(),
355 );
356
357 assert_ne!(class_name_output, class_name_output_2);
358
359 let key = class_name_output
360 .get(export_id)
361 .unwrap()
362 .as_string()
363 .unwrap()
364 .split(' ')
365 .next()
366 .unwrap();
367
368 let key_2 = class_name_output_2
369 .get(export_id)
370 .unwrap()
371 .as_string()
372 .unwrap()
373 .split(' ')
374 .next()
375 .unwrap();
376
377 let injectable_rule = css_output.get(key).unwrap();
378 let injectable_rule_2 = css_output_2.get(key_2).unwrap();
379
380 assert_ne!(injectable_rule, injectable_rule_2);
381 }
382
383 #[test]
384 fn generates_styles_for_nested_at_rules() {
385 let export_id = "TestTheme.stylex.js//buttonTheme";
386
387 let mut default_vars = default_vars_factory(&[
388 ("__varGroupHash__", export_id),
389 ("bgColor", "var(--xgck17p)"),
390 ]);
391
392 let created_theme = style_object_factory(
393 &[(
394 "bgColor",
395 &[
396 ("default", "green"),
397 ("@supports (color: oklab(0 0 0))", "oklab(0.7 -0.3 -0.4)"),
398 ],
399 &[(
400 "@media (prefers-color-scheme: dark)",
401 &[
402 ("default", "lightgreen"),
403 ("@supports (color: oklab(0 0 0))", "oklab(0.7 -0.2 -0.4)"),
404 ],
405 )],
406 )],
407 &[],
408 );
409
410 let (_class_name_output, css_output) = stylex_create_theme(
411 &mut default_vars,
412 &created_theme,
413 &mut StateManager::default(),
414 &mut IndexMap::default(),
415 );
416
417 assert_eq!(
418 css_output,
419 exprected_result_factory(&[
420 (
421 "x2y918k",
422 (".x2y918k, .x2y918k:root{--xgck17p:green;}", 0.5)
423 ),
424 (
425 "x2y918k-1lveb7",
426 (
427 "@media (prefers-color-scheme: dark){.x2y918k, .x2y918k:root{--xgck17p:lightgreen;}}",
428 0.6
429 )
430 ),
431 (
432 "x2y918k-1e6ryz3",
433 (
434 "@supports (color: oklab(0 0 0)){@media (prefers-color-scheme: dark){.x2y918k, .x2y918k:root{--xgck17p:oklab(0.7 -0.2 -0.4);}}}",
435 0.7
436 )
437 ),
438 (
439 "x2y918k-kpd015",
440 (
441 "@supports (color: oklab(0 0 0)){.x2y918k, .x2y918k:root{--xgck17p:oklab(0.7 -0.3 -0.4);}}",
442 0.6
443 )
444 )
445 ])
446 )
447 }
448
449 #[test]
450 fn generates_styles_for_typed_nested_at_rules() {
451 let export_id = "TestTheme.stylex.js//buttonTheme";
452
453 let mut default_vars = default_vars_factory(&[
454 ("__varGroupHash__", export_id),
455 ("bgColor", "var(--xgck17p)"),
456 ]);
457
458 let created_theme = style_object_factory(
459 &[(
460 "bgColor",
461 &[],
462 &[
463 (
464 "default",
465 &[
466 ("default", "green"),
467 ("@supports (color: oklab(0 0 0))", "oklab(0.7 -0.3 -0.4)"),
468 ],
469 ),
470 (
471 "@media (prefers-color-scheme: dark)",
472 &[
473 ("default", "lightgreen"),
474 ("@supports (color: oklab(0 0 0))", "oklab(0.7 -0.2 -0.4)"),
475 ],
476 ),
477 ],
478 )],
479 &[],
480 );
481
482 let (_class_name_output, css_output) = stylex_create_theme(
483 &mut default_vars,
484 &created_theme,
485 &mut StateManager::default(),
486 &mut IndexMap::default(),
487 );
488
489 assert_eq!(
490 css_output,
491 exprected_result_factory(&[
492 (
493 "x2y918k",
494 (".x2y918k, .x2y918k:root{--xgck17p:green;}", 0.5)
495 ),
496 (
497 "x2y918k-1lveb7",
498 (
499 "@media (prefers-color-scheme: dark){.x2y918k, .x2y918k:root{--xgck17p:lightgreen;}}",
500 0.6
501 )
502 ),
503 (
504 "x2y918k-1e6ryz3",
505 (
506 "@supports (color: oklab(0 0 0)){@media (prefers-color-scheme: dark){.x2y918k, .x2y918k:root{--xgck17p:oklab(0.7 -0.2 -0.4);}}}",
507 0.7
508 )
509 ),
510 (
511 "x2y918k-kpd015",
512 (
513 "@supports (color: oklab(0 0 0)){.x2y918k, .x2y918k:root{--xgck17p:oklab(0.7 -0.3 -0.4);}}",
514 0.6
515 )
516 )
517 ])
518 )
519 }
520}