|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require 'rails_helper' |
| 4 | + |
| 5 | +RSpec.describe Api::V2::PlansController do |
| 6 | + include ApiHelper |
| 7 | + include Mocks::ApiV2JsonSamples |
| 8 | + include Webmocks |
| 9 | + include IdentifierHelper |
| 10 | + |
| 11 | + context 'OAuth (authorization_code grant type) — on behalf of a user' do |
| 12 | + before do |
| 13 | + @user = create(:user) |
| 14 | + @client = create(:oauth_application) |
| 15 | + token = mock_authorization_code_token(oauth_application: @client, user: @user).token |
| 16 | + |
| 17 | + @headers = { |
| 18 | + Accept: 'application/json', |
| 19 | + 'Content-Type': 'application/json', |
| 20 | + Authorization: "Bearer #{token}" |
| 21 | + } |
| 22 | + end |
| 23 | + |
| 24 | + def fetch_plans_json_response |
| 25 | + get(api_v2_plans_path, headers: @headers) |
| 26 | + expect(response).to render_template('api/v2/_standard_response') |
| 27 | + expect(response).to render_template('api/v2/plans/index') |
| 28 | + JSON.parse(response.body).with_indifferent_access |
| 29 | + end |
| 30 | + |
| 31 | + describe 'GET /api/v2/plans (index)' do |
| 32 | + context 'an invalid API token is included' do |
| 33 | + it 'returns a 401 and the expected Oauth 2.0 headers' do |
| 34 | + # Swap actual token with a random string |
| 35 | + @headers['Authorization'] = "Bearer #{SecureRandom.uuid}" |
| 36 | + get(api_v2_plans_path, headers: @headers) |
| 37 | + |
| 38 | + expect(response.code).to eql('401') |
| 39 | + expect(response.body).to be_empty |
| 40 | + |
| 41 | + # Expect Doorkeeper to return the standard OAuth 2.0 WWW-Authenticate header for invalid tokens |
| 42 | + expect(response.headers['WWW-Authenticate']).to match( |
| 43 | + /Bearer realm="Doorkeeper", error="invalid_token", error_description="The access token is invalid"/ |
| 44 | + ) |
| 45 | + end |
| 46 | + end |
| 47 | + |
| 48 | + context 'a valid API token is included' do |
| 49 | + let(:json) { fetch_plans_json_response } |
| 50 | + it 'returns a 200 and the expected response body' do |
| 51 | + # Items array is empty |
| 52 | + expect(json[:items]).to eq([]) |
| 53 | + |
| 54 | + # total_items reflects that nothing is returned |
| 55 | + expect(json[:total_items]).to eq(0) |
| 56 | + |
| 57 | + # Status code and message are correct |
| 58 | + expect(json[:code]).to eq(200) |
| 59 | + expect(json[:message]).to eq('OK') |
| 60 | + |
| 61 | + # Server and source are present and sensible |
| 62 | + expect(json[:server]).to eq(ApplicationService.application_name) |
| 63 | + expect(json[:source]).to eq('GET /api/v2/plans') |
| 64 | + |
| 65 | + # Time is present and parseable |
| 66 | + expect { Time.iso8601(json[:time]) }.not_to raise_error |
| 67 | + |
| 68 | + # Client is included |
| 69 | + expect(json[:client]).to eq(@client.name) |
| 70 | + end |
| 71 | + |
| 72 | + it 'returns an empty array if no plans are available' do |
| 73 | + # Items array is empty |
| 74 | + expect(json[:items]).to eq([]) |
| 75 | + |
| 76 | + # total_items reflects that nothing is returned |
| 77 | + expect(json[:total_items]).to eq(0) |
| 78 | + end |
| 79 | + |
| 80 | + it 'returns the expected plans' do |
| 81 | + # See `app/policies/api/v2/plans_policy.rb for plans included/excluded via `GET api/v2/plans` |
| 82 | + |
| 83 | + # Create the included plans |
| 84 | + included_plans = [create(:plan, org: @user.org), create(:plan)] |
| 85 | + included_plans[0].add_user!(@user.id, :creator) |
| 86 | + # Add multiple roles for testing (ensure duplicate plans will not returned) |
| 87 | + included_plans[1].add_user!(@user.id, :editor) |
| 88 | + included_plans[1].add_user!(@user.id, :commenter) |
| 89 | + |
| 90 | + # Created the excluded plans |
| 91 | + create(:plan, :creator, org: @user.org) |
| 92 | + inactive_plan = create(:plan, :creator) |
| 93 | + inactive_plan.add_user!(@user.id, :editor) |
| 94 | + Role.where(plan_id: inactive_plan.id, user_id: @user.id).update!(active: false) |
| 95 | + |
| 96 | + expect(json[:items].length).to be(included_plans.length) |
| 97 | + |
| 98 | + # Api::V2::PlanPresenter.identifier uses api_v2_plan_url(@plan) to set the "identifier". |
| 99 | + # That url is constructed using `request.host` / "www.example.com" |
| 100 | + # api_v2_plan_url(@plan) within this test will construct the url via |
| 101 | + # default_url_options[:host] / "example.org" |
| 102 | + # Because the urls are misaligned, we will only compare the paths here. |
| 103 | + # TODO: Consider aligning default_url_options[:host] (in test.rb) with `request.host` |
| 104 | + returned_identifiers = json[:items].map { |item| item[:dmp][:dmp_id][:identifier] } |
| 105 | + returned_paths = returned_identifiers.map { |url| URI(url).path } |
| 106 | + expected_paths = included_plans.map { |plan| api_v2_plan_path(plan) } |
| 107 | + expect(returned_paths).to eq(expected_paths) |
| 108 | + end |
| 109 | + |
| 110 | + it 'allows for paging' do |
| 111 | + original_page_size = Rails.configuration.x.application.api_max_page_size |
| 112 | + Rails.configuration.x.application.api_max_page_size = 10 |
| 113 | + |
| 114 | + create_list(:plan, 11, :publicly_visible) do |plan| |
| 115 | + plan.add_user!(@user.id, :commenter) |
| 116 | + end |
| 117 | + json = fetch_plans_json_response |
| 118 | + |
| 119 | + test_paging(json: json, headers: @headers) |
| 120 | + |
| 121 | + Rails.configuration.x.application.api_max_page_size = original_page_size |
| 122 | + end |
| 123 | + end |
| 124 | + end |
| 125 | + end |
| 126 | +end |
0 commit comments