@@ -16881,4 +16881,126 @@ export const A = () => <Box _hover={hoverStyle} bg="red" />;
1688116881 .unwrap()
1688216882 ));
1688316883 }
16884+
16885+ // Coverage for extract_style_from_expression.rs:206 — the
16886+ // `Expression::BinaryExpression | StaticMemberExpression | CallExpression`
16887+ // arm. Both internal branches must be exercised in a single, dedicated
16888+ // test so coverage tooling can attribute hits to this exact line:
16889+ //
16890+ // 207: `if let Some(name) = name { dynamic_style(...) }` (Some path)
16891+ // 211: `else { ExtractResult::default() }` (None path,
16892+ // reached only via `_xxx={...}` selector recursion)
16893+ //
16894+ // Each variant (binary / static-member / call) is asserted on its own so
16895+ // a regression in any single pattern fails loudly instead of being hidden
16896+ // behind a multi-snapshot test.
16897+ #[test]
16898+ #[serial]
16899+ fn extract_dynamic_style_props_binary_member_call_arm() {
16900+ // ── Some(name) branch — line 207 ────────────────────────────────
16901+ // BinaryExpression on a real prop name
16902+ reset_class_map();
16903+ reset_file_map();
16904+ assert_debug_snapshot!(ToBTreeSet::from(
16905+ extract(
16906+ "test.tsx",
16907+ r#"import { Box } from "@devup-ui/core";
16908+ <Box bg={a + b} />;
16909+ "#,
16910+ ExtractOption {
16911+ package: "@devup-ui/core".to_string(),
16912+ css_dir: "@devup-ui/core".to_string(),
16913+ single_css: true,
16914+ import_main_css: false,
16915+ import_aliases: HashMap::new()
16916+ }
16917+ )
16918+ .unwrap()
16919+ ));
16920+
16921+ // StaticMemberExpression on a real prop name
16922+ reset_class_map();
16923+ reset_file_map();
16924+ assert_debug_snapshot!(ToBTreeSet::from(
16925+ extract(
16926+ "test.tsx",
16927+ r#"import { Box } from "@devup-ui/core";
16928+ <Box color={theme.color} />;
16929+ "#,
16930+ ExtractOption {
16931+ package: "@devup-ui/core".to_string(),
16932+ css_dir: "@devup-ui/core".to_string(),
16933+ single_css: true,
16934+ import_main_css: false,
16935+ import_aliases: HashMap::new()
16936+ }
16937+ )
16938+ .unwrap()
16939+ ));
16940+
16941+ // CallExpression on a real prop name
16942+ reset_class_map();
16943+ reset_file_map();
16944+ assert_debug_snapshot!(ToBTreeSet::from(
16945+ extract(
16946+ "test.tsx",
16947+ r#"import { Box } from "@devup-ui/core";
16948+ <Box w={getWidth()} />;
16949+ "#,
16950+ ExtractOption {
16951+ package: "@devup-ui/core".to_string(),
16952+ css_dir: "@devup-ui/core".to_string(),
16953+ single_css: true,
16954+ import_main_css: false,
16955+ import_aliases: HashMap::new()
16956+ }
16957+ )
16958+ .unwrap()
16959+ ));
16960+
16961+ // ── None branch (line 211) — pseudo-selector recursion drops `name` ─
16962+ // Each of these enters extract_style_from_expression with
16963+ // `name = Some("_hover")`, hits the `strip_prefix("_")` recursion that
16964+ // calls back with `name = None`, and lands in the else arm of line
16965+ // 206 → 211. Without the fix this used to panic; the assertion is
16966+ // simply that extract() returns Ok with no styles for the dropped
16967+ // pseudo-selector attribute.
16968+ for src in [
16969+ // BinaryExpression
16970+ r#"import {Box} from '@devup-ui/react'
16971+ declare const a: any; declare const b: any;
16972+ export const A = () => <Box _hover={a + b} />;
16973+ "#,
16974+ // StaticMemberExpression
16975+ r#"import {Box} from '@devup-ui/react'
16976+ declare const t: { hover: object };
16977+ export const A = () => <Box _hover={t.hover} />;
16978+ "#,
16979+ // CallExpression
16980+ r#"import {Box} from '@devup-ui/react'
16981+ declare const fn: () => object;
16982+ export const A = () => <Box _hover={fn()} />;
16983+ "#,
16984+ ] {
16985+ reset_class_map();
16986+ reset_file_map();
16987+ let out = extract(
16988+ "test.tsx",
16989+ src,
16990+ ExtractOption {
16991+ package: "@devup-ui/react".to_string(),
16992+ css_dir: "@devup-ui/react".to_string(),
16993+ single_css: true,
16994+ import_main_css: false,
16995+ import_aliases: HashMap::new(),
16996+ },
16997+ )
16998+ .expect("graceful extract for pseudo-selector with non-literal value");
16999+ assert!(
17000+ out.styles.is_empty(),
17001+ "expected no extracted styles for pseudo-selector dropped attr, got: {:#?}",
17002+ out.styles
17003+ );
17004+ }
17005+ }
1688417006}
0 commit comments