Commit d2afddfe authored by Rémy Coutable's avatar Rémy Coutable

Refactor EventFilter and increase its test coverage

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 65cf8052
...@@ -273,10 +273,10 @@ class ApplicationController < ActionController::Base ...@@ -273,10 +273,10 @@ class ApplicationController < ActionController::Base
end end
def event_filter def event_filter
# Split using comma to maintain backward compatibility Ex/ "filter1,filter2" @event_filter ||=
filters = cookies['event_filter'].split(',')[0] if cookies['event_filter'].present? EventFilter.new(params[:event_filter].presence || cookies[:event_filter]).tap do |new_event_filter|
filters = params[:event_filter].split(',')[0] if params[:event_filter].present? cookies[:event_filter] = new_event_filter.filter
@event_filter ||= EventFilter.new(filters) end
end end
# JSON for infinite scroll via Pager object # JSON for infinite scroll via Pager object
......
...@@ -40,7 +40,7 @@ class DashboardController < Dashboard::ApplicationController ...@@ -40,7 +40,7 @@ class DashboardController < Dashboard::ApplicationController
end end
@events = EventCollection @events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: @event_filter) .new(projects, offset: params[:offset].to_i, filter: event_filter)
.to_a .to_a
Events::RenderService.new(current_user).execute(@events) Events::RenderService.new(current_user).execute(@events)
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
.fade-left= icon('angle-left') .fade-left= icon('angle-left')
.fade-right= icon('angle-right') .fade-right= icon('angle-right')
%ul.nav-links.event-filter.scrolling-tabs.nav.nav-tabs %ul.nav-links.event-filter.scrolling-tabs.nav.nav-tabs
= event_filter_link EventFilter.all, _('All'), s_('EventFilterBy|Filter by all') = event_filter_link EventFilter::ALL, _('All'), s_('EventFilterBy|Filter by all')
- if event_filter_visible(:repository) - if event_filter_visible(:repository)
= event_filter_link EventFilter.push, _('Push events'), s_('EventFilterBy|Filter by push events') = event_filter_link EventFilter::PUSH, _('Push events'), s_('EventFilterBy|Filter by push events')
- if event_filter_visible(:merge_requests) - if event_filter_visible(:merge_requests)
= event_filter_link EventFilter.merged, _('Merge events'), s_('EventFilterBy|Filter by merge events') = event_filter_link EventFilter::MERGED, _('Merge events'), s_('EventFilterBy|Filter by merge events')
- if event_filter_visible(:issues) - if event_filter_visible(:issues)
= event_filter_link EventFilter.issue, _('Issue events'), s_('EventFilterBy|Filter by issue events') = event_filter_link EventFilter::ISSUE, _('Issue events'), s_('EventFilterBy|Filter by issue events')
- if comments_visible? - if comments_visible?
= event_filter_link EventFilter.comments, _('Comments'), s_('EventFilterBy|Filter by comments') = event_filter_link EventFilter::COMMENTS, _('Comments'), s_('EventFilterBy|Filter by comments')
= event_filter_link EventFilter.team, _('Team'), s_('EventFilterBy|Filter by team') = event_filter_link EventFilter::TEAM, _('Team'), s_('EventFilterBy|Filter by team')
class EventFilter # frozen_string_literal: true
attr_accessor :params
class << self
def all
'all'
end
def push
'push'
end
def merged
'merged'
end
def issue class EventFilter
'issue' attr_accessor :filter
end
ALL = 'all'
def comments PUSH = 'push'
'comments' MERGED = 'merged'
end ISSUE = 'issue'
COMMENTS = 'comments'
def team TEAM = 'team'
'team' FILTERS = [ALL, PUSH, MERGED, ISSUE, COMMENTS, TEAM].freeze
end
def initialize(filter)
# Split using comma to maintain backward compatibility Ex/ "filter1,filter2"
filter = filter.to_s.split(',')[0].to_s
@filter = FILTERS.include?(filter) ? filter : ALL
end end
def initialize(params) def active?(key)
@params = if params filter == key.to_s
params.dup
else
[] # EventFilter.default_filter
end
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def apply_filter(events) def apply_filter(events)
return events if params.blank? || params == EventFilter.all case filter
when PUSH
case params
when EventFilter.push
events.where(action: Event::PUSHED) events.where(action: Event::PUSHED)
when EventFilter.merged when MERGED
events.where(action: Event::MERGED) events.where(action: Event::MERGED)
when EventFilter.comments when COMMENTS
events.where(action: Event::COMMENTED) events.where(action: Event::COMMENTED)
when EventFilter.team when TEAM
events.where(action: [Event::JOINED, Event::LEFT, Event::EXPIRED]) events.where(action: [Event::JOINED, Event::LEFT, Event::EXPIRED])
when EventFilter.issue when ISSUE
events.where(action: [Event::CREATED, Event::UPDATED, Event::CLOSED, Event::REOPENED]) events.where(action: [Event::CREATED, Event::UPDATED, Event::CLOSED, Event::REOPENED])
end
end
# rubocop: enable CodeReuse/ActiveRecord
def options(key)
filter = params.dup
if filter.include? key
filter.delete key
else else
filter << key events
end
filter
end
def active?(key)
if params.present?
params.include? key
else
key == EventFilter.all
end end
end end
# rubocop: enable CodeReuse/ActiveRecord
end end
...@@ -3,7 +3,7 @@ module QA ...@@ -3,7 +3,7 @@ module QA
module Project module Project
class Activity < Page::Base class Activity < Page::Base
view 'app/views/shared/_event_filter.html.haml' do view 'app/views/shared/_event_filter.html.haml' do
element :push_events, "event_filter_link EventFilter.push, _('Push events')" element :push_events, "event_filter_link EventFilter::PUSH, _('Push events')"
end end
def go_to_push_events def go_to_push_events
......
...@@ -24,7 +24,7 @@ FactoryBot.define do ...@@ -24,7 +24,7 @@ FactoryBot.define do
factory :push_event, class: PushEvent do factory :push_event, class: PushEvent do
project factory: :project_empty_repo project factory: :project_empty_repo
author factory: :user author(factory: :user) { project.creator }
action Event::PUSHED action Event::PUSHED
end end
......
...@@ -3,8 +3,10 @@ require 'spec_helper' ...@@ -3,8 +3,10 @@ require 'spec_helper'
describe 'Projects > Activity > User sees activity' do describe 'Projects > Activity > User sees activity' do
let(:project) { create(:project, :repository, :public) } let(:project) { create(:project, :repository, :public) }
let(:user) { project.creator } let(:user) { project.creator }
let(:issue) { create(:issue, project: project) }
before do before do
create(:event, :created, project: project, target: issue, author: user)
event = create(:push_event, project: project, author: user) event = create(:push_event, project: project, author: user)
create(:push_event_payload, create(:push_event_payload,
event: event, event: event,
...@@ -12,10 +14,18 @@ describe 'Projects > Activity > User sees activity' do ...@@ -12,10 +14,18 @@ describe 'Projects > Activity > User sees activity' do
commit_to: '6d394385cf567f80a8fd85055db1ab4c5295806f', commit_to: '6d394385cf567f80a8fd85055db1ab4c5295806f',
ref: 'fix', ref: 'fix',
commit_count: 1) commit_count: 1)
visit activity_project_path(project)
end end
it 'shows the last push in the activity page', :js do it 'shows the last push in the activity page', :js do
visit activity_project_path(project)
expect(page).to have_content "#{user.name} pushed new branch fix" expect(page).to have_content "#{user.name} pushed new branch fix"
end end
it 'allows to filter event with the "event_filter=issue" URL param', :js do
visit activity_project_path(project, event_filter: 'issue')
expect(page).not_to have_content "#{user.name} pushed new branch fix"
expect(page).to have_content "#{user.name} opened issue #{issue.to_reference}"
end
end end
require 'spec_helper' require 'spec_helper'
describe EventFilter do describe EventFilter do
describe 'FILTERS' do
it 'returns a definite list of filters' do
expect(described_class::FILTERS).to eq(%w[all push merged issue comments team])
end
end
describe '#filter' do
it 'returns "all" if given filter is nil' do
expect(described_class.new(nil).filter).to eq(described_class::ALL)
end
it 'returns "all" if given filter is ""' do
expect(described_class.new('').filter).to eq(described_class::ALL)
end
it 'returns "all" if given filter is "foo"' do
expect(described_class.new('foo').filter).to eq('all')
end
end
describe '#apply_filter' do describe '#apply_filter' do
let(:source_user) { create(:user) } set(:public_project) { create(:project, :public) }
let!(:public_project) { create(:project, :public) }
set(:push_event) { create(:push_event, project: public_project) }
set(:merged_event) { create(:event, :merged, project: public_project, target: public_project) }
set(:created_event) { create(:event, :created, project: public_project, target: public_project) }
set(:updated_event) { create(:event, :updated, project: public_project, target: public_project) }
set(:closed_event) { create(:event, :closed, project: public_project, target: public_project) }
set(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project) }
set(:comments_event) { create(:event, :commented, project: public_project, target: public_project) }
set(:joined_event) { create(:event, :joined, project: public_project, target: public_project) }
set(:left_event) { create(:event, :left, project: public_project, target: public_project) }
let!(:push_event) { create(:push_event, project: public_project, author: source_user) } let(:filtered_events) { described_class.new(filter).apply_filter(Event.all) }
let!(:merged_event) { create(:event, :merged, project: public_project, target: public_project, author: source_user) }
let!(:created_event) { create(:event, :created, project: public_project, target: public_project, author: source_user) }
let!(:updated_event) { create(:event, :updated, project: public_project, target: public_project, author: source_user) }
let!(:closed_event) { create(:event, :closed, project: public_project, target: public_project, author: source_user) }
let!(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project, author: source_user) }
let!(:comments_event) { create(:event, :commented, project: public_project, target: public_project, author: source_user) }
let!(:joined_event) { create(:event, :joined, project: public_project, target: public_project, author: source_user) }
let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) }
it 'applies push filter' do context 'with the "push" filter' do
events = described_class.new(described_class.push).apply_filter(Event.all) let(:filter) { described_class::PUSH }
expect(events).to contain_exactly(push_event)
it 'filters push events only' do
expect(filtered_events).to contain_exactly(push_event)
end
end end
it 'applies merged filter' do context 'with the "merged" filter' do
events = described_class.new(described_class.merged).apply_filter(Event.all) let(:filter) { described_class::MERGED }
expect(events).to contain_exactly(merged_event)
it 'filters merged events only' do
expect(filtered_events).to contain_exactly(merged_event)
end
end end
it 'applies issue filter' do context 'with the "issue" filter' do
events = described_class.new(described_class.issue).apply_filter(Event.all) let(:filter) { described_class::ISSUE }
expect(events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
it 'filters issue events only' do
expect(filtered_events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
end
end end
it 'applies comments filter' do context 'with the "comments" filter' do
events = described_class.new(described_class.comments).apply_filter(Event.all) let(:filter) { described_class::COMMENTS }
expect(events).to contain_exactly(comments_event)
it 'filters comment events only' do
expect(filtered_events).to contain_exactly(comments_event)
end
end end
it 'applies team filter' do context 'with the "team" filter' do
events = described_class.new(described_class.team).apply_filter(Event.all) let(:filter) { described_class::TEAM }
expect(events).to contain_exactly(joined_event, left_event)
it 'filters team events only' do
expect(filtered_events).to contain_exactly(joined_event, left_event)
end
end end
it 'applies all filter' do context 'with the "all" filter' do
events = described_class.new(described_class.all).apply_filter(Event.all) let(:filter) { described_class::ALL }
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
it 'returns all events' do
expect(filtered_events).to eq(Event.all)
end
end
context 'with an unknown filter' do
let(:filter) { 'foo' }
it 'returns all events' do
expect(filtered_events).to eq(Event.all)
end
end
context 'with a nil filter' do
let(:filter) { nil }
it 'returns all events' do
expect(filtered_events).to eq(Event.all)
end
end
end
describe '#active?' do
let(:event_filter) { described_class.new(described_class::TEAM) }
it 'returns false if filter does not include the given key' do
expect(event_filter.active?('foo')).to eq(false)
end end
it 'applies no filter' do it 'returns false if the given key is nil' do
events = described_class.new(nil).apply_filter(Event.all) expect(event_filter.active?(nil)).to eq(false)
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
end end
it 'applies unknown filter' do it 'returns true if filter does not include the given key' do
events = described_class.new('').apply_filter(Event.all) expect(event_filter.active?(described_class::TEAM)).to eq(true)
expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
end end
end end
end end
...@@ -41,7 +41,7 @@ describe EventCollection do ...@@ -41,7 +41,7 @@ describe EventCollection do
end end
it 'allows filtering of events using an EventFilter' do it 'allows filtering of events using an EventFilter' do
filter = EventFilter.new(EventFilter.issue) filter = EventFilter.new(EventFilter::ISSUE)
events = described_class.new(projects, filter: filter).to_a events = described_class.new(projects, filter: filter).to_a
expect(events.length).to eq(1) expect(events.length).to eq(1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment