# frozen_string_literal: true require 'acceptance_helper' RSpec.describe 'Categories', type: :acceptance do # Needed to initialize documentation for this type of request. # It should come before all the other calls (it will let the metadata # class know which resource we're dealing with) resource 'Categories', 'Manage categories in a group' # Define an entity that can be returned by an URL. entity :category, id: { type: :integer, description: 'The id' }, name: { type: :string, description: 'The name' }, group_id: { type: :number, description: 'Concerned group' }, created_at: { type: :datetime, description: 'Creation date' }, updated_at: { type: :datetime, description: 'Modification date' }, url: { type: :string, description: 'URL to this category' } entity :error, error: { type: :string, name: 'The error' } entity :form_error, errors: { type: :object, description: 'Form errors', attributes: { name: { type: :array, description: 'Name errors' }, group: { type: :array, description: 'Group errors' }, } } # Some vars to use in the tests let(:current_user) { FactoryBot.create :user_active } let(:group) { current_user.groups.first } let(:group_id) { group.id } let(:category) { FactoryBot.create :category, user: current_user, group: group } # Declare a path accessed with a given method # Their values can be declared with a "let(:var){ value }" statement, # or passed to "visit" method (see "for_code 404") on_get '/api/groups/:group_id/categories', 'Categories defined in the given group' do # Declare path parameters for documentation path_params group_id: { type: :integer, description: 'Target group identifier' } # Expectations for the given HTTP status for_code 200, 'Success' do |example| FactoryBot.create_list :category, 2, user: current_user, group: group # This method is not built-in; check: ../README.md sign_in current_user # Actually visit the path. It will expect the given code and a # content of type "application/JSON" (except for 204: no content # statuses) visit example # Custom matcher: have_many will expect a body with an array of # the given entity. All entries in the response will have its keys # checked (not the content type). # The `defined` method will get the correct entity for comparison expect(response).to have_many defined :category # Other expectations expect(JSON.parse(response.body).count).to eq 2 end for_code 404, 'Not found (not owned)' do |example| sign_in current_user group_id = FactoryBot.create(:user_active).groups.first.id visit example, path_params: { group_id: group_id } expect(response).to have_one defined :error end for_code 401, 'Not authorized' do |example| visit example expect(response).to have_one defined :error end end on_get '/api/groups/:group_id/categories/:id', 'Get category' do path_params group_id: { type: :integer, description: 'Target group identifier' }, id: { type: :integer, description: 'Category id' } let(:id) { category.id } for_code 200, 'Success' do |example| sign_in current_user visit example expect(response).to have_one defined :category end for_code 401, 'Not authorized' do |example| visit example expect(response).to have_one defined :error end for_code 404, 'Not found' do |example| sign_in current_user visit example, path_params: { id: 0 } expect(response).to have_one defined :error end end on_post '/api/groups/:group_id/categories', 'Creates a category' do path_params group_id: { type: :integer, description: 'Target group identifier' } request_params category: { type: :object, required: true, attributes: { name: { type: :string, required: true, description: 'The name' }, } } let(:id) { category.id } for_code 201, 'Success' do |example| sign_in current_user visit example, payload: { category: { name: 'New category' } } expect(response).to have_one defined :category end for_code 422, 'Form error' do |example| sign_in current_user visit example, payload: { category: {} } expect(response).to have_one defined :form_error end end on_put '/api/groups/:group_id/categories/:id', 'Updates a category' do path_params group_id: { type: :integer, description: 'Target group identifier' }, id: { type: :integer, description: 'Category id' } let(:id) { category.id } request_params category: { type: :object, required: true, description: 'New category attributes', attributes: { name: { type: :string, required: false, description: 'The new name' }, } } for_code 200, 'Success' do |example| sign_in current_user visit example, payload: { category: { name: 'New name' } } expect(response).to have_one defined :category end end on_delete '/api/groups/:group_id/categories/:id', 'Deletes a category' do path_params group_id: { type: :integer, description: 'Target group identifier' }, id: { type: :integer, description: 'Category id' } let(:id) { category.id } for_code 204, 'Success' do |example| sign_in current_user visit example # Not checking content for 204 responses end end end