@@ -557,4 +557,258 @@ describe("Markdown file-like href behavior", () => {
557557 expect ( screen . getByText ( "Ready" ) ) . toBeTruthy ( ) ;
558558 } ) ;
559559
560+ it ( "renders inline dollar math when enabled" , ( ) => {
561+ const { container } = render (
562+ < Markdown
563+ value = "Euler identity: $e^{i\\pi}+1=0$"
564+ className = "markdown"
565+ enableMathRendering
566+ /> ,
567+ ) ;
568+
569+ expect ( container . querySelector ( ".katex" ) ) . toBeTruthy ( ) ;
570+ expect ( container . textContent ) . toContain ( "Euler identity" ) ;
571+ } ) ;
572+
573+ it ( "renders block math when enabled" , ( ) => {
574+ const { container } = render (
575+ < Markdown
576+ value = { [ "$$" , "\\nabla \\cdot \\mathbf{E} = \\frac{\\rho}{\\varepsilon_0}" , "$$" ] . join (
577+ "\n" ,
578+ ) }
579+ className = "markdown"
580+ enableMathRendering
581+ /> ,
582+ ) ;
583+
584+ expect ( container . querySelector ( ".katex-display" ) ) . toBeTruthy ( ) ;
585+ } ) ;
586+
587+ it ( "supports \\(inline\\) and \\[block\\] LaTeX delimiters when enabled" , ( ) => {
588+ const { container } = render (
589+ < Markdown
590+ value = { [
591+ "Inline: \\(x^2 + y^2\\)" ,
592+ "" ,
593+ "\\[" ,
594+ "\\int_0^1 x^2\\,dx = \\frac{1}{3}" ,
595+ "\\]" ,
596+ ] . join ( "\n" ) }
597+ className = "markdown"
598+ enableMathRendering
599+ /> ,
600+ ) ;
601+
602+ expect ( container . querySelectorAll ( ".katex" ) . length ) . toBeGreaterThanOrEqual ( 2 ) ;
603+ expect ( container . querySelector ( ".katex-display" ) ) . toBeTruthy ( ) ;
604+ } ) ;
605+
606+ it ( "does not render math inside fenced code blocks" , ( ) => {
607+ const { container } = render (
608+ < Markdown
609+ value = { [ "```text" , "$e^{i\\pi}+1=0$" , "\\(x^2\\)" , "```" ] . join ( "\n" ) }
610+ className = "markdown"
611+ enableMathRendering
612+ /> ,
613+ ) ;
614+
615+ expect ( container . querySelector ( ".katex" ) ) . toBeNull ( ) ;
616+ expect ( container . textContent ) . toContain ( "$e^{i\\pi}+1=0$" ) ;
617+ expect ( container . textContent ) . toContain ( "\\(x^2\\)" ) ;
618+ } ) ;
619+
620+ it ( "does not render math inside container-prefixed fenced code blocks" , ( ) => {
621+ const { container } = render (
622+ < Markdown
623+ value = { [
624+ "> ```text" ,
625+ "> \\(x^2\\)" ,
626+ "> \\[x+y\\]" ,
627+ "> ```" ,
628+ "" ,
629+ "Outside: \\(z^2\\)" ,
630+ ] . join ( "\n" ) }
631+ className = "markdown"
632+ enableMathRendering
633+ /> ,
634+ ) ;
635+
636+ expect ( container . querySelectorAll ( ".katex" ) . length ) . toBe ( 1 ) ;
637+ expect ( container . textContent ) . toContain ( "\\(x^2\\)" ) ;
638+ expect ( container . textContent ) . toContain ( "\\[x+y\\]" ) ;
639+ } ) ;
640+
641+ it ( "does not render math inside indented code blocks" , ( ) => {
642+ const { container } = render (
643+ < Markdown
644+ value = { [
645+ " \\(x^2\\)" ,
646+ " \\[" ,
647+ " x+y" ,
648+ " \\]" ,
649+ "" ,
650+ "Outside: \\(z^2\\)" ,
651+ ] . join ( "\n" ) }
652+ className = "markdown"
653+ enableMathRendering
654+ /> ,
655+ ) ;
656+
657+ expect ( container . querySelectorAll ( ".katex" ) . length ) . toBe ( 1 ) ;
658+ expect ( container . textContent ) . toContain ( "\\(x^2\\)" ) ;
659+ expect ( container . textContent ) . toContain ( "\\[" ) ;
660+ expect ( container . textContent ) . toContain ( "\\]" ) ;
661+ } ) ;
662+
663+ it ( "does not rewrite escaped \\(inline\\) delimiters" , ( ) => {
664+ const { container } = render (
665+ < Markdown
666+ value = { [ "Literal: \\\\(x\\\\)" , "Outside: \\(z^2\\)" ] . join ( "\n" ) }
667+ className = "markdown"
668+ enableMathRendering
669+ /> ,
670+ ) ;
671+
672+ expect ( container . querySelectorAll ( ".katex" ) . length ) . toBe ( 1 ) ;
673+ expect ( container . textContent ) . toContain ( "\\(x\\)" ) ;
674+ } ) ;
675+
676+ it ( "renders \\(inline\\) math when adjacent to percent and slash punctuation" , ( ) => {
677+ const { container } = render (
678+ < Markdown
679+ value = { [
680+ "Success: \\(p\\)%" ,
681+ "Ratio: \\(a\\)/\\(b\\)" ,
682+ ] . join ( "\n" ) }
683+ className = "markdown"
684+ enableMathRendering
685+ /> ,
686+ ) ;
687+
688+ expect ( container . querySelectorAll ( ".katex" ) . length ) . toBe ( 3 ) ;
689+ expect ( container . textContent ) . toContain ( "Success:" ) ;
690+ expect ( container . textContent ) . toContain ( "Ratio:" ) ;
691+ } ) ;
692+
693+ it ( "does not render math inside blockquote-indented code blocks" , ( ) => {
694+ const { container } = render (
695+ < Markdown
696+ value = { [
697+ "> \\(x^2\\)" ,
698+ "> \\[x+y\\]" ,
699+ "" ,
700+ "Outside: \\(z^2\\)" ,
701+ ] . join ( "\n" ) }
702+ className = "markdown"
703+ enableMathRendering
704+ /> ,
705+ ) ;
706+
707+ expect ( container . querySelectorAll ( ".katex" ) . length ) . toBe ( 1 ) ;
708+ expect ( container . textContent ) . toContain ( "\\(x^2\\)" ) ;
709+ expect ( container . textContent ) . toContain ( "\\[x+y\\]" ) ;
710+ } ) ;
711+
712+ it ( "keeps math-like delimiters literal inside long fences with nested shorter fences" , ( ) => {
713+ const { container } = render (
714+ < Markdown
715+ value = { [
716+ "````text" ,
717+ "inner fence marker:" ,
718+ "```" ,
719+ "\\(x^2\\)" ,
720+ "\\[x+y\\]" ,
721+ "````" ,
722+ "Outside: \\(z^2\\)" ,
723+ ] . join ( "\n" ) }
724+ className = "markdown"
725+ enableMathRendering
726+ /> ,
727+ ) ;
728+
729+ expect ( container . querySelector ( ".katex" ) ) . toBeTruthy ( ) ;
730+ expect ( container . textContent ) . toContain ( "\\(x^2\\)" ) ;
731+ expect ( container . textContent ) . toContain ( "\\[x+y\\]" ) ;
732+ } ) ;
733+
734+ it ( "preserves nested list and blockquote structure for \\\\[...\\\\] block delimiters" , ( ) => {
735+ const { container } = render (
736+ < Markdown
737+ value = { [
738+ "- List item with block math:" ,
739+ " \\[" ,
740+ " x^2 + y^2 = r^2" ,
741+ " \\]" ,
742+ "" ,
743+ "> \\[" ,
744+ "> E = mc^2" ,
745+ "> \\]" ,
746+ ] . join ( "\n" ) }
747+ className = "markdown"
748+ enableMathRendering
749+ /> ,
750+ ) ;
751+
752+ expect ( container . querySelector ( "li .katex-display" ) ) . toBeTruthy ( ) ;
753+ expect ( container . querySelector ( "blockquote .katex-display" ) ) . toBeTruthy ( ) ;
754+ } ) ;
755+
756+ it ( "does not rewrite escaped latex delimiters in link destinations" , ( ) => {
757+ render (
758+ < Markdown
759+ value = "[wiki](https://en.wikipedia.org/wiki/Function_\\(mathematics\\))"
760+ className = "markdown"
761+ enableMathRendering
762+ /> ,
763+ ) ;
764+
765+ const link = screen . getByText ( "wiki" ) . closest ( "a" ) ;
766+ expect ( link ?. getAttribute ( "href" ) ) . toBe (
767+ "https://en.wikipedia.org/wiki/Function_%5C(mathematics%5C)" ,
768+ ) ;
769+ } ) ;
770+
771+ it ( "does not rewrite escaped latex delimiters in plain URL literals and references" , ( ) => {
772+ const { container } = render (
773+ < Markdown
774+ value = { [
775+ "https://example.com/\\(foo\\)" ,
776+ "[ref]: https://example.com/\\(bar\\)" ,
777+ ] . join ( "\n" ) }
778+ className = "markdown"
779+ enableMathRendering
780+ /> ,
781+ ) ;
782+
783+ const plainUrlLink = screen . getByText ( "https://example.com/\\(foo\\)" ) . closest ( "a" ) ;
784+ expect ( plainUrlLink ?. getAttribute ( "href" ) ) . toBe ( "https://example.com/%5C(foo%5C)" ) ;
785+ const referenceUrlLink = screen . getByText ( "https://example.com/\\(bar\\)" ) . closest ( "a" ) ;
786+ expect ( referenceUrlLink ?. getAttribute ( "href" ) ) . toBe ( "https://example.com/%5C(bar%5C)" ) ;
787+ expect ( container . textContent ) . toContain ( "[ref]:" ) ;
788+ } ) ;
789+
790+ it ( "matches blockquote block-math closer when quote spacing differs" , ( ) => {
791+ const { container } = render (
792+ < Markdown
793+ value = { [ "> \\[" , "> E = mc^2" , ">\\]" ] . join ( "\n" ) }
794+ className = "markdown"
795+ enableMathRendering
796+ /> ,
797+ ) ;
798+
799+ expect ( container . querySelector ( "blockquote .katex-display" ) ) . toBeTruthy ( ) ;
800+ } ) ;
801+
802+ it ( "matches blockquote block-math closer when quote indentation differs" , ( ) => {
803+ const { container } = render (
804+ < Markdown
805+ value = { [ " > \\[" , "> E = mc^2" , ">\\]" ] . join ( "\n" ) }
806+ className = "markdown"
807+ enableMathRendering
808+ /> ,
809+ ) ;
810+
811+ expect ( container . querySelector ( "blockquote .katex-display" ) ) . toBeTruthy ( ) ;
812+ } ) ;
813+
560814} ) ;
0 commit comments