1#[cfg(test)]
2mod stylex_create {
3 use std::rc::Rc;
4
5 use indexmap::IndexMap;
6 use swc_core::ecma::ast::{Expr, ExprOrSpread, KeyValueProp};
7
8 use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
9 use crate::shared::enums::data_structures::flat_compiled_styles_value::FlatCompiledStylesValue;
10 use crate::shared::structures::functions::FunctionMap;
11 use crate::shared::structures::state::EvaluationState;
12 use crate::shared::structures::state_manager::StateManager;
13 use crate::shared::structures::types::{ClassPathsMap, InjectableStylesMap, StylesObjectMap};
14 use crate::shared::transformers::stylex_create::stylex_create_set;
15 use crate::shared::utils::ast::convertors::create_string_expr;
16 use stylex_ast::ast::factories::{
17 create_array_expression, create_key_value_prop, create_key_value_prop_ident,
18 create_nested_object_prop, create_null_lit, create_object_expression,
19 create_string_key_value_prop,
20 };
21 use stylex_constants::constants::common::COMPILED_KEY;
22 use stylex_structures::stylex_state_options::StyleXStateOptions;
23 use stylex_types::structures::injectable_style::InjectableStyle;
24
25 fn style_object_factory(args: &[(&str, &[(&str, &str)])]) -> IndexMap<Expr, Vec<KeyValueProp>> {
26 let mut object = IndexMap::new();
27
28 for (key, value) in args {
29 object.insert(
30 create_string_expr(key),
31 value
32 .iter()
33 .map(|(key, value)| create_key_value_prop_ident(key, create_string_expr(value)))
34 .collect(),
35 );
36 }
37
38 object
39 }
40
41 type StyleNestedObjectFactoryArgs<'a> = [(&'a str, &'a [(&'a str, &'a [(&'a str, &'a str)])])];
42
43 fn style_nested_object_factory(
44 args: &StyleNestedObjectFactoryArgs,
45 ) -> IndexMap<Expr, Vec<KeyValueProp>> {
46 let mut object = IndexMap::new();
47
48 for (key, value) in args {
49 object.insert(
50 create_string_expr(key),
51 value
52 .iter()
53 .map(|(key, value)| {
54 create_key_value_prop_ident(
55 key,
56 create_object_expression(
57 value
58 .iter()
59 .map(|(key, value)| create_string_key_value_prop(key, value))
60 .collect(),
61 ),
62 )
63 })
64 .collect(),
65 );
66 }
67
68 object
69 }
70
71 enum StringOrNull<'a> {
72 String(&'a str),
73 Null,
74 }
75
76 enum DepthProps<'a> {
77 One(&'a str),
78 Two(&'a [(&'a str, &'a StringOrNull<'a>)]),
79 Three(&'a [(&'a str, &'a [(&'a str, &'a str)])]),
80 }
82
83 type StyleMultipleDepthNestedObjectFactoryArgs<'a> = [(
84 &'a str,
85 &'a [(&'a str, &'a [(&'a str, &'a DepthProps<'a>)])],
86 )];
87
88 fn style_multiple_depth_nested_object_factory(
89 args: &StyleMultipleDepthNestedObjectFactoryArgs,
90 ) -> IndexMap<Expr, Vec<KeyValueProp>> {
91 let mut object = IndexMap::new();
92
93 for (key, value) in args {
94 object.insert(
95 create_string_expr(key),
96 value
97 .iter()
98 .map(|(key, value)| {
99 create_key_value_prop_ident(
100 key,
101 create_object_expression(
102 value
103 .iter()
104 .map(|(key, values)| match values {
105 DepthProps::One(strng) => create_string_key_value_prop(key, strng),
106 DepthProps::Two(arr) => create_nested_object_prop(
107 key,
108 arr
109 .iter()
110 .map(|(key, value)| match value {
111 StringOrNull::String(strng) => create_string_key_value_prop(key, strng),
112 StringOrNull::Null => {
113 create_key_value_prop(key, Expr::Lit(create_null_lit()))
114 },
115 })
116 .collect(),
117 ),
118 DepthProps::Three(arr) => create_nested_object_prop(
119 key,
120 arr
121 .iter()
122 .map(|(key, values)| {
123 create_nested_object_prop(
124 key,
125 values
126 .iter()
127 .map(|(key, value)| create_string_key_value_prop(key, value))
128 .collect(),
129 )
130 })
131 .collect(),
132 ),
133 })
157 .collect(),
158 ),
159 )
160 })
161 .collect(),
162 );
163 }
164
165 object
166 }
167
168 type StyleArrayObjectFactoryArgs<'a> = [(&'a str, &'a [(&'a str, &'a [&'a str])])];
169 fn style_array_object_factory(
170 args: &StyleArrayObjectFactoryArgs,
171 ) -> IndexMap<Expr, Vec<KeyValueProp>> {
172 let mut object = IndexMap::new();
173
174 for (key, value) in args {
175 object.insert(
176 create_string_expr(key),
177 value
178 .iter()
179 .map(|(key, value)| {
180 let elems = value
181 .iter()
182 .map(|arg| {
183 Some(ExprOrSpread {
184 spread: None,
185 expr: Box::new(create_string_expr(arg)),
186 })
187 })
188 .collect::<Vec<Option<ExprOrSpread>>>();
189
190 create_key_value_prop_ident(key, create_array_expression(elems))
191 })
192 .collect(),
193 );
194 }
195
196 object
197 }
198
199 type InjectedStylesArg<'a> = [(&'a str, &'a [(&'a str, (&'a str, f64))])];
200
201 fn exprected_result_factory(
202 resolved_namespaces: &[(&str, &[(&str, &str)])],
203 injected_styles: &InjectedStylesArg,
204 class_paths_in_namespace: &[(&str, &[(&str, &[&str])])],
205 ) -> (StylesObjectMap, InjectableStylesMap, ClassPathsMap) {
206 let mut expected_resolved_namespaces = IndexMap::new();
207 let mut expected_injected_styles = IndexMap::new();
208 let mut expected_class_paths_in_namespace = IndexMap::new();
209
210 for (resolved_namespace, namespace) in resolved_namespaces {
211 let mut default_val = IndexMap::new();
212
213 default_val.insert(
214 COMPILED_KEY.to_string(),
215 Rc::new(FlatCompiledStylesValue::Bool(true)),
216 );
217
218 for (key, value) in namespace.iter() {
219 default_val.insert(
220 key.to_string(),
221 Rc::new(if value.eq(&"null") {
222 FlatCompiledStylesValue::Null
223 } else {
224 FlatCompiledStylesValue::String(value.to_string())
225 }),
226 );
227 }
228
229 expected_resolved_namespaces.insert(resolved_namespace.to_string(), Rc::new(default_val));
230 }
231
232 for injected_style in injected_styles {
233 for (key, inj) in injected_style.1 {
234 let (value, priority) = inj;
235 expected_injected_styles.insert(
236 key.to_string(),
237 InjectableStyle::regular(value.to_string(), Some(*priority)),
238 );
239 }
240 }
241
242 for (namespace, class_paths) in class_paths_in_namespace {
243 let mut default_val = IndexMap::new();
244
245 for (key, value) in class_paths.iter() {
246 default_val.insert(
247 key.to_string(),
248 value.iter().map(|v| v.to_string()).collect(),
249 );
250 }
251
252 expected_class_paths_in_namespace.insert(namespace.to_string(), Rc::new(default_val));
253 }
254
255 (
256 expected_resolved_namespaces,
257 expected_injected_styles,
258 expected_class_paths_in_namespace,
259 )
260 }
261
262 fn stylex_create(
263 style_object: IndexMap<Expr, Vec<KeyValueProp>>,
264 ) -> (StylesObjectMap, InjectableStylesMap, ClassPathsMap) {
265 stylex_create_set(
266 &EvaluateResultValue::Map(style_object),
267 &mut EvaluationState::default(),
268 &mut StateManager {
269 options: StyleXStateOptions {
270 debug: true,
271 enable_debug_class_names: true,
272
273 ..Default::default()
274 },
275 ..Default::default()
276 },
277 &FunctionMap::default(),
278 )
279 }
280
281 #[test]
282 fn color_red() {
283 let object =
284 style_object_factory(&[("default", &[("backgroundColor", "red"), ("color", "blue")])]);
285
286 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
287
288 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
289 exprected_result_factory(
290 &[(
291 "default",
292 &[
293 ("backgroundColor-kWkggS", "backgroundColor-xrkmrrc"),
294 ("color-kMwMTN", "color-xju2f9n"),
295 ],
296 )],
297 &[(
298 "default",
299 &[
300 (
301 "backgroundColor-xrkmrrc",
302 (".backgroundColor-xrkmrrc{background-color:red}", 3000.0),
303 ),
304 ("color-xju2f9n", (".color-xju2f9n{color:blue}", 3000.0)),
305 ],
306 )],
307 &[(
308 "default",
309 &[
310 ("backgroundColor-xrkmrrc", &["backgroundColor"]),
311 ("color-xju2f9n", &["color"]),
312 ],
313 )],
314 );
315
316 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
317 assert_eq!(injected_styles, expected_injected_styles);
318 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace);
319 }
320
321 #[test]
322 fn webkit() {
323 let object = style_object_factory(&[(
324 "default",
325 &[("WebkitBoxOrient", "vertical"), ("WebkitLineClamp", "2")],
326 )]);
327
328 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
329
330 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
331 exprected_result_factory(
332 &[(
333 "default",
334 &[
335 ("WebkitBoxOrient-kgKLqz", "WebkitBoxOrient-x1ua5tub"),
336 ("WebkitLineClamp-kJFfOR", "WebkitLineClamp-x1h7i4cw"),
337 ],
338 )],
339 &[(
340 "default",
341 &[
342 (
343 "WebkitBoxOrient-x1ua5tub",
344 (
345 ".WebkitBoxOrient-x1ua5tub{-webkit-box-orient:vertical}",
346 3000.0,
347 ),
348 ),
349 (
350 "WebkitLineClamp-x1h7i4cw",
351 (".WebkitLineClamp-x1h7i4cw{-webkit-line-clamp:2}", 3000.0),
352 ),
353 ],
354 )],
355 &[(
356 "default",
357 &[
358 ("WebkitBoxOrient-x1ua5tub", &["WebkitBoxOrient"]),
359 ("WebkitLineClamp-x1h7i4cw", &["WebkitLineClamp"]),
360 ],
361 )],
362 );
363
364 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
365 assert_eq!(injected_styles, expected_injected_styles);
366 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace);
367 }
368
369 #[test]
370 fn transition_property_margin_top() {
371 let camel_case_object =
372 style_object_factory(&[("default", &[("transitionProperty", "marginTop")])]);
373 let kebab_case_object =
374 style_object_factory(&[("default", &[("transitionProperty", "margin-top")])]);
375
376 let camel_case = stylex_create(camel_case_object);
377 let kebab_case = stylex_create(kebab_case_object);
378
379 assert_eq!(camel_case, kebab_case);
380
381 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = camel_case;
382
383 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
384 exprected_result_factory(
385 &[(
386 "default",
387 &[("transitionProperty-k1ekBW", "transitionProperty-x1cfch2b")],
388 )],
389 &[(
390 "default",
391 &[(
392 "transitionProperty-x1cfch2b",
393 (
394 ".transitionProperty-x1cfch2b{transition-property:margin-top}",
395 3000.0,
396 ),
397 )],
398 )],
399 &[(
400 "default",
401 &[("transitionProperty-x1cfch2b", &["transitionProperty"])],
402 )],
403 );
404
405 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
406 assert_eq!(injected_styles, expected_injected_styles);
407 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace);
408 }
409
410 #[test]
411 fn will_change_margin_top() {
412 let camel_case_object = style_object_factory(&[("default", &[("willChange", "marginTop")])]);
413 let kebab_case_object = style_object_factory(&[("default", &[("willChange", "margin-top")])]);
414
415 let camel_case = stylex_create(camel_case_object);
416 let kebab_case = stylex_create(kebab_case_object);
417
418 assert_eq!(camel_case, kebab_case);
419
420 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = camel_case;
421
422 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
423 exprected_result_factory(
424 &[("default", &[("willChange-k6sLGO", "willChange-x1a6dnx1")])],
425 &[(
426 "default",
427 &[(
428 "willChange-x1a6dnx1",
429 (".willChange-x1a6dnx1{will-change:margin-top}", 3000.0),
430 )],
431 )],
432 &[("default", &[("willChange-x1a6dnx1", &["willChange"])])],
433 );
434
435 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
436 assert_eq!(injected_styles, expected_injected_styles);
437 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
438 }
439
440 #[test]
441 fn transition_property_dash_dash_foo() {
442 let object = style_object_factory(&[("default", &[("transitionProperty", "--foo")])]);
443
444 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
445
446 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
447 exprected_result_factory(
448 &[(
449 "default",
450 &[("transitionProperty-k1ekBW", "transitionProperty-x17389it")],
451 )],
452 &[(
453 "default",
454 &[(
455 "transitionProperty-x17389it",
456 (
457 ".transitionProperty-x17389it{transition-property:--foo}",
458 3000.0,
459 ),
460 )],
461 )],
462 &[(
463 "default",
464 &[("transitionProperty-x17389it", &["transitionProperty"])],
465 )],
466 );
467
468 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
469 assert_eq!(injected_styles, expected_injected_styles);
470 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
471 }
472
473 #[test]
474 fn will_change_dash_dash_foo() {
475 let object = style_object_factory(&[("default", &[("willChange", "--foo")])]);
476
477 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
478
479 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
480 exprected_result_factory(
481 &[("default", &[("willChange-k6sLGO", "willChange-x1lxaxzv")])],
482 &[(
483 "default",
484 &[(
485 "willChange-x1lxaxzv",
486 (".willChange-x1lxaxzv{will-change:--foo}", 3000.0),
487 )],
488 )],
489 &[("default", &[("willChange-x1lxaxzv", &["willChange"])])],
490 );
491
492 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
493 assert_eq!(injected_styles, expected_injected_styles);
494 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
495 }
496
497 #[test]
498 fn transition_property_opacity_margin_top() {
499 let camel_case_object =
500 style_object_factory(&[("default", &[("transitionProperty", "opacity, marginTop")])]);
501 let kebab_case_object =
502 style_object_factory(&[("default", &[("transitionProperty", "opacity, margin-top")])]);
503
504 let camel_case = stylex_create(camel_case_object);
505 let kebab_case = stylex_create(kebab_case_object);
506
507 assert_eq!(camel_case, kebab_case);
508
509 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = camel_case;
510
511 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
512 exprected_result_factory(
513 &[(
514 "default",
515 &[("transitionProperty-k1ekBW", "transitionProperty-x95ccmk")],
516 )],
517 &[(
518 "default",
519 &[(
520 "transitionProperty-x95ccmk",
521 (
522 ".transitionProperty-x95ccmk{transition-property:opacity,margin-top}",
523 3000.0,
524 ),
525 )],
526 )],
527 &[(
528 "default",
529 &[("transitionProperty-x95ccmk", &["transitionProperty"])],
530 )],
531 );
532
533 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
534 assert_eq!(injected_styles, expected_injected_styles);
535 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
536 }
537
538 #[test]
539 fn padding_shorthand() {
540 let object = style_object_factory(&[(
541 "short",
542 &[
543 (
544 "padding",
545 "calc((100% - 50px) * 0.5) var(--rightpadding, 20px)",
546 ),
547 ("paddingTop", "0"),
548 ],
549 )]);
550
551 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
552
553 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
554 exprected_result_factory(
555 &[(
556 "short",
557 &[
558 ("padding-kmVPX3", "padding-x1lmef92"),
559 ("paddingTop-kLKAdn", "paddingTop-xexx8yu"),
560 ],
561 )],
562 &[(
563 "default",
564 &[
565 (
566 "padding-x1lmef92",
567 (
568 ".padding-x1lmef92{padding:calc((100% - 50px) * .5) var(--rightpadding,20px)}",
569 1000.0,
570 ),
571 ),
572 (
573 "paddingTop-xexx8yu",
574 (".paddingTop-xexx8yu{padding-top:0}", 4000.0),
575 ),
576 ],
577 )],
578 &[(
579 "short",
580 &[
581 ("padding-x1lmef92", &["padding"]),
582 ("paddingTop-xexx8yu", &["paddingTop"]),
583 ],
584 )],
585 );
586
587 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
588 assert_eq!(injected_styles, expected_injected_styles);
589 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
590 }
591
592 #[test]
593 fn transforms_style_object_with_custom_property() {
594 let object = style_object_factory(&[("default", &[("--background-color", "red")])]);
595
596 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
597
598 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
599 exprected_result_factory(
600 &[(
601 "default",
602 &[("--background-color", "--background-color-xgau0yw")],
603 )],
604 &[(
605 "default",
606 &[(
607 "--background-color-xgau0yw",
608 (".--background-color-xgau0yw{--background-color:red}", 1.0),
609 )],
610 )],
611 &[(
612 "default",
613 &[("--background-color-xgau0yw", &["--background-color"])],
614 )],
615 );
616
617 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
618 assert_eq!(injected_styles, expected_injected_styles);
619 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
620 }
621
622 #[test]
623 fn transforms_style_object_with_custom_property_as_value() {
624 let object =
625 style_object_factory(&[("default", &[("--final-color", "var(--background-color)")])]);
626
627 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
628
629 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
630 exprected_result_factory(
631 &[("default", &[("--final-color", "--final-color-x13tgbkp")])],
632 &[(
633 "default",
634 &[(
635 "--final-color-x13tgbkp",
636 (
637 ".--final-color-x13tgbkp{--final-color:var(--background-color)}",
638 1.0,
639 ),
640 )],
641 )],
642 &[("default", &[("--final-color-x13tgbkp", &["--final-color"])])],
643 );
644
645 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
646 assert_eq!(injected_styles, expected_injected_styles);
647 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
648 }
649
650 #[test]
651 fn transforms_multiple_namespaces() {
652 let object = style_object_factory(&[
653 ("default", &[("backgroundColor", "red")]),
654 ("default2", &[("color", "blue")]),
655 ]);
656
657 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
658
659 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
660 exprected_result_factory(
661 &[
662 (
663 "default",
664 &[("backgroundColor-kWkggS", "backgroundColor-xrkmrrc")],
665 ),
666 ("default2", &[("color-kMwMTN", "color-xju2f9n")]),
667 ],
668 &[
669 (
670 "default",
671 &[("color-xju2f9n", (".color-xju2f9n{color:blue}", 3000.0))],
672 ),
673 (
674 "backgroundColor-xrkmrrc",
675 &[(
676 "backgroundColor-xrkmrrc",
677 (".backgroundColor-xrkmrrc{background-color:red}", 3000.0),
678 )],
679 ),
680 ],
681 &[
682 (
683 "default",
684 &[("backgroundColor-xrkmrrc", &["backgroundColor"])],
685 ),
686 ("default2", &[("color-xju2f9n", &["color"])]),
687 ],
688 );
689
690 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
691 assert_eq!(injected_styles, expected_injected_styles);
692 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
693 }
694
695 #[test]
696 fn does_not_transform_attr_value() {
697 let object = style_object_factory(&[("default", &[("content", "attr(some-attribute)")])]);
698
699 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
700
701 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
702 exprected_result_factory(
703 &[("default", &[("content-kah6P1", "content-xd71okc")])],
704 &[(
705 "default",
706 &[(
707 "content-xd71okc",
708 (".content-xd71okc{content:attr(some-attribute)}", 3000.0),
709 )],
710 )],
711 &[("default", &[("content-xd71okc", &["content"])])],
712 );
713
714 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
715 assert_eq!(injected_styles, expected_injected_styles);
716 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
717 }
718
719 #[test]
720 fn does_not_add_units_to_variable_value() {
721 let object = style_object_factory(&[("default", &[("--foo", "500")])]);
722
723 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
724
725 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
726 exprected_result_factory(
727 &[("default", &[("--foo", "--foo-xwzgxvi")])],
728 &[(
729 "default",
730 &[("--foo-xwzgxvi", (".--foo-xwzgxvi{--foo:500}", 1.0))],
731 )],
732 &[("default", &[("--foo-xwzgxvi", &["--foo"])])],
733 );
734
735 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
736 assert_eq!(injected_styles, expected_injected_styles);
737 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
738 }
739
740 #[test]
741 fn transforms_nested_pseudo_class_to_css() {
742 let object = style_nested_object_factory(&[(
743 "default",
744 &[(":hover", &[("backgroundColor", "red"), ("color", "blue")])],
745 )]);
746
747 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
748
749 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
750 exprected_result_factory(
751 &[(
752 "default",
753 &[
754 (":hover_backgroundColor-kGzVvX", "backgroundColor-x1gykpug"),
755 (":hover_color-kDPRdz", "color-x17z2mba"),
756 ],
757 )],
758 &[(
759 "default",
760 &[
761 (
762 "backgroundColor-x1gykpug",
763 (
764 ".backgroundColor-x1gykpug:hover{background-color:red}",
765 3130.0,
766 ),
767 ),
768 (
769 "color-x17z2mba",
770 (".color-x17z2mba:hover{color:blue}", 3130.0),
771 ),
772 ],
773 )],
774 &[(
775 "default",
776 &[
777 ("backgroundColor-x1gykpug", &[":hover", "backgroundColor"]),
778 ("color-x17z2mba", &[":hover", "color"]),
779 ],
780 )],
781 );
782
783 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
784 assert_eq!(injected_styles, expected_injected_styles);
785 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
786 }
787
788 #[test]
789 fn transforms_nested_pseudo_classes_within_pseudo_elements() {
790 let object = style_multiple_depth_nested_object_factory(&[(
791 "default",
792 &[(
793 "::before",
794 &[(
795 "color",
796 &DepthProps::Two(&[
797 ("default", &StringOrNull::String("red")),
798 (":hover", &StringOrNull::String("blue")),
799 ]),
800 )],
801 )],
802 )]);
803
804 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
805
806 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
807 exprected_result_factory(
808 &[(
809 "default",
810 &[("::before_color-kxBb7d", "color-x16oeupf color-xeb2lg0")],
811 )],
812 &[(
813 "default",
814 &[
815 (
816 "color-x16oeupf",
817 (".color-x16oeupf::before{color:red}", 8000.0),
818 ),
819 (
820 "color-xeb2lg0",
821 (".color-xeb2lg0::before:hover{color:blue}", 8130.0),
822 ),
823 ],
824 )],
825 &[(
826 "default",
827 &[
828 ("color-x16oeupf", &["::before", "default", "color"]),
829 ("color-xeb2lg0", &["::before", ":hover", "color"]),
830 ],
831 )],
832 );
833
834 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
835 assert_eq!(injected_styles, expected_injected_styles);
836 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
837 }
838
839 #[test]
840 fn transforms_nested_legacy_pseudo_classes_within_pseudo_elements() {
841 let object = style_multiple_depth_nested_object_factory(&[(
842 "default",
843 &[(
844 "::before",
845 &[
846 ("color", &DepthProps::One("red")),
847 (
848 ":hover",
849 &DepthProps::Two(&[("color", &StringOrNull::String("blue"))]),
850 ),
851 ],
852 )],
853 )]);
854
855 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
856
857 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
858 exprected_result_factory(
859 &[(
860 "default",
861 &[
862 ("::before_:hover_color-kkC3X7", "color-xeb2lg0"),
863 ("::before_color-kxBb7d", "color-x16oeupf"),
864 ],
865 )],
866 &[(
867 "default",
868 &[
869 (
870 "color-x16oeupf",
871 (".color-x16oeupf::before{color:red}", 8000.0),
872 ),
873 (
874 "color-xeb2lg0",
875 (".color-xeb2lg0::before:hover{color:blue}", 8130.0),
876 ),
877 ],
878 )],
879 &[(
880 "default",
881 &[
882 ("color-x16oeupf", &["::before", "color"]),
883 ("color-xeb2lg0", &["::before", ":hover", "color"]),
884 ],
885 )],
886 );
887
888 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
889 assert_eq!(injected_styles, expected_injected_styles);
890 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
891 }
892
893 #[test]
894 fn transforms_nested_pseudo_element_within_legacy_pseudo_class() {
895 let object = style_multiple_depth_nested_object_factory(&[(
896 "default",
897 &[
898 ("::before", &[("color", &DepthProps::One("red"))]),
899 (
900 ":hover",
901 &[(
902 "::before",
903 &DepthProps::Three(&[(
904 "color",
905 &[
906 ("default", "blue"),
907 (":hover", "green"),
908 (":active", "yellow"),
909 ],
910 )]),
911 )],
912 ),
913 ],
914 )]);
915
916 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
917
918 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
919 exprected_result_factory(
920 &[(
921 "default",
922 &[
923 ("::before_color-kxBb7d", "color-x16oeupf"),
924 (
925 ":hover_::before_color-kFlxxK",
926 "color-xzzpreb color-x1gobd9t color-x1lvqgcc",
927 ),
928 ],
929 )],
930 &[(
931 "default",
932 &[
933 (
934 "color-x16oeupf",
935 (".color-x16oeupf::before{color:red}", 8000.0),
936 ),
937 (
938 "color-x1gobd9t",
939 (".color-x1gobd9t:hover::before:hover{color:green}", 8260.0),
940 ),
941 (
942 "color-x1lvqgcc",
943 (".color-x1lvqgcc:hover::before:active{color:yellow}", 8300.0),
944 ),
945 (
946 "color-xzzpreb",
947 (".color-xzzpreb:hover::before{color:blue}", 8130.0),
948 ),
949 ],
950 )],
951 &[(
952 "default",
953 &[
954 ("color-x16oeupf", &["::before", "color"]),
955 ("color-x1gobd9t", &[":hover", "::before", ":hover", "color"]),
956 (
957 "color-x1lvqgcc",
958 &[":hover", "::before", ":active", "color"],
959 ),
960 ("color-xzzpreb", &[":hover", "::before", "default", "color"]),
961 ],
962 )],
963 );
964
965 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
966 assert_eq!(injected_styles, expected_injected_styles);
967 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
968 }
969
970 #[test]
971 #[ignore]
972 fn transforms_nested_pseudo_classes_within_pseudo_elements_v2() {
973 let before_hover_object = style_multiple_depth_nested_object_factory(&[(
974 "default",
975 &[(
976 "::before",
977 &[(
978 "color",
979 &DepthProps::Two(&[
980 ("default", &StringOrNull::Null),
981 (":hover", &StringOrNull::String("blue")),
982 ]),
983 )],
984 )],
985 )]);
986
987 let hover_before_object = style_multiple_depth_nested_object_factory(&[(
988 "default",
989 &[(
990 ":hover",
991 &[(
992 "::before",
993 &DepthProps::Two(&[("color", &StringOrNull::String("blue"))]),
994 )],
995 )],
996 )]);
997
998 let (before_hover, _, _) = stylex_create(before_hover_object);
999 let (hover_before, _, _) = stylex_create(hover_before_object);
1000
1001 let before_hover_class = before_hover
1002 .get("default")
1003 .and_then(|a| a.get("::before_color"))
1004 .unwrap();
1005
1006 let hover_before_class = hover_before
1007 .get("default")
1008 .and_then(|a| a.get(":hover_::before_color"))
1009 .unwrap();
1010
1011 assert_eq!(
1012 before_hover_class,
1013 &Rc::new(FlatCompiledStylesValue::String("color-xeb2lg0".to_string()))
1014 );
1015
1016 assert_eq!(
1017 hover_before_class,
1018 &Rc::new(FlatCompiledStylesValue::String("color-xeb2lg0".to_string()))
1019 );
1020
1021 assert_ne!(before_hover_class, hover_before_class)
1022 }
1023
1024 #[test]
1025 fn transforms_array_values_as_fallbacks() {
1026 let object = style_array_object_factory(&[("default", &[("position", &["sticky", "fixed"])])]);
1027
1028 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
1029
1030 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
1031 exprected_result_factory(
1032 &[("default", &[("position-kVAEAm", "position-x1ruww2u")])],
1033 &[(
1034 "default",
1035 &[(
1036 "position-x1ruww2u",
1037 (".position-x1ruww2u{position:sticky;position:fixed}", 3000.0),
1038 )],
1039 )],
1040 &[("default", &[("position-x1ruww2u", &["position"])])],
1041 );
1042
1043 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
1044 assert_eq!(injected_styles, expected_injected_styles);
1045 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
1046 }
1047
1048 #[test]
1049 fn transforms_valid_shorthands() {
1050 let object = style_object_factory(&[(
1051 "default",
1052 &[
1053 ("overflow", "hidden"),
1054 ("borderStyle", "dashed"),
1055 ("borderWidth", "1"),
1056 ],
1057 )]);
1058
1059 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
1060
1061 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
1062 exprected_result_factory(
1063 &[(
1064 "default",
1065 &[
1066 ("borderStyle-ksu8eU", "borderStyle-xbsl7fq"),
1067 ("borderWidth-kMzoRj", "borderWidth-xmkeg23"),
1068 ("overflow-kVQacm", "overflow-xb3r6kr"),
1069 ],
1070 )],
1071 &[(
1072 "default",
1073 &[
1074 (
1075 "overflow-xb3r6kr",
1076 (".overflow-xb3r6kr{overflow:hidden}", 2000.0),
1077 ),
1078 (
1079 "borderStyle-xbsl7fq",
1080 (".borderStyle-xbsl7fq{border-style:dashed}", 2000.0),
1081 ),
1082 (
1083 "borderWidth-xmkeg23",
1084 (".borderWidth-xmkeg23{border-width:1px}", 2000.0),
1085 ),
1086 ],
1087 )],
1088 &[(
1089 "default",
1090 &[
1091 ("overflow-xb3r6kr", &["overflow"]),
1092 ("borderStyle-xbsl7fq", &["borderStyle"]),
1093 ("borderWidth-xmkeg23", &["borderWidth"]),
1094 ],
1095 )],
1096 );
1097
1098 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
1099 assert_eq!(injected_styles, expected_injected_styles);
1100 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
1101 }
1102
1103 #[test]
1104 fn transforms_media_queries() {
1105 let mut object = style_nested_object_factory(&[(
1106 "default",
1107 &[
1108 ("@media (min-width: 1000px)", &[("backgroundColor", "blue")]),
1109 (
1110 "@media (min-width: 2000px)",
1111 &[("backgroundColor", "purple")],
1112 ),
1113 ],
1114 )]);
1115
1116 let def = object.get_mut(&create_string_expr("default")).unwrap();
1117
1118 def.push(create_key_value_prop_ident(
1119 "backgroundColor",
1120 create_string_expr("red"),
1121 ));
1122
1123 let (resolved_namespaces, injected_styles, class_paths_in_namespace) = stylex_create(object);
1124
1125 let (expected_resolved_namespaces, expected_injected_styles, expected_class_paths_in_namespace) =
1126 exprected_result_factory(
1127 &[(
1128 "default",
1129 &[
1130 (
1131 "@media (min-width: 1000px)_backgroundColor-ksQ81T",
1132 "backgroundColor-xc445zv",
1133 ),
1134 (
1135 "@media (min-width: 2000px)_backgroundColor-kkpvmn",
1136 "backgroundColor-x1ssfqz5",
1137 ),
1138 ("backgroundColor-kWkggS", "backgroundColor-xrkmrrc"),
1139 ],
1140 )],
1141 &[(
1142 "default",
1143 &[
1144 (
1145 "backgroundColor-x1ssfqz5",
1146 (
1147 "@media (min-width: 2000px){.backgroundColor-x1ssfqz5.backgroundColor-x1ssfqz5{background-color:purple}}",
1148 3200.0,
1149 ),
1150 ),
1151 (
1152 "backgroundColor-xc445zv",
1153 (
1154 "@media (min-width: 1000px){.backgroundColor-xc445zv.backgroundColor-xc445zv{background-color:blue}}",
1155 3200.0,
1156 ),
1157 ),
1158 (
1159 "backgroundColor-xrkmrrc",
1160 (".backgroundColor-xrkmrrc{background-color:red}", 3000.0),
1161 ),
1162 ],
1163 )],
1164 &[(
1165 "default",
1166 &[
1167 (
1168 "backgroundColor-xc445zv",
1169 &["@media (min-width: 1000px)", "backgroundColor"],
1170 ),
1171 (
1172 "backgroundColor-x1ssfqz5",
1173 &["@media (min-width: 2000px)", "backgroundColor"],
1174 ),
1175 ("backgroundColor-xrkmrrc", &["backgroundColor"]),
1176 ],
1177 )],
1178 );
1179
1180 assert_eq!(resolved_namespaces, expected_resolved_namespaces);
1181 assert_eq!(injected_styles, expected_injected_styles);
1182 assert_eq!(class_paths_in_namespace, expected_class_paths_in_namespace)
1183 }
1184}