todos_spec.rb 7.42 KB
Newer Older
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
1 2 3 4 5
require 'spec_helper'

describe API::Todos, api: true do
  include ApiHelpers

6 7
  let(:project_1) { create(:empty_project) }
  let(:project_2) { create(:empty_project) }
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
8 9 10 11
  let(:author_1) { create(:user) }
  let(:author_2) { create(:user) }
  let(:john_doe) { create(:user, username: 'john_doe') }
  let(:merge_request) { create(:merge_request, source_project: project_1) }
12
  let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) }
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
13
  let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) }
14
  let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe) }
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
15 16
  let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) }

17 18 19 20 21
  before do
    project_1.team << [john_doe, :developer]
    project_2.team << [john_doe, :developer]
  end

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
22 23
  describe 'GET /todos' do
    context 'when unauthenticated' do
24
      it 'returns authentication error' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
25
        get api('/todos')
26

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
27 28 29 30 31
        expect(response.status).to eq(401)
      end
    end

    context 'when authenticated' do
32
      it 'returns an array of pending todos for current user' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
33
        get api('/todos', john_doe)
34

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
35
        expect(response.status).to eq(200)
36
        expect(response).to include_pagination_headers
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
37 38
        expect(json_response).to be_an Array
        expect(json_response.length).to eq(3)
Robert Schilling's avatar
Robert Schilling committed
39 40 41 42
        expect(json_response[0]['id']).to eq(pending_3.id)
        expect(json_response[0]['project']).to be_a Hash
        expect(json_response[0]['author']).to be_a Hash
        expect(json_response[0]['target_type']).to be_present
43
        expect(json_response[0]['target']).to be_a Hash
Robert Schilling's avatar
Robert Schilling committed
44 45 46
        expect(json_response[0]['target_url']).to be_present
        expect(json_response[0]['body']).to be_present
        expect(json_response[0]['state']).to eq('pending')
Robert Schilling's avatar
Robert Schilling committed
47
        expect(json_response[0]['action_name']).to eq('assigned')
Robert Schilling's avatar
Robert Schilling committed
48
        expect(json_response[0]['created_at']).to be_present
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
49 50 51
      end

      context 'and using the author filter' do
52
        it 'filters based on author_id param' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
53
          get api('/todos', john_doe), { author_id: author_2.id }
54

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
55
          expect(response.status).to eq(200)
56
          expect(response).to include_pagination_headers
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
57 58 59 60 61 62
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(2)
        end
      end

      context 'and using the type filter' do
63
        it 'filters based on type param' do
64 65
          create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request)

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
66
          get api('/todos', john_doe), { type: 'MergeRequest' }
67

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
68
          expect(response.status).to eq(200)
69
          expect(response).to include_pagination_headers
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
70 71 72 73 74 75
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
        end
      end

      context 'and using the state filter' do
76
        it 'filters based on state param' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
77
          get api('/todos', john_doe), { state: 'done' }
78

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
79
          expect(response.status).to eq(200)
80
          expect(response).to include_pagination_headers
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
81 82 83 84 85 86
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
        end
      end

      context 'and using the project filter' do
87
        it 'filters based on project_id param' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
88
          get api('/todos', john_doe), { project_id: project_2.id }
89

Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
90
          expect(response.status).to eq(200)
91
          expect(response).to include_pagination_headers
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
92 93 94 95
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
        end
      end
96 97 98 99 100 101

      context 'and using the action filter' do
        it 'filters based on action param' do
          get api('/todos', john_doe), { action: 'mentioned' }

          expect(response.status).to eq(200)
102
          expect(response).to include_pagination_headers
103 104 105 106
          expect(json_response).to be_an Array
          expect(json_response.length).to eq(1)
        end
      end
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
107 108 109
    end
  end

110
  describe 'POST /todos/:id/mark_as_done' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
111
    context 'when unauthenticated' do
112
      it 'returns authentication error' do
113
        post api("/todos/#{pending_1.id}/mark_as_done")
114

115
        expect(response).to have_http_status(401)
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
116 117 118 119
      end
    end

    context 'when authenticated' do
120
      it 'marks a todo as done' do
121
        post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
122

123 124 125
        expect(response).to have_http_status(201)
        expect(json_response['id']).to eq(pending_1.id)
        expect(json_response['state']).to eq('done')
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
126 127
        expect(pending_1.reload).to be_done
      end
128 129 130 131

      it 'updates todos cache' do
        expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original

132
        post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
133
      end
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
134 135 136
    end
  end

137
  describe 'POST /mark_as_done' do
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
138
    context 'when unauthenticated' do
139
      it 'returns authentication error' do
140
        post api('/todos/mark_as_done')
141

142
        expect(response).to have_http_status(401)
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
143 144 145 146
      end
    end

    context 'when authenticated' do
147
      it 'marks all todos as done' do
148
        post api('/todos/mark_as_done', john_doe)
149

150
        expect(response).to have_http_status(204)
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
151 152 153 154
        expect(pending_1.reload).to be_done
        expect(pending_2.reload).to be_done
        expect(pending_3.reload).to be_done
      end
155 156 157 158

      it 'updates todos cache' do
        expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original

159
        post api("/todos/mark_as_done", john_doe)
160
      end
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
161 162
    end
  end
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

  shared_examples 'an issuable' do |issuable_type|
    it 'creates a todo on an issuable' do
      post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", john_doe)

      expect(response.status).to eq(201)
      expect(json_response['project']).to be_a Hash
      expect(json_response['author']).to be_a Hash
      expect(json_response['target_type']).to eq(issuable.class.name)
      expect(json_response['target']).to be_a Hash
      expect(json_response['target_url']).to be_present
      expect(json_response['body']).to be_present
      expect(json_response['state']).to eq('pending')
      expect(json_response['action_name']).to eq('marked')
      expect(json_response['created_at']).to be_present
    end

    it 'returns 304 there already exist a todo on that issuable' do
      create(:todo, project: project_1, author: author_1, user: john_doe, target: issuable)

      post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", john_doe)

      expect(response.status).to eq(304)
    end

    it 'returns 404 if the issuable is not found' do
      post api("/projects/#{project_1.id}/#{issuable_type}/123/todo", john_doe)

      expect(response.status).to eq(404)
    end
193 194 195 196 197 198 199 200 201 202 203 204 205

    it 'returns an error if the issuable is not accessible' do
      guest = create(:user)
      project_1.team << [guest, :guest]

      post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", guest)

      if issuable_type == 'merge_requests'
        expect(response).to have_http_status(403)
      else
        expect(response).to have_http_status(404)
      end
    end
206 207 208 209 210
  end

  describe 'POST :id/issuable_type/:issueable_id/todo' do
    context 'for an issue' do
      it_behaves_like 'an issuable', 'issues' do
211
        let(:issuable) { create(:issue, :confidential, author: author_1, project: project_1) }
212 213 214 215 216 217 218 219 220
      end
    end

    context 'for a merge request' do
      it_behaves_like 'an issuable', 'merge_requests' do
        let(:issuable) { merge_request }
      end
    end
  end
Douglas Barbosa Alexandre's avatar
Douglas Barbosa Alexandre committed
221
end