54 | if child.tag == :p 55 | [:blockquote, [child]] 56 | else 57 | [child] 58 | end 59 | end 60 | end 61 | 62 | it 'should not pass those nodes again to the block' do 63 | expect(rewriter.to_hexp).to eql H[:div, [ 64 | [:a], 65 | [:blockquote, [ 66 | [:p]]], 67 | [:br]]] 68 | end 69 | end 70 | 71 | context 'with a one parameter block' do 72 | let :hexp do 73 | H[:parent, [[:child]]] 74 | end 75 | 76 | let :block do 77 | proc do |child| 78 | expect(child).to eq(H[:child]) 79 | [child] 80 | end 81 | end 82 | 83 | it 'should receive the child node as its argument' do 84 | rewriter.to_hexp 85 | end 86 | end 87 | 88 | describe 'block response types' do 89 | context 'when responding with a single node' do 90 | let :block do 91 | proc do |child| 92 | H[:br] 93 | end 94 | end 95 | 96 | it 'should replace the existing node' do 97 | expect(rewriter.to_hexp).to eq H[:div, [ [:br] ]*3 ] 98 | end 99 | end 100 | 101 | context 'when responding with an array that starts with a Symbol' do 102 | let :block do 103 | proc do |child| 104 | [:br, {class: 'foo'} ] 105 | end 106 | end 107 | 108 | it 'should treat it as a node and replace the existing one' do 109 | expect(rewriter.to_hexp).to eq H[:div, [ [:br, {'class' => 'foo'}] ]*3 ] 110 | end 111 | end 112 | 113 | context 'when responding with a String' do 114 | let :hexp do 115 | H[:div, [ 116 | [:p] 117 | ] 118 | ] 119 | end 120 | 121 | let :block do 122 | proc do |child| 123 | "Hello" 124 | end 125 | end 126 | 127 | it 'should convert it to a text node' do 128 | expect(rewriter.to_hexp).to eq H[:div, [ Hexp::TextNode.new("Hello") ] ] 129 | end 130 | end 131 | 132 | 133 | context 'when responding with nil' do 134 | let :block do 135 | proc do |node| 136 | node if [:p, :br].include? node.tag 137 | end 138 | end 139 | 140 | it 'should remove the original node' do 141 | expect(rewriter.to_hexp).to eq H[:div, [ H[:p], H[:br] ]] 142 | end 143 | end 144 | end 145 | 146 | context 'when responding with something else than a Hexp, Array or String' do 147 | let :block do 148 | proc do |node| 149 | Object.new 150 | end 151 | end 152 | 153 | it 'should raise a FormatError' do 154 | expect{rewriter.to_hexp}.to raise_exception(Hexp::FormatError) 155 | end 156 | end 157 | 158 | context 'with a css selector argument' do 159 | let(:selector) { 'p.foo' } 160 | 161 | it 'should delegate to CssSelection, rather than Rewriter' do 162 | expect(Hexp::Node::CssSelection).to receive(:new).with(hexp, selector).and_return(double(:rewrite => hexp)) 163 | hexp.rewrite(selector) 164 | end 165 | end 166 | 167 | end 168 | -------------------------------------------------------------------------------- /spec/unit/hexp/node/selection_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Node::Selection do 4 | subject(:selection) { Hexp::Node::Selection.new(hexp, block) } 5 | let(:yielded_elements) { [] } 6 | let(:block) { proc {|el| yielded_elements << el } } 7 | let(:hexp) { H[:div, [[:span]]] } 8 | 9 | describe 'as Enumerable' do 10 | let(:block) { proc {|el| el.tag == :span} } 11 | 12 | it 'should enumerate elements for which the block returns trueish' do 13 | expect(selection.to_a).to eq [H[:span]] 14 | end 15 | end 16 | 17 | describe 'rewriting operations' do 18 | let(:block) { proc {|el| el.tag == :span} } 19 | 20 | it 'should perform them on elements that match' do 21 | expect(selection.attr('class', 'matched').to_hexp).to eq( 22 | H[:div, [[:span, {class: 'matched'}]]] 23 | ) 24 | end 25 | 26 | describe 'wrap' do 27 | let(:hexp) { H[:ul, [[:a, href: 'foo'], [:a, href: 'bar']]] } 28 | let(:block) { proc {|el| el.tag == :a} } 29 | 30 | it 'should be able to wrap element' do 31 | expect(selection.wrap(:li).to_hexp).to eq( 32 | H[:ul, [[:li, H[:a, href: 'foo']], [:li, H[:a, href: 'bar']]]] 33 | ) 34 | end 35 | end 36 | 37 | describe 'rewrite' do 38 | let(:hexp) { H[:ul, [[:a, href: 'foo'], [:span]]] } 39 | let(:block) { proc {|el| el.tag == :a} } 40 | 41 | it 'should work on matching elements, and skip the rest' do 42 | expect(selection.rewrite{ H[:br] }.to_hexp).to eq H[:ul, [[:br], [:span]]] 43 | end 44 | end 45 | end 46 | 47 | context 'with a single element' do 48 | let(:hexp) { H[:div] } 49 | 50 | it 'should be lazy' do 51 | expect(block).to_not receive(:call) 52 | selection 53 | end 54 | 55 | it 'should yield the root element when realized' do 56 | expect(block).to receive(:call).once.with(H[:div]) 57 | selection.each {} 58 | end 59 | end 60 | 61 | context 'with nested elements' do 62 | let(:hexp) { 63 | H[:div, [ 64 | [:span, "hello"], 65 | [:span, "world"]]]} 66 | 67 | it 'should traverse the whole tree once, depth-first' do 68 | selection.each {} 69 | expect(yielded_elements).to eq [ 70 | Hexp::TextNode.new("hello"), 71 | H[:span, "hello"], 72 | Hexp::TextNode.new("world"), 73 | H[:span, "world"], 74 | hexp 75 | ] 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /spec/unit/hexp/node/text_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Node do 4 | subject { described_class[:p] } 5 | 6 | its(:text?) { should be false } 7 | end 8 | -------------------------------------------------------------------------------- /spec/unit/hexp/node/to_dom_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Node, 'to_dom' do 4 | subject { Hexp::Node[:blink] } 5 | 6 | it 'should delegate to Domize' do 7 | expect(Hexp::Node::Domize).to receive(:new).with(subject, {}).and_return( ->{ 'result' } ) 8 | expect(subject.to_dom).to eql 'result' 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/unit/hexp/node/to_hexp_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Node, 'to_hexp' do 4 | let(:object) {Hexp::Node.new(:p) } 5 | subject { object.to_hexp } 6 | 7 | it { should == subject } 8 | end 9 | -------------------------------------------------------------------------------- /spec/unit/hexp/node/to_html_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Node, 'to_html' do 4 | subject { Hexp::Node[:tt] } 5 | 6 | it 'should render HTML' do 7 | expect(subject.to_html).to eql '' 8 | end 9 | 10 | describe 'attribute escaping' do 11 | subject { Hexp::Node[:foo, {bar: "it's fine&dandy"}] } 12 | 13 | it 'should escape ampersand, single quote' do 14 | expect(subject.to_html).to eql "" 15 | end 16 | end 17 | 18 | describe 'text node escaping' do 19 | subject { Hexp::Node[:foo, "it's 5 > 3, & 6 < 3, \"fine chap\""] } 20 | 21 | it 'should escape ampersand, single quote, double quote, lower than, greater than' do 22 | expect(subject.to_html).to eql " it's 5 > 3, & 6 < 3, "fine chap" " 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/unit/hexp/nokogiri/equality_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Nokogiri::Equality do 4 | let(:doc) { Nokogiri::HTML::Document.new } 5 | 6 | context 'two empty documents' do 7 | it 'should be equal' do 8 | expect(described_class.new(Nokogiri::HTML::Document.new, Nokogiri::HTML::Document.new).call).to be true 9 | end 10 | end 11 | 12 | context 'two nodes with the same attributes' do 13 | it 'should be equal' do 14 | node1 = Nokogiri::XML::Node.new('div', doc) 15 | node1['class'] = 'hello' 16 | node2 = Nokogiri::XML::Node.new('div', doc) 17 | node2['class'] = 'hello' 18 | 19 | expect(described_class.new(node1, node2).call).to be true 20 | end 21 | end 22 | 23 | context 'one node has an attribute more' do 24 | it 'should be equal' do 25 | node1 = Nokogiri::XML::Node.new('div', doc) 26 | node1['class'] = 'hello' 27 | node2 = Nokogiri::XML::Node.new('div', doc) 28 | node2['class'] = 'hello' 29 | node2['id'] = 'zigzag' 30 | 31 | expect(described_class.new(node1, node2).call).to be true 32 | end 33 | end 34 | 35 | context 'two nodes with the same children' do 36 | it 'should be equal' do 37 | node1 = Nokogiri::XML::Node.new('div', doc) 38 | node1 << Nokogiri::XML::Node.new('p', doc) 39 | node2 = Nokogiri::XML::Node.new('div', doc) 40 | node2 << Nokogiri::XML::Node.new('p', doc) 41 | 42 | expect(described_class.new(node1, node2).call).to be true 43 | end 44 | end 45 | 46 | context 'two nodes with a child of a different name' do 47 | it 'should not be equal' do 48 | node1 = Nokogiri::XML::Node.new('div', doc) 49 | node1 << Nokogiri::XML::Node.new('p', doc) 50 | node2 = Nokogiri::XML::Node.new('div', doc) 51 | node2 << Nokogiri::XML::Node.new('em', doc) 52 | 53 | expect(described_class.new(node1, node2).call).to be false 54 | end 55 | end 56 | 57 | context 'one node has a child more than the other, otherwise identical' do 58 | it 'should not be equal' do 59 | node1 = Nokogiri::XML::Node.new('div', doc) 60 | node1 << Nokogiri::XML::Node.new('p', doc) 61 | node2 = Nokogiri::XML::Node.new('div', doc) 62 | node2 << Nokogiri::XML::Node.new('p', doc) 63 | node2 << Nokogiri::XML::Node.new('em', doc) 64 | 65 | expect(described_class.new(node1, node2).call).to be false 66 | end 67 | end 68 | 69 | end 70 | -------------------------------------------------------------------------------- /spec/unit/hexp/nokogiri/reader_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Nokogiri::Reader do 4 | let(:doc) { Nokogiri::HTML::Document.new } 5 | 6 | 7 | 8 | end 9 | -------------------------------------------------------------------------------- /spec/unit/hexp/parse_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp, 'parse' do 4 | context 'with an empty document' do 5 | let(:html) { '' } 6 | 7 | it 'should raise an exception' do 8 | expect{ Hexp.parse(html) }.to raise_exception Hexp::ParseError 9 | end 10 | end 11 | 12 | it 'should parse a single tag' do 13 | expect(Hexp.parse('Hello!')).to eq H[:a, 'Hello!'] 14 | end 15 | 16 | it 'should parse nested tags' do 17 | expect(Hexp.parse('Ciao Bella')).to eq H[:a, ['Ciao ', H[:em, 'Bella']]] 18 | end 19 | 20 | it 'should parse attributes' do 21 | expect(Hexp.parse('Ciao Bella')).to eq H[:a, {href: 'pretty'}, 'Ciao Bella'] 22 | end 23 | 24 | it 'should parse style tags' do 25 | expect(Hexp.parse('')).to eq( 26 | H[:html, 27 | H[:head, 28 | H[:style, {type: 'text/css'}, 'h1 {font-weigth: 400;}'] 29 | ] 30 | ] 31 | ) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/unit/hexp/text_node_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::TextNode do 4 | subject { described_class.new('some string') } 5 | 6 | describe 'Node triplet' do 7 | its(:tag) { should be_nil } 8 | its(:attributes) { should eq({}) } 9 | its(:attributes) { should be_frozen } 10 | its(:children) { should eq([]) } 11 | its(:children) { should be_frozen } 12 | end 13 | 14 | describe 'DSL methods' do 15 | its(:text?) { should be true } 16 | its(:rewrite) { should eq(subject) } 17 | its(:to_hexp) { should eq(subject) } 18 | 19 | describe 'class?' do 20 | it 'should always return false' do 21 | expect(subject.class?('strong')).to be false 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/unit/hexp/unparser_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp::Unparser do 4 | let(:unparser) { described_class.new({}) } 5 | let(:node) { H[:p, %q{Hello "world", it's great meet & chat >.<}] } 6 | let(:html) { unparser.call(node) } 7 | 8 | it 'should escape sensitive characters' do 9 | expect(html).to eql 'Hello "world", it's great meet & chat >.<
' 10 | end 11 | 12 | context 'inside a script tag' do 13 | let(:node) { H[:script, %q{Hello "world", }, %q{it's great meet & chat >.<}] } 14 | 15 | it 'should not escape' do 16 | expect(html).to eql %q{} 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/unit/hexp_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Hexp, 'Array' do 4 | context 'with an array as input' do 5 | it 'should return the array' do 6 | expect(Hexp.Array([:foo])).to eq([:foo]) 7 | end 8 | end 9 | 10 | context 'with a single object as an input' do 11 | it 'should wrap it in an array' do 12 | expect(Hexp.Array(:foo)).to eq([:foo]) 13 | end 14 | end 15 | 16 | context 'with an object that responds to to_ary' do 17 | let(:array_like) do 18 | Class.new { def to_ary; [1,2,3] ; end }.new 19 | end 20 | 21 | it 'should return the result of to_ary' do 22 | expect(Hexp.Array(array_like)).to eq([1,2,3]) 23 | end 24 | end 25 | end 26 | 27 | describe Hexp, 'build' do 28 | it 'should delegate to Hexp::Builder.new' do 29 | block = proc {} 30 | expect(Hexp::Builder).to receive(:new).with(:div, class: 'moambe', &block) 31 | Hexp.build(:div, class: 'moambe', &block) 32 | end 33 | end 34 | --------------------------------------------------------------------------------