spec/grape/validations_spec.rb in grape-1.5.0 vs spec/grape/validations_spec.rb in grape-1.5.1

- old
+ new

@@ -881,9 +881,277 @@ requires(:required_subitems, type: Array) { requires :value } end end expect(declared_params).to eq([items: [:key, { optional_subitems: [:value] }, { required_subitems: [:value] }]]) end + + context <<~DESC do + Issue occurs whenever: + * param structure with at least three levels + * 1st level item is a required Array that has >1 entry with an optional item present and >1 entry with an optional item missing + * 2nd level is an optional Array or Hash + * 3rd level is a required item (can be any type) + * additional levels do not effect the issue from occuring + DESC + + it "example based off actual real world use case" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Array do + requires :batches, type: Array do + requires :batch_no, type: String + end + end + end + end + + subject.get '/validate_required_arrays_under_optional_arrays' do + 'validate_required_arrays_under_optional_arrays works!' + end + + data = { + orders: [ + { id: 77, drugs: [{batches: [{batch_no: "A1234567"}]}]}, + { id: 70 } + ] + } + + get '/validate_required_arrays_under_optional_arrays', data + expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!") + expect(last_response.status).to eq(200) + end + + it "simplest example using Arry -> Array -> Hash -> String" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Array do + requires :batch_no, type: String + end + end + end + + subject.get '/validate_required_arrays_under_optional_arrays' do + 'validate_required_arrays_under_optional_arrays works!' + end + + data = { + orders: [ + { id: 77, drugs: [{batch_no: "A1234567"}]}, + { id: 70 } + ] + } + + get '/validate_required_arrays_under_optional_arrays', data + expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!") + expect(last_response.status).to eq(200) + end + + it "simplest example using Arry -> Hash -> String" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Hash do + requires :batch_no, type: String + end + end + end + + subject.get '/validate_required_arrays_under_optional_arrays' do + 'validate_required_arrays_under_optional_arrays works!' + end + + data = { + orders: [ + { id: 77, drugs: {batch_no: "A1234567"}}, + { id: 70 } + ] + } + + get '/validate_required_arrays_under_optional_arrays', data + expect(last_response.body).to eq("validate_required_arrays_under_optional_arrays works!") + expect(last_response.status).to eq(200) + end + + it "correctly indexes invalida data" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Array do + requires :batch_no, type: String + requires :quantity, type: Integer + end + end + end + + subject.get '/correctly_indexes' do + 'correctly_indexes works!' + end + + data = { + orders: [ + { id: 70 }, + { id: 77, drugs: [{batch_no: "A1234567", quantity: 12}, {batch_no: "B222222"}]} + ] + } + + get '/correctly_indexes', data + expect(last_response.body).to eq("orders[1][drugs][1][quantity] is missing") + expect(last_response.status).to eq(400) + end + + context "multiple levels of optional and requires settings" do + before do + subject.params do + requires :top, type: Array do + requires :top_id, type: Integer, allow_blank: false + optional :middle_1, type: Array do + requires :middle_1_id, type: Integer, allow_blank: false + optional :middle_2, type: Array do + requires :middle_2_id, type: String, allow_blank: false + optional :bottom, type: Array do + requires :bottom_id, type: Integer, allow_blank: false + end + end + end + end + end + + subject.get '/multi_level' do + 'multi_level works!' + end + end + + it "with valid data" do + data = { + top: [ + { top_id: 1, middle_1: [ + {middle_1_id: 11}, {middle_1_id: 12, middle_2: [ + {middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: 1221}]}]}]}, + { top_id: 2, middle_1: [ + {middle_1_id: 21}, {middle_1_id: 22, middle_2: [ + {middle_2_id: 221}]}]}, + { top_id: 3, middle_1: [ + {middle_1_id: 31}, {middle_1_id: 32}]}, + { top_id: 4 } + ] + } + + get '/multi_level', data + expect(last_response.body).to eq("multi_level works!") + expect(last_response.status).to eq(200) + end + + it "with invalid data" do + data = { + top: [ + { top_id: 1, middle_1: [ + {middle_1_id: 11}, {middle_1_id: 12, middle_2: [ + {middle_2_id: 121}, {middle_2_id: 122, bottom: [{bottom_id: nil}]}]}]}, + { top_id: 2, middle_1: [ + {middle_1_id: 21}, {middle_1_id: 22, middle_2: [{middle_2_id: nil}]}]}, + { top_id: 3, middle_1: [ + {middle_1_id: nil}, {middle_1_id: 32}]}, + { top_id: nil, missing_top_id: 4 } + ] + } + # debugger + get '/multi_level', data + expect(last_response.body.split(", ")).to match_array([ + "top[3][top_id] is empty", + "top[2][middle_1][0][middle_1_id] is empty", + "top[1][middle_1][1][middle_2][0][middle_2_id] is empty", + "top[0][middle_1][1][middle_2][1][bottom][0][bottom_id] is empty" + ]) + expect(last_response.status).to eq(400) + end + end + end + + it "exactly_one_of" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Hash do + optional :batch_no, type: String + optional :batch_id, type: String + exactly_one_of :batch_no, :batch_id + end + end + end + + subject.get '/exactly_one_of' do + 'exactly_one_of works!' + end + + data = { + orders: [ + { id: 77, drugs: {batch_no: "A1234567"}}, + { id: 70 } + ] + } + + get '/exactly_one_of', data + expect(last_response.body).to eq("exactly_one_of works!") + expect(last_response.status).to eq(200) + end + + it "at_least_one_of" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Hash do + optional :batch_no, type: String + optional :batch_id, type: String + at_least_one_of :batch_no, :batch_id + end + end + end + + subject.get '/at_least_one_of' do + 'at_least_one_of works!' + end + + data = { + orders: [ + { id: 77, drugs: {batch_no: "A1234567"}}, + { id: 70 } + ] + } + + get '/at_least_one_of', data + expect(last_response.body).to eq("at_least_one_of works!") + expect(last_response.status).to eq(200) + end + + it "all_or_none_of" do + subject.params do + requires :orders, type: Array do + requires :id, type: Integer + optional :drugs, type: Hash do + optional :batch_no, type: String + optional :batch_id, type: String + all_or_none_of :batch_no, :batch_id + end + end + end + + subject.get '/all_or_none_of' do + 'all_or_none_of works!' + end + + data = { + orders: [ + { id: 77, drugs: {batch_no: "A1234567", batch_id: "12"}}, + { id: 70 } + ] + } + + get '/all_or_none_of', data + expect(last_response.body).to eq("all_or_none_of works!") + expect(last_response.status).to eq(200) + end end context 'multiple validation errors' do before do subject.params do