Skip to main content

stylex_transform/shared/transformers/tests/
stylex_create_test.rs

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    // Four(&'a [(&'a str, &'a [(&'a str, &'a [(&'a str, &'a str)])])]),
81  }
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                    // DepthProps::Four(arr) => create_nested_object_prop(
134                    //   key,
135                    //   arr
136                    //     .iter()
137                    //     .map(|(key, values)| {
138                    //       create_nested_object_prop(
139                    //         key,
140                    //         values
141                    //           .iter()
142                    //           .map(|(key, values)| {
143                    //             create_nested_object_prop(
144                    //               key,
145                    //               values
146                    //                 .iter()
147                    //                 .map(|(key, value)| create_string_key_value_prop(key, value))
148                    //                 .collect(),
149                    //             )
150                    //           })
151                    //           .collect(),
152                    //       )
153                    //     })
154                    //     .collect(),
155                    // ),
156                  })
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}