use crate::{
TransformClassNameRewriteV0, TransformExecutionContextV0,
execute_transform_passes_on_source_with_dialect_and_context,
};
use omena_parser::StyleDialect;
use omena_transform_cst::TransformPassKind;
#[test]
fn execution_runtime_rewrites_css_module_class_names_with_identity_map() {
let source = r#".button { composes: base utility global(reset); color: red; } .base, .utility { color: blue; } .button:hover { color: green; } .button :global(.external) { color: purple; } :global(.root) .button { color: orange; } :global(.standalone) { color: teal; } :global { .global-block { color: silver; } } :local(.button) { color: navy; } :local { .button { color: maroon; } } @media (min-width: 1px) { .button { color: black; } }"#;
let context = TransformExecutionContextV0 {
class_name_rewrites: vec![
TransformClassNameRewriteV0 {
original_name: "button".to_string(),
rewritten_name: "_button_abc123".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "base".to_string(),
rewritten_name: "_base_def456".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "utility".to_string(),
rewritten_name: "_utility_ghi789".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "external".to_string(),
rewritten_name: "_external_global".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "root".to_string(),
rewritten_name: "_root_global".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "global-block".to_string(),
rewritten_name: "_global_block_should_not_apply".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "reset".to_string(),
rewritten_name: "_reset_should_not_apply".to_string(),
},
],
..TransformExecutionContextV0::default()
};
let execution = execute_transform_passes_on_source_with_dialect_and_context(
source,
StyleDialect::Css,
&[
TransformPassKind::HashCssModuleClassNames,
TransformPassKind::PrintCss,
],
&context,
);
assert_eq!(execution.mutation_count, 14);
assert_eq!(
execution.output_css,
r#"._button_abc123{ composes: _base_def456 _utility_ghi789 global(reset); color: red; } ._base_def456, ._utility_ghi789{ color: blue; } ._button_abc123:hover{ color: green; } ._button_abc123 .external{ color: purple; } .root ._button_abc123{ color: orange; } .standalone{ color: teal; } .global-block { color: silver; } ._button_abc123{ color: navy; } ._button_abc123{ color: maroon; } @media (min-width: 1px) { ._button_abc123{ color: black; } }"#
);
assert_eq!(
execution.executed_pass_ids,
vec!["css-modules-class-hashing", "print-css"]
);
}
#[test]
fn execution_runtime_preserves_global_composes_during_css_module_class_hashing() {
let source = r#".button { composes: global(reset); color: red; }"#;
let context = TransformExecutionContextV0 {
class_name_rewrites: vec![
TransformClassNameRewriteV0 {
original_name: "button".to_string(),
rewritten_name: "_button_x".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "reset".to_string(),
rewritten_name: "_reset_should_not_apply".to_string(),
},
],
..TransformExecutionContextV0::default()
};
let execution = execute_transform_passes_on_source_with_dialect_and_context(
source,
StyleDialect::Css,
&[
TransformPassKind::HashCssModuleClassNames,
TransformPassKind::PrintCss,
],
&context,
);
assert_eq!(execution.mutation_count, 1);
assert_eq!(
execution.output_css,
r#"._button_x{ composes: global(reset); color: red; }"#
);
assert_eq!(
execution.executed_pass_ids,
vec!["css-modules-class-hashing", "print-css"]
);
}
#[test]
fn execution_runtime_rewrites_css_module_scope_prelude_class_names() {
let source = r#"@scope (.card) to (:global(.footer)) { .title { color: red; } }"#;
let context = TransformExecutionContextV0 {
class_name_rewrites: vec![
TransformClassNameRewriteV0 {
original_name: "card".to_string(),
rewritten_name: "_card_x".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "footer".to_string(),
rewritten_name: "_footer_should_not_apply".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "title".to_string(),
rewritten_name: "_title_z".to_string(),
},
],
..TransformExecutionContextV0::default()
};
let execution = execute_transform_passes_on_source_with_dialect_and_context(
source,
StyleDialect::Css,
&[
TransformPassKind::HashCssModuleClassNames,
TransformPassKind::PrintCss,
],
&context,
);
assert_eq!(execution.mutation_count, 2);
assert_eq!(
execution.output_css,
r#"@scope (._card_x) to (.footer) { ._title_z{ color: red; } }"#
);
assert_eq!(
execution.executed_pass_ids,
vec!["css-modules-class-hashing", "print-css"]
);
}
#[test]
fn execution_runtime_rewrites_css_module_supports_selector_class_names() {
let source = r#"@supports selector(.card:has(:global(.footer), .title)) { .item { color: red; } } @supports (background: paint(.card)) { .paint { color: blue; } }"#;
let context = TransformExecutionContextV0 {
class_name_rewrites: vec![
TransformClassNameRewriteV0 {
original_name: "card".to_string(),
rewritten_name: "_card_x".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "footer".to_string(),
rewritten_name: "_footer_should_not_apply".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "title".to_string(),
rewritten_name: "_title_z".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "item".to_string(),
rewritten_name: "_item_q".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "paint".to_string(),
rewritten_name: "_paint_p".to_string(),
},
],
..TransformExecutionContextV0::default()
};
let execution = execute_transform_passes_on_source_with_dialect_and_context(
source,
StyleDialect::Css,
&[
TransformPassKind::HashCssModuleClassNames,
TransformPassKind::PrintCss,
],
&context,
);
assert_eq!(execution.mutation_count, 3);
assert_eq!(
execution.output_css,
r#"@supports selector(._card_x:has(.footer, ._title_z)) { ._item_q{ color: red; } } @supports (background: paint(.card)) { ._paint_p{ color: blue; } }"#
);
assert_eq!(
execution.executed_pass_ids,
vec!["css-modules-class-hashing", "print-css"]
);
}
#[test]
fn execution_runtime_hashes_escaped_css_module_class_selectors() {
let source = r#".foo\:bar { color: red; } :local(.foo\:bar) { color: blue; } :global(.foo\:bar) .foo\:bar { color: green; }"#;
let context = TransformExecutionContextV0 {
class_name_rewrites: vec![TransformClassNameRewriteV0 {
original_name: "foo:bar".to_string(),
rewritten_name: "_foo_bar_0".to_string(),
}],
..TransformExecutionContextV0::default()
};
let execution = execute_transform_passes_on_source_with_dialect_and_context(
source,
StyleDialect::Css,
&[
TransformPassKind::HashCssModuleClassNames,
TransformPassKind::PrintCss,
],
&context,
);
assert_eq!(execution.mutation_count, 3);
assert_eq!(
execution.output_css,
r#"._foo_bar_0{ color: red; } ._foo_bar_0{ color: blue; } .foo\:bar ._foo_bar_0{ color: green; }"#
);
assert_eq!(
execution.executed_pass_ids,
vec!["css-modules-class-hashing", "print-css"]
);
}
#[test]
fn execution_runtime_hashes_nested_css_module_selectors_after_unwrap() {
let source = r#".item { color: red; &--primary { color: blue; } & .body { color: green; } }"#;
let context = TransformExecutionContextV0 {
class_name_rewrites: vec![
TransformClassNameRewriteV0 {
original_name: "item".to_string(),
rewritten_name: "_item_0".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "item--primary".to_string(),
rewritten_name: "_item--primary_1".to_string(),
},
TransformClassNameRewriteV0 {
original_name: "body".to_string(),
rewritten_name: "_body_2".to_string(),
},
],
..TransformExecutionContextV0::default()
};
let execution = execute_transform_passes_on_source_with_dialect_and_context(
source,
StyleDialect::Scss,
&[
TransformPassKind::HashCssModuleClassNames,
TransformPassKind::NestingUnwrap,
TransformPassKind::PrintCss,
],
&context,
);
assert_eq!(
execution.ordered_pass_ids,
vec!["nesting-unwrap", "css-modules-class-hashing", "print-css"]
);
assert!(execution.output_css.contains("._item_0{ color: red; }"));
assert!(
execution
.output_css
.contains("._item--primary_1{ color: blue; }")
);
assert!(
execution
.output_css
.contains("._item_0 ._body_2{ color: green; }")
);
assert_eq!(
execution.executed_pass_ids,
vec!["nesting-unwrap", "css-modules-class-hashing", "print-css"]
);
}