From 7cb907cc77f5b7fdc4a5b2acc094e1fa3b3b9f92 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Thu, 30 Mar 2017 22:11:12 -0300 Subject: Add "search" optional param and docs for V4 Notice that this param is being supported since V3, but we have not added the proper docs for it --- .../30195-document-search-param-on-api.yml | 4 + doc/api/issues.md | 142 +++++--- lib/api/issues.rb | 1 + spec/requests/api/issues_spec.rb | 376 ++++++++------------- 4 files changed, 231 insertions(+), 292 deletions(-) create mode 100644 changelogs/unreleased/30195-document-search-param-on-api.yml diff --git a/changelogs/unreleased/30195-document-search-param-on-api.yml b/changelogs/unreleased/30195-document-search-param-on-api.yml new file mode 100644 index 00000000000..f19f6ab699e --- /dev/null +++ b/changelogs/unreleased/30195-document-search-param-on-api.yml @@ -0,0 +1,4 @@ +--- +title: Add search optional param and docs for V4 +merge_request: +author: diff --git a/doc/api/issues.md b/doc/api/issues.md index a19c965a8c3..5702cdcf3c1 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -26,16 +26,20 @@ GET /issues?labels=foo,bar&state=opened GET /issues?milestone=1.0.0 GET /issues?milestone=1.0.0&state=opened GET /issues?iids[]=42&iids[]=43 +GET /issues?search=issue+title+or+description ``` -| Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `state` | string | no | Return all issues or just those that are `opened` or `closed`| -| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | -| `milestone` | string| no | The milestone title | -| `iids` | Array[integer] | no | Return only the issues having the given `iid` | -| `order_by`| string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | -| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| +| Attribute | Type | Required | Description | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| +| `state` | string | no | Return all issues or just those that are `opened` or `closed` | +| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | +| `milestone` | string | no | The milestone title | +| `iids` | Array[integer] | no | Return only the issues having the given `iid` | +| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +| `search` | string | no | Search issues against their `title` and `description` | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| ```bash curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/issues @@ -104,17 +108,21 @@ GET /groups/:id/issues?labels=foo,bar&state=opened GET /groups/:id/issues?milestone=1.0.0 GET /groups/:id/issues?milestone=1.0.0&state=opened GET /groups/:id/issues?iids[]=42&iids[]=43 +GET /groups/:id/issues?search=issue+title+or+description ``` -| Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `id` | integer | yes | The ID of a group | -| `state` | string | no | Return all issues or just those that are `opened` or `closed`| -| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | -| `iids` | Array[integer] | no | Return only the issues having the given `iid` | -| `milestone` | string| no | The milestone title | -| `order_by`| string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | -| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| +| Attribute | Type | Required | Description | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| +| `id` | integer | yes | The ID of a group | +| `state` | string | no | Return all issues or just those that are `opened` or `closed` | +| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | +| `iids` | Array[integer] | no | Return only the issues having the given `iid` | +| `milestone` | string | no | The milestone title | +| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +| `search` | string | no | Search group issues against their `title` and `description` | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| ```bash @@ -184,17 +192,21 @@ GET /projects/:id/issues?labels=foo,bar&state=opened GET /projects/:id/issues?milestone=1.0.0 GET /projects/:id/issues?milestone=1.0.0&state=opened GET /projects/:id/issues?iids[]=42&iids[]=43 +GET /projects/:id/issues?search=issue+title+or+description ``` -| Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `id` | integer | yes | The ID of a project | -| `iids` | Array[integer] | no | Return only the milestone having the given `iid` | -| `state` | string | no | Return all issues or just those that are `opened` or `closed`| -| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | -| `milestone` | string| no | The milestone title | -| `order_by`| string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | -| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| +| Attribute | Type | Required | Description | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| +| `id` | integer | yes | The ID of a project | +| `iids` | Array[integer] | no | Return only the milestone having the given `iid` | +| `state` | string | no | Return all issues or just those that are `opened` or `closed` | +| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | +| `milestone` | string | no | The milestone title | +| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +| `search` | string | no | Search project issues against their `title` and `description` | +|-------------+----------------+----------+-----------------------------------------------------------------------------------------------------------------------------| ```bash @@ -258,10 +270,12 @@ Get a single project issue. GET /projects/:id/issues/:issue_iid ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/41 @@ -323,19 +337,23 @@ Creates a new project issue. POST /projects/:id/issues ``` -| Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `id` | integer | yes | The ID of a project | -| `title` | string | yes | The title of an issue | -| `description` | string | no | The description of an issue | -| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. | -| `assignee_id` | integer | no | The ID of a user to assign issue | -| `milestone_id` | integer | no | The ID of a milestone to assign issue | -| `labels` | string | no | Comma-separated label names for an issue | -| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | -| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | -| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. When passing a description or title, these values will take precedence over the default values. | -| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. | +|-------------------------------------------+---------+----------+------------------------------------------------------------------------------------------------------------------------------------------------------| +| Attribute | Type | Required | Description | +|-------------------------------------------+---------+----------+------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | integer | yes | The ID of a project | +| `title` | string | yes | The title of an issue | +| `description` | string | no | The description of an issue | +| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. | +| `assignee_id` | integer | no | The ID of a user to assign issue | +| `milestone_id` | integer | no | The ID of a milestone to assign issue | +| `labels` | string | no | Comma-separated label names for an issue | +| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | +| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | +| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. | +| - | - | - | When passing a description or title, these values will take precedence over the default values. | +| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion | +| - | - | - | as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. | +|-------------------------------------------+---------+----------+------------------------------------------------------------------------------------------------------------------------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug @@ -383,8 +401,9 @@ closed. PUT /projects/:id/issues/:issue_iid ``` +|----------------+---------+----------+------------------------------------------------------------------------------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|----------------+---------+----------+------------------------------------------------------------------------------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | | `title` | string | no | The title of an issue | @@ -396,6 +415,7 @@ PUT /projects/:id/issues/:issue_iid | `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it | | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | | `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | +|----------------+---------+----------+------------------------------------------------------------------------------------------------------------| ```bash curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close @@ -442,10 +462,12 @@ Only for admins and project owners. Soft deletes the issue in question. DELETE /projects/:id/issues/:issue_iid ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85 @@ -464,11 +486,13 @@ project, it will then be assigned to the issue that is being moved. POST /projects/:id/issues/:issue_iid/move ``` +|-----------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-----------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | | `to_project_id` | integer | yes | The ID of the new project | +|-----------------+---------+----------+--------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/4/issues/85/move @@ -520,10 +544,12 @@ is returned. POST /projects/:id/issues/:issue_iid/subscribe ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/subscribe @@ -575,10 +601,12 @@ status code `304` is returned. POST /projects/:id/issues/:issue_iid/unsubscribe ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/unsubscribe @@ -594,10 +622,12 @@ returned. POST /projects/:id/issues/:issue_iid/todo ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/todo @@ -685,11 +715,13 @@ Sets an estimated time of work for this issue. POST /projects/:id/issues/:issue_iid/time_estimate ``` +|-------------+---------+----------+------------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+------------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | | `duration` | string | yes | The duration in human format. e.g: 3h30m | +|-------------+---------+----------+------------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/time_estimate?duration=3h30m @@ -714,10 +746,12 @@ Resets the estimated time for this issue to 0 seconds. POST /projects/:id/issues/:issue_iid/reset_time_estimate ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_time_estimate @@ -742,11 +776,13 @@ Adds spent time for this issue POST /projects/:id/issues/:issue_iid/add_spent_time ``` +|-------------+---------+----------+------------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+------------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | | `duration` | string | yes | The duration in human format. e.g: 3h30m | +|-------------+---------+----------+------------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/add_spent_time?duration=1h @@ -771,10 +807,12 @@ Resets the total spent time for this issue to 0 seconds. POST /projects/:id/issues/:issue_iid/reset_spent_time ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/reset_spent_time @@ -797,10 +835,12 @@ Example response: GET /projects/:id/issues/:issue_iid/time_stats ``` +|-------------+---------+----------+--------------------------------------| | Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | +|-------------+---------+----------+--------------------------------------| | `id` | integer | yes | The ID of a project | | `issue_iid` | integer | yes | The internal ID of a project's issue | +|-------------+---------+----------+--------------------------------------| ```bash curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/time_stats diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 4dce5dd130a..09053e615cb 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -26,6 +26,7 @@ module API desc: 'Return issues sorted in `asc` or `desc` order.' optional :milestone, type: String, desc: 'Return issues for a specific milestone' optional :iids, type: Array[Integer], desc: 'The IID array of issues' + optional :search, type: String, desc: 'Search issues for text present in the title or description' use :pagination end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 4729adba11c..2b27ce6390a 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -12,6 +12,8 @@ describe API::Issues, api: true do let(:assignee) { create(:assignee) } let(:admin) { create(:user, :admin) } let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } + let(:issue_title) { 'foo' } + let(:issue_description) { 'closed' } let!(:closed_issue) do create :closed_issue, author: user, @@ -38,7 +40,9 @@ describe API::Issues, api: true do project: project, milestone: milestone, created_at: generate(:past_time), - updated_at: 1.hour.ago + updated_at: 1.hour.ago, + title: issue_title, + description: issue_description end let!(:label) do create(:label, title: 'label', color: '#FFAABB', project: project) @@ -61,6 +65,7 @@ describe API::Issues, api: true do context "when unauthenticated" do it "returns authentication error" do get api("/issues") + expect(response).to have_http_status(401) end end @@ -69,9 +74,7 @@ describe API::Issues, api: true do it "returns an array of issues" do get api("/issues", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + expect_paginated_array_response(size: 2) expect(json_response.first['title']).to eq(issue.title) expect(json_response.last).to have_key('web_url') end @@ -79,41 +82,43 @@ describe API::Issues, api: true do it 'returns an array of closed issues' do get api('/issues?state=closed', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an array of opened issues' do get api('/issues?state=opened', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(issue.id) end it 'returns an array of all issues' do get api('/issues?state=all', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['id']).to eq(issue.id) expect(json_response.second['id']).to eq(closed_issue.id) end + it 'returns issues matching given search string for title' do + get api("/issues?search=#{issue.title}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + + it 'returns issues matching given search string for description' do + get api("/issues?search=#{issue.description}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + it 'returns an array of labeled issues' do get api("/issues?labels=#{label.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label.title]) end @@ -126,29 +131,20 @@ describe API::Issues, api: true do get api("/issues", user), labels: "#{label.title},#{label_b.title},#{label_c.title}" - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title]) end it 'returns an empty array if no issue matches labels' do get api('/issues?labels=foo,bar', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of labeled issues matching given state' do get api("/issues?labels=#{label.title}&state=opened", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label.title]) expect(json_response.first['state']).to eq('opened') end @@ -156,47 +152,32 @@ describe API::Issues, api: true do it 'returns unlabeled issues for "No Label" label' do get api("/issues", user), labels: 'No Label' - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to be_empty end it 'returns an empty array if no issue matches labels and state filters' do get api("/issues?labels=#{label.title}&state=closed", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no issue matches milestone' do get api("/issues?milestone=#{empty_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if milestone does not exist' do get api("/issues?milestone=foo", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of issues in given milestone' do get api("/issues?milestone=#{milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['id']).to eq(issue.id) expect(json_response.second['id']).to eq(closed_issue.id) end @@ -205,49 +186,36 @@ describe API::Issues, api: true do get api("/issues?milestone=#{milestone.title}"\ '&state=closed', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an array of issues with no milestone' do get api("/issues?milestone=#{no_milestone_title}", author) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(confidential_issue.id) end it 'returns an array of issues found by iids' do get api('/issues', user), iids: [closed_issue.iid] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an empty array if iid does not exist' do get api("/issues", user), iids: [99999] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'sorts by created_at descending by default' do get api('/issues', user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -255,9 +223,8 @@ describe API::Issues, api: true do get api('/issues?sort=asc', user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort) end @@ -265,9 +232,8 @@ describe API::Issues, api: true do get api('/issues?order_by=updated_at', user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -275,9 +241,8 @@ describe API::Issues, api: true do get api('/issues?order_by=updated_at&sort=asc', user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 2) expect(response_dates).to eq(response_dates.sort) end @@ -316,7 +281,9 @@ describe API::Issues, api: true do assignee: user, project: group_project, milestone: group_milestone, - updated_at: 1.hour.ago + updated_at: 1.hour.ago, + title: issue_title, + description: issue_description end let!(:group_label) do create(:label, title: 'group_lbl', color: '#FFAABB', project: group_project) @@ -336,74 +303,65 @@ describe API::Issues, api: true do it 'returns all group issues (including opened and closed)' do get api(base_url, admin) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) end it 'returns group issues without confidential issues for non project members' do get api("#{base_url}?state=opened", non_member) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['title']).to eq(group_issue.title) end it 'returns group confidential issues for author' do get api("#{base_url}?state=opened", author) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns group confidential issues for assignee' do get api("#{base_url}?state=opened", assignee) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns group issues with confidential issues for project members' do get api("#{base_url}?state=opened", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns group confidential issues for admin' do get api("#{base_url}?state=opened", admin) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) end it 'returns an array of labeled group issues' do get api("#{base_url}?labels=#{group_label.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([group_label.title]) end it 'returns an array of labeled group issues where all labels match' do get api("#{base_url}?labels=#{group_label.title},foo,bar", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) + end + + it 'returns issues matching given search string for title' do + get api("#{base_url}?search=#{group_issue.title}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(group_issue.id) + end + + it 'returns issues matching given search string for description' do + get api("#{base_url}?search=#{group_issue.description}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(group_issue.id) end it 'returns an array of labeled issues when all labels matches' do @@ -415,65 +373,45 @@ describe API::Issues, api: true do get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}" - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title]) end it 'returns an array of issues found by iids' do get api(base_url, user), iids: [group_issue.iid] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_issue.id) end it 'returns an empty array if iid does not exist' do get api(base_url, user), iids: [99999] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no group issue matches labels' do get api("#{base_url}?labels=foo,bar", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no issue matches milestone' do get api("#{base_url}?milestone=#{group_empty_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if milestone does not exist' do get api("#{base_url}?milestone=foo", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of issues in given milestone' do get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_issue.id) end @@ -481,10 +419,7 @@ describe API::Issues, api: true do get api("#{base_url}?milestone=#{group_milestone.title}"\ '&state=closed', user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_closed_issue.id) end @@ -492,9 +427,8 @@ describe API::Issues, api: true do get api("#{base_url}?milestone=#{no_milestone_title}", user) expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(group_confidential_issue.id) end @@ -502,9 +436,8 @@ describe API::Issues, api: true do get api(base_url, user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -512,9 +445,8 @@ describe API::Issues, api: true do get api("#{base_url}?sort=asc", user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end @@ -522,9 +454,8 @@ describe API::Issues, api: true do get api("#{base_url}?order_by=updated_at", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -532,9 +463,8 @@ describe API::Issues, api: true do get api("#{base_url}?order_by=updated_at&sort=asc", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end end @@ -563,79 +493,55 @@ describe API::Issues, api: true do get api("/projects/#{restricted_project.id}/issues", non_member) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response).to eq([]) + expect_paginated_array_response(size: 0) end it 'returns project issues without confidential issues for non project members' do get api("#{base_url}/issues", non_member) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['title']).to eq(issue.title) end it 'returns project issues without confidential issues for project members with guest role' do get api("#{base_url}/issues", guest) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['title']).to eq(issue.title) end it 'returns project confidential issues for author' do get api("#{base_url}/issues", author) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns project confidential issues for assignee' do get api("#{base_url}/issues", assignee) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns project issues with confidential issues for project members' do get api("#{base_url}/issues", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns project confidential issues for admin' do get api("#{base_url}/issues", admin) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(3) + expect_paginated_array_response(size: 3) expect(json_response.first['title']).to eq(issue.title) end it 'returns an array of labeled project issues' do get api("#{base_url}/issues?labels=#{label.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label.title]) end @@ -648,74 +554,65 @@ describe API::Issues, api: true do get api("#{base_url}/issues", user), labels: "#{label.title},#{label_b.title},#{label_c.title}" - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['labels']).to eq([label_c.title, label_b.title, label.title]) end + it 'returns issues matching given search string for title' do + get api("#{base_url}/issues?search=#{issue.title}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + + it 'returns issues matching given search string for description' do + get api("#{base_url}/issues?search=#{issue.description}", user) + + expect_paginated_array_response(size: 1) + expect(json_response.first['id']).to eq(issue.id) + end + it 'returns an array of issues found by iids' do get api("#{base_url}/issues", user), iids: [issue.iid] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(issue.id) end it 'returns an empty array if iid does not exist' do get api("#{base_url}/issues", user), iids: [99999] - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if not all labels matches' do get api("#{base_url}/issues?labels=#{label.title},foo", user) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no project issue matches labels' do get api("#{base_url}/issues?labels=foo,bar", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if no issue matches milestone' do get api("#{base_url}/issues?milestone=#{empty_milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an empty array if milestone does not exist' do get api("#{base_url}/issues?milestone=foo", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) + expect_paginated_array_response(size: 0) end it 'returns an array of issues in given milestone' do get api("#{base_url}/issues?milestone=#{milestone.title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) + expect_paginated_array_response(size: 2) expect(json_response.first['id']).to eq(issue.id) expect(json_response.second['id']).to eq(closed_issue.id) end @@ -723,20 +620,14 @@ describe API::Issues, api: true do it 'returns an array of issues matching state in milestone' do get api("#{base_url}/issues?milestone=#{milestone.title}&state=closed", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(closed_issue.id) end it 'returns an array of issues with no milestone' do get api("#{base_url}/issues?milestone=#{no_milestone_title}", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect_paginated_array_response(size: 1) expect(json_response.first['id']).to eq(confidential_issue.id) end @@ -744,9 +635,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues", user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -754,9 +644,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues?sort=asc", user) response_dates = json_response.map { |issue| issue['created_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end @@ -764,9 +653,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues?order_by=updated_at", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort.reverse) end @@ -774,9 +662,8 @@ describe API::Issues, api: true do get api("#{base_url}/issues?order_by=updated_at&sort=asc", user) response_dates = json_response.map { |issue| issue['updated_at'] } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array + + expect_paginated_array_response(size: 3) expect(response_dates).to eq(response_dates.sort) end end @@ -1457,4 +1344,11 @@ describe API::Issues, api: true do include_examples 'time tracking endpoints', 'issue' end + + def expect_paginated_array_response(size: nil) + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(size) if size + end end -- cgit v1.2.1