issues_resolver_spec.rb 8.21 KB
Newer Older
1 2
# frozen_string_literal: true

3 4 5 6 7 8
require 'spec_helper'

describe Resolvers::IssuesResolver do
  include GraphqlHelpers

  let(:current_user) { create(:user) }
9

10 11 12 13 14 15 16 17 18 19 20 21
  let_it_be(:group)         { create(:group) }
  let_it_be(:project)       { create(:project, group: group) }
  let_it_be(:other_project) { create(:project, group: group) }

  let_it_be(:milestone) { create(:milestone, project: project) }
  let_it_be(:assignee)  { create(:user) }
  let_it_be(:issue1)    { create(:issue, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: milestone) }
  let_it_be(:issue2)    { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
  let_it_be(:issue3)    { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
  let_it_be(:issue4)    { create(:issue) }
  let_it_be(:label1)    { create(:label, project: project) }
  let_it_be(:label2)    { create(:label, project: project) }
22

23
  context "with a project" do
24 25 26 27 28
    before do
      project.add_developer(current_user)
      create(:label_link, label: label1, target: issue1)
      create(:label_link, label: label1, target: issue2)
      create(:label_link, label: label2, target: issue2)
29 30
    end

31 32 33 34
    describe '#resolve' do
      it 'finds all issues' do
        expect(resolve_issues).to contain_exactly(issue1, issue2)
      end
35

36 37 38
      it 'filters by state' do
        expect(resolve_issues(state: 'opened')).to contain_exactly(issue1)
        expect(resolve_issues(state: 'closed')).to contain_exactly(issue2)
39 40
      end

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
      it 'filters by milestone' do
        expect(resolve_issues(milestone_title: milestone.title)).to contain_exactly(issue1)
      end

      it 'filters by assignee_username' do
        expect(resolve_issues(assignee_username: assignee.username)).to contain_exactly(issue2)
      end

      it 'filters by assignee_id' do
        expect(resolve_issues(assignee_id: assignee.id)).to contain_exactly(issue2)
      end

      it 'filters by any assignee' do
        expect(resolve_issues(assignee_id: IssuableFinder::FILTER_ANY)).to contain_exactly(issue2)
      end

      it 'filters by no assignee' do
        expect(resolve_issues(assignee_id: IssuableFinder::FILTER_NONE)).to contain_exactly(issue1)
      end

61 62 63
      it 'filters by labels' do
        expect(resolve_issues(label_name: [label1.title])).to contain_exactly(issue1, issue2)
        expect(resolve_issues(label_name: [label1.title, label2.title])).to contain_exactly(issue2)
64 65
      end

66 67 68 69 70 71 72 73
      describe 'filters by created_at' do
        it 'filters by created_before' do
          expect(resolve_issues(created_before: 2.hours.ago)).to contain_exactly(issue1)
        end

        it 'filters by created_after' do
          expect(resolve_issues(created_after: 2.hours.ago)).to contain_exactly(issue2)
        end
74 75
      end

76 77 78 79 80 81 82 83
      describe 'filters by updated_at' do
        it 'filters by updated_before' do
          expect(resolve_issues(updated_before: 2.hours.ago)).to contain_exactly(issue1)
        end

        it 'filters by updated_after' do
          expect(resolve_issues(updated_after: 2.hours.ago)).to contain_exactly(issue2)
        end
84 85
      end

86 87
      describe 'filters by closed_at' do
        let!(:issue3) { create(:issue, project: project, state: :closed, closed_at: 3.hours.ago) }
88

89 90 91 92 93 94 95
        it 'filters by closed_before' do
          expect(resolve_issues(closed_before: 2.hours.ago)).to contain_exactly(issue3)
        end

        it 'filters by closed_after' do
          expect(resolve_issues(closed_after: 2.hours.ago)).to contain_exactly(issue2)
        end
96 97
      end

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
      context 'when searching issues' do
        it 'returns correct issues' do
          expect(resolve_issues(search: 'foo')).to contain_exactly(issue2)
        end

        it 'uses project search optimization' do
          expected_arguments = {
            search: 'foo',
            attempt_project_search_optimizations: true,
            iids: [],
            project_id: project.id
          }
          expect(IssuesFinder).to receive(:new).with(anything, expected_arguments).and_call_original

          resolve_issues(search: 'foo')
        end
114
      end
115

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
      describe 'sorting' do
        context 'when sorting by created' do
          it 'sorts issues ascending' do
            expect(resolve_issues(sort: 'created_asc')).to eq [issue1, issue2]
          end

          it 'sorts issues descending' do
            expect(resolve_issues(sort: 'created_desc')).to eq [issue2, issue1]
          end
        end

        context 'when sorting by due date' do
          let(:project) { create(:project) }

          let!(:due_issue1) { create(:issue, project: project, due_date: 3.days.from_now) }
          let!(:due_issue2) { create(:issue, project: project, due_date: nil) }
          let!(:due_issue3) { create(:issue, project: project, due_date: 2.days.ago) }
          let!(:due_issue4) { create(:issue, project: project, due_date: nil) }

          it 'sorts issues ascending' do
            expect(resolve_issues(sort: :due_date_asc)).to eq [due_issue3, due_issue1, due_issue4, due_issue2]
          end

          it 'sorts issues descending' do
            expect(resolve_issues(sort: :due_date_desc)).to eq [due_issue1, due_issue3, due_issue4, due_issue2]
          end
        end
143 144 145 146 147 148 149 150 151 152 153 154 155

        context 'when sorting by relative position' do
          let(:project) { create(:project) }

          let!(:relative_issue1) { create(:issue, project: project, relative_position: 2000) }
          let!(:relative_issue2) { create(:issue, project: project, relative_position: nil) }
          let!(:relative_issue3) { create(:issue, project: project, relative_position: 1000) }
          let!(:relative_issue4) { create(:issue, project: project, relative_position: nil) }

          it 'sorts issues ascending' do
            expect(resolve_issues(sort: :relative_position_asc)).to eq [relative_issue3, relative_issue1, relative_issue4, relative_issue2]
          end
        end
156
      end
157

158 159
      it 'returns issues user can see' do
        project.add_guest(current_user)
160

161
        create(:issue, confidential: true)
162

163 164
        expect(resolve_issues).to contain_exactly(issue1, issue2)
      end
165

166 167 168
      it 'finds a specific issue with iid' do
        expect(resolve_issues(iid: issue1.iid)).to contain_exactly(issue1)
      end
169

170 171 172
      it 'finds a specific issue with iids' do
        expect(resolve_issues(iids: issue1.iid)).to contain_exactly(issue1)
      end
173

174 175 176 177
      it 'finds multiple issues with iids' do
        expect(resolve_issues(iids: [issue1.iid, issue2.iid]))
          .to contain_exactly(issue1, issue2)
      end
178

179 180 181 182 183 184 185
      it 'finds only the issues within the project we are looking at' do
        another_project = create(:project)
        iids = [issue1, issue2].map(&:iid)

        iids.each do |iid|
          create(:issue, project: another_project, iid: iid)
        end
186

187 188 189 190
        expect(resolve_issues(iids: iids)).to contain_exactly(issue1, issue2)
      end
    end
  end
191

192 193 194 195 196 197 198 199 200 201 202 203 204 205
  context "with a group" do
    before do
      group.add_developer(current_user)
    end

    describe '#resolve' do
      it 'finds all group issues' do
        result = resolve(described_class, obj: group, ctx: { current_user: current_user })

        expect(result).to contain_exactly(issue1, issue2, issue3)
      end
    end
  end

206 207
  context "when passing a non existent, batch loaded project" do
    let(:project) do
208
      BatchLoader::GraphQL.for("non-existent-path").batch do |_fake_paths, loader, _|
209
        loader.call("non-existent-path", nil)
210
      end
211
    end
212

213 214
    it "returns nil without breaking" do
      expect(resolve_issues(iids: ["don't", "break"])).to be_empty
215
    end
216 217
  end

218
  it 'increases field complexity based on arguments' do
219
    field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
220 221 222 223 224

    expect(field.to_graphql.complexity.call({}, {}, 1)).to eq 4
    expect(field.to_graphql.complexity.call({}, { labelName: 'foo' }, 1)).to eq 8
  end

225 226 227 228
  def resolve_issues(args = {}, context = { current_user: current_user })
    resolve(described_class, obj: project, args: args, ctx: context)
  end
end