require 'spec_helper.rb' class MyFakeError < StandardError end class FakePersonHolder include ActiveModel::Validations attr_accessor :name, :person validates_presence_of :name def valid? # doing this because we can't use validates_associated on a non-AR object, and # our logic doesn't depend on validates_associated, per se super.tap { unless person.valid? errors.add(:person,"is not valid") end } end end class FakePerson include ActiveModel::Validations attr_accessor :first_name, :last_name, :age validates_each :first_name, :last_name do |record, attr, value| record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z end validates_numericality_of :age validates_presence_of :first_name end describe Stitches::Errors do it "can be created from an exception" do exception = MyFakeError.new("OH NOES!") errors = Stitches::Errors.from_exception(exception) expect(errors.size).to eq(1) expect(errors.first.code).to eq("my_fake") expect(errors.first.message).to eq("OH NOES!") end it "renders useful JSON" do errors = Stitches::Errors.new([ Stitches::Error.new(code: "not_found", message: "Was not found, yo"), Stitches::Error.new(code: "and_you_should_feel_bad", message: "And you should feel bad about even asking"), ]) expect(errors.to_json).to eq( [ { "code" => "not_found", "message" => "Was not found, yo", }, { "code" => "and_you_should_feel_bad", "message" => "And you should feel bad about even asking", } ].to_json ) end context "creation from an active record object" do let(:object) { FakePerson.new.tap { |person| person.age = "asdfasdf" person.last_name = "zjohnson" }} it "sets reasonable messages for the fields of the object" do object.valid? errors = Stitches::Errors.from_active_record_object(object) errors_hash = JSON.parse(errors.to_json).sort_by {|_| _["code"] } expect(errors_hash[0]["code"]).to eq("age_invalid") expect(errors_hash[0]["message"]).to eq("Age is not a number") expect(errors_hash[1]["code"]).to eq("first_name_invalid") expect(errors_hash[1]["message"]).to eq("First name can't be blank") expect(errors_hash[2]["code"]).to eq("last_name_invalid") expect(errors_hash[2]["message"]).to eq("Last name starts with z.") end it "digs one level deep into the object for associated active-records" do holder = FakePersonHolder.new holder.name = nil holder.person = object holder.valid? errors = Stitches::Errors.from_active_record_object(holder) errors_hash = JSON.parse(errors.to_json).sort_by {|_| _["code"] } expect(errors_hash[0]["code"]).to eq("name_invalid") expect(errors_hash[0]["message"]).to eq("Name can't be blank") expect(errors_hash[1]["code"]).to eq("person_invalid") expect(errors_hash[1]["message"]).to eq("Age is not a number, First name can't be blank, Last name starts with z.") end it "works with nested attributes" do object.errors.add("something.nested", "is required") errors = Stitches::Errors.from_active_record_object(object) errors_hash = JSON.parse(errors.to_json).sort_by {|_| _["code"] } expect(errors_hash[0]["code"]).to eq("something-nested_invalid") expect(errors_hash[0]["message"]).to eq("Something nested is required") end end end