# frozen_string_literal: true require 'spec_helper' RSpec.describe Banzai::Filter::MathFilter do using RSpec::Parameterized::TableSyntax include FilterSpecHelper shared_examples 'inline math' do it 'removes surrounding dollar signs and adds class code, math and js-render-math' do doc = filter(text) expected = result_template.gsub('', '') expected.gsub!('', '') expect(doc.to_s).to eq expected end end shared_examples 'display math' do let_it_be(:template_prefix_with_pre) { '
' }
    let_it_be(:template_prefix_with_code) { '' }
    let(:use_pre_tags) { false }

    it 'removes surrounding dollar signs and adds class code, math and js-render-math' do
      doc = filter(text)

      template_prefix = use_pre_tags ? template_prefix_with_pre : template_prefix_with_code
      template_suffix = "#{'
' if use_pre_tags}" expected = result_template.gsub('', template_prefix) expected.gsub!('', template_suffix) expect(doc.to_s).to eq expected end end describe 'inline math using $...$ syntax' do context 'with valid syntax' do where(:text, :result_template) do '$2+2$' | '2+2' '$22+1$ and $22 + a^2$' | '22+1 and 22 + a^2' '$22 and $2+2$' | '$22 and 2+2' '$2+2$ $22 and flightjs/Flight$22 $2+2$' | '2+2 $22 and flightjs/Flight$22 2+2' '$1/2$ <b>test</b>' | '1/2 <b>test</b>' '$a!$' | 'a!' '$x$' | 'x' end with_them do it_behaves_like 'inline math' end end it 'does not handle dollar literals properly' do doc = filter('$20+30\$$') expected = '20+30\\$' expect(doc.to_s).to eq expected end end describe 'inline math using $`...`$ syntax' do context 'with valid syntax' do where(:text, :result_template) do '$2+2$' | '2+2' '$22+1$ and $22 + a^2$' | '22+1 and 22 + a^2' '$22 and $2+2$' | '$22 and 2+2' '$2+2$ $22 and flightjs/Flight$22 $2+2$' | '2+2 $22 and flightjs/Flight$22 2+2' 'test $$2+2$$ test' | 'test $2+2$ test' end with_them do it_behaves_like 'inline math' end end end describe 'inline display math using $$...$$ syntax' do context 'with valid syntax' do where(:text, :result_template) do '$$2+2$$' | '2+2' '$$ 2+2 $$' | '2+2' '$$22+1$$ and $$22 + a^2$$' | '22+1 and 22 + a^2' '$22 and $$2+2$$' | '$22 and 2+2' '$$2+2$$ $22 and flightjs/Flight$22 $$2+2$$' | '2+2 $22 and flightjs/Flight$22 2+2' 'flightjs/Flight$22 and $$a^2 + b^2 = c^2$$' | 'flightjs/Flight$22 and a^2 + b^2 = c^2' '$$a!$$' | 'a!' '$$x$$' | 'x' '$$20,000 and $$30,000' | '20,000 and30,000' end with_them do it_behaves_like 'display math' end end end describe 'block display math using $$\n...\n$$ syntax' do context 'with valid syntax' do where(:text, :result_template) do "$$\n2+2\n$$" | "2+2" end with_them do it_behaves_like 'display math' do let(:use_pre_tags) { true } end end end end describe 'display math using ```math...``` syntax' do it 'adds data-math-style display attribute to display math' do doc = filter('
2+2
') pre = doc.xpath('descendant-or-self::pre').first expect(pre['data-math-style']).to eq 'display' end it 'adds js-render-math class to display math' do doc = filter('
2+2
') pre = doc.xpath('descendant-or-self::pre').first expect(pre[:class]).to include("js-render-math") end it 'ignores code blocks that are not math' do input = '
2+2
' doc = filter(input) expect(doc.to_s).to eq input end it 'requires the pre to contain both code and math' do input = '
2+2
' doc = filter(input) expect(doc.to_s).to eq input end it 'dollar signs around to display math' do doc = filter('$
2+2
$') before = doc.xpath('descendant-or-self::text()[1]').first after = doc.xpath('descendant-or-self::text()[3]').first expect(before.to_s).to eq '$' expect(after.to_s).to eq '$' end end describe 'unrecognized syntax' do where(:text) do [ '2+2', 'test $2+2 test', 'test 2+2$ test', '$2+2$', '$20,000 and $30,000', '$20,000 in $USD', '$ a^2 $', "test $$\n2+2\n$$", "$\n$", '$$$' ] end with_them do it 'is ignored' do expect(filter(text).to_s).to eq text end end end it 'handles multiple styles in one text block' do doc = filter('$2+2$ + $3+3$ + $$4+4$$') expect(doc.search('.js-render-math').count).to eq(3) expect(doc.search('[data-math-style="inline"]').count).to eq(2) expect(doc.search('[data-math-style="display"]').count).to eq(1) end it 'limits how many elements can be marked as math' do stub_const('Banzai::Filter::MathFilter::RENDER_NODES_LIMIT', 2) doc = filter('$2+2$ + $3+3$ + $4+4$') expect(doc.search('.js-render-math').count).to eq(2) end it 'does not recognize new syntax when feature flag is off' do stub_feature_flags(markdown_dollar_math: false) doc = filter('$1+2$') expect(doc.to_s).to eq '$1+2$' end end