module SimpleNavigation describe Item do let!(:item_container) { ItemContainer.new } let(:adapter) { double(:adapter) } let(:item_args) { [item_container, :my_key, 'name', url, options] } let(:item) { Item.new(*item_args) } let(:options) { Hash.new } let(:url) { 'url' } before { allow(SimpleNavigation).to receive_messages(adapter: adapter) } describe '#highlights_on' do let(:options) {{ highlights_on: :test }} it "returns the item's highlights_on option" do expect(item.highlights_on).to eq :test end end describe '#initialize' do context 'when there is a sub_navigation' do let(:subnav_container) { double(:subnav_container).as_null_object } shared_examples 'creating sub navigation container' do it 'creates a sub navigation container with a level+1' do expect(item.sub_navigation.level).to eq 2 end end context 'when a block is given' do it_behaves_like 'creating sub navigation container' do let(:item) { Item.new(*item_args) {} } end it 'calls the block' do allow(ItemContainer).to receive_messages(new: subnav_container) expect{ |blk| Item.new(*item_args, &blk) }.to yield_with_args(subnav_container) end end context 'when no block is given' do context 'and items are given' do let(:items) { [] } let(:options) {{ items: items }} it_behaves_like 'creating sub navigation container' it "sets the items on the subnav_container" do expect(item.sub_navigation.items).to eq items end end context 'and no items are given' do it "doesn't create a new ItemContainer" do item = Item.new(*item_args) expect(item.sub_navigation).to be_nil end end end end context 'when a :method option is given' do let(:options) {{ method: :delete }} it "sets the item's method" do expect(item.method).to eq :delete end end context 'when no :method option is given' do it "sets the item's method to nil" do expect(item.method).to be_nil end end context 'when an :highlights_on option is given' do let(:highlights_on) { double(:highlights_on) } let(:options) {{ highlights_on: highlights_on }} it "sets the item's highlights_on" do expect(item.highlights_on).to eq highlights_on end end context 'when no :highlights_on option is given' do it "sets the item's highlights_on to nil" do expect(item.highlights_on).to be_nil end end context 'when a url is given' do context 'and it is a string' do it "sets the item's url accordingly" do expect(item.url).to eq 'url' end end context 'and it is a proc' do let(:url) { proc{ "my_" + "url" } } it "sets the item's url accordingly" do expect(item.url).to eq 'my_url' end end context 'and it is nil' do let(:url) { nil } it "sets the item's url accordingly" do expect(item.url).to be_nil end end end context 'when no url nor options is specified' do let(:item_args) { [item_container, :my_key, 'name'] } it "sets the item's url to nil" do expect(item.url).to be_nil end end context 'when only a url is given' do let(:item_args) { [item_container, :my_key, 'name', 'url'] } it "set the item's url accordingly" do expect(item.url).to eq 'url' end end context 'when url and options are given' do let(:options) {{ html: { option: true } }} before { allow(adapter).to receive_messages(current_page?: false) } it "set the item's url accordingly" do expect(item.url).to eq 'url' end it "sets the item's html_options accordingly" do allow(item).to \ receive_messages(selected_by_subnav?: false, selected_by_condition?: false) expect(item.html_options).to include(option: true) end end end describe '#link_html_options' do let(:options) {{ link_html: :test }} it "returns the item's link_html option" do expect(item.link_html_options).to eq :test end end describe '#method' do let(:options) {{ method: :test }} it "returns the item's method option" do expect(item.method).to eq :test end end describe '#name' do before do allow(SimpleNavigation.config).to \ receive_messages(name_generator: proc{ |name| "#{name}" }) end context 'when no option is given' do context 'and the name_generator uses only the name' do it 'uses the default name_generator' do expect(item.name).to eq 'name' end end context 'and the name_generator uses only the item itself' do before do allow(SimpleNavigation.config).to \ receive_messages(name_generator: proc{ |name, item| "#{item.key}" }) end it 'uses the default name_generator' do expect(item.name).to eq 'my_key' end end end context 'when the :apply_generator is false' do it "returns the item's name" do expect(item.name(apply_generator: false)).to eq 'name' end end context 'when a block is given' do let(:item_args) { [item_container, :my_key, -> { 'Name in block' }, url, options] } it "returns the item's name that is defined in the block" do expect(item.name).to include 'Name in block' end end end describe '#selected?' do context 'when the item has no :highlights_on option' do before { allow(SimpleNavigation).to receive_messages(config: config) } context 'and auto highlighting is off' do let(:config) { double(:config, auto_highlight: false) } it 'returns false' do expect(item.selected?).to be false end end context 'and auto highlighting is on' do let(:config) { double(:config, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true, auto_highlight: true) } context "and the current url matches the item's url" do before { allow(adapter).to receive_messages(current_page?: true) } it 'returns true' do expect(item.selected?).to be true end end context "and the current url does not match the item's url" do let(:config) do double(:config, auto_highlight: false, highlight_on_subpath: false) end before { allow(adapter).to receive_messages(current_page?: false) } it 'returns false' do expect(item.selected?).to be false end end context 'and highlights_on_subpath is on' do let(:config) do double(:config, auto_highlight: true, highlight_on_subpath: true, ignore_query_params_on_auto_highlight: true, ignore_anchors_on_auto_highlight: true) end context "but item has no url" do let(:url) { nil } it 'returns false' do expect(item.selected?).to be false end end context "and the current url is a sub path of the item's url" do before do allow(adapter).to \ receive_messages(current_page?: false, request_uri: 'url/test') end it 'returns true' do expect(item.selected?).to be true end end context "and the current url is not a sub path of the item's url" do before do allow(adapter).to \ receive_messages(current_page?: false, request_uri: 'other/test') end it 'returns false' do expect(item.selected?).to be false end end end end end context 'when the item has a :highlights_on option' do context 'and it is a regular expression' do before { allow(adapter).to receive_messages(request_uri: '/test') } context 'and the current url matches the expression' do let(:options) {{ highlights_on: /test/ }} it 'returns true' do expect(item.selected?).to be true end end context 'and the current url does not match the expression' do let(:options) {{ highlights_on: /other/ }} it 'returns false' do expect(item.selected?).to be false end end end context 'and it is a callable object' do context 'and the call returns true' do let(:options) {{ highlights_on: -> { true } }} it 'returns true' do expect(item.selected?).to be true end end context 'and the call returns false' do let(:options) {{ highlights_on: -> { false } }} it 'returns false' do expect(item.selected?).to be false end end end context 'and it is the :subpath symbol' do let(:options) {{ highlights_on: :subpath }} context "and the current url is a sub path of the item's url" do before do allow(adapter).to receive_messages(request_uri: 'url/test') end it 'returns true' do expect(item.selected?).to be true end end context "and the current url is not a sub path of the item's url" do before do allow(adapter).to receive_messages(request_uri: 'other/test') end it 'returns false' do expect(item.selected?).to be false end end end context 'and it is non usable' do let(:options) {{ highlights_on: :hello }} it 'raises an exception' do expect{ item.selected? }.to raise_error(ArgumentError, ':highlights_on must be a Regexp, Proc or :subpath') end end end end describe '#selected_class' do context 'when the item is selected' do before { allow(item).to receive_messages(selected?: true) } it 'returns the default selected_class' do expect(item.selected_class).to eq 'selected' end context 'and selected_class is defined in the context' do before { allow(item_container).to receive_messages(selected_class: 'defined') } it "returns the context's selected_class" do expect(item.selected_class).to eq 'defined' end end end context 'when the item is not selected' do before { allow(item).to receive_messages(selected?: false) } it 'returns nil' do expect(item.selected_class).to be_nil end end end describe ':html_options argument' do let(:selected_classes) { 'selected simple-navigation-active-leaf' } context 'when the :class option is given' do let(:options) {{ html: { class: 'my_class' } }} context 'and the item is selected' do before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) } it "adds the specified class to the item's html classes" do expect(item.html_options[:class]).to include('my_class') end it "doesn't replace the default html classes of a selected item" do expect(item.html_options[:class]).to include(selected_classes) end end context "and the item isn't selected" do before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) } it "sets the specified class as the item's html classes" do expect(item.html_options[:class]).to include('my_class') end end end context "when the :class option isn't given" do context 'and the item is selected' do before { allow(item).to receive_messages(selected?: true, selected_by_condition?: true) } it "sets the default html classes of a selected item" do expect(item.html_options[:class]).to include(selected_classes) end end context "and the item isn't selected" do before { allow(item).to receive_messages(selected?: false, selected_by_condition?: false) } it "doesn't set any html class on the item" do expect(item.html_options[:class]).to be_blank end end end shared_examples 'generating id' do |id| it "sets the item's html id to the specified id" do expect(item.html_options[:id]).to eq id end end describe 'when the :id option is given' do let(:options) {{ html: { id: 'my_id' } }} before do allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids) allow(item).to receive_messages(selected?: false, selected_by_condition?: false) end context 'and :autogenerate_item_ids is true' do let(:generate_ids) { true } it_behaves_like 'generating id', 'my_id' end context 'and :autogenerate_item_ids is false' do let(:generate_ids) { false } it_behaves_like 'generating id', 'my_id' end end context "when the :id option isn't given" do before do allow(SimpleNavigation.config).to receive_messages(autogenerate_item_ids: generate_ids) allow(item).to receive_messages(selected?: false, selected_by_condition?: false) end context 'and :autogenerate_item_ids is true' do let(:generate_ids) { true } it_behaves_like 'generating id', 'my_key' end context 'and :autogenerate_item_ids is false' do let(:generate_ids) { false } it "doesn't set any html id on the item" do expect(item.html_options[:id]).to be_blank end end end end end end