describe Frenetic::Resource do let(:client) { Frenetic.new(url:'http://example.org') } let(:resource) { MyResource.new } let(:other_resource) { MyOtherResource.new } let(:description_stub) do Frenetic::HalJson::ResponseWrapper.new('resources' => { 'schema' => { 'my_resource' => { 'properties' => { 'foo' => 'string', 'baz' => 'integer' } }, 'my_other_resource' => { 'properties' => { 'bar' => 'integer' } } } } ) end before do client.stub(:description).and_return description_stub described_class.stub(:api).and_return client stub_const 'MyResource', Class.new(described_class) stub_const 'MyOtherResource', Class.new(described_class) end subject { resource } describe '#attributes' do subject { resource.attributes } it { should include 'foo' => nil } it { should include 'baz' => nil } end describe '#to_hash' do subject { resource.to_hash } it { should == resource.attributes } end context "created from a Hash" do let(:resource) { MyResource.new( foo: 'bar' ) } it { should respond_to(:foo) } it { should respond_to(:foo=) } its(:links) { should be_a Hash } its(:links) { should be_empty } context 'other subclasses' do subject { other_resource } it { should_not respond_to(:foo) } it { should_not respond_to(:foo=) } end end context "created from a HAL-JSON response" do let(:api_response) do { '_links' => { '_self' => { '_href' => 'bar' } }, 'foo' => 1, 'bar' => 2 } end let(:wrapped_response) do Frenetic::HalJson::ResponseWrapper.new(api_response) end let(:resource_a) { MyResource.new( wrapped_response ) } let(:resource_b) { MyResource.new } before do resource_a && resource_b end context "initialized with data" do subject { resource_a } its(:foo) { should == 1 } it { should_not respond_to(:bar) } its(:links) { should_not be_empty } end context "intiailized in sequence without data" do subject { resource_b } it { should respond_to(:foo) } it { should_not respond_to(:bar) } its(:links) { should be_empty } end context "with embedded resources" do let(:api_response) do { '_links' => { '_self' => { '_href' => 'bar' } }, 'foo' => 1, '_embedded' => embed } end subject { resource_a } context 'that have a Resource representation' do subject { super().my_other_resource } let(:embed) do { 'my_other_resource' => { 'bar' => 123 } } end its(:bar) { should == 123 } end context 'that do not have a Resource representation' do subject { super().foo } let(:embed) do { 'foo' => { 'bar' => 'baz' } } end it { should include 'bar' => 'baz' } end end end describe ".api_client" do before do described_class.unstub! :api end subject { MyResource } context "with a block" do before { subject.api_client { client } } it "should reference the defined API client" do subject.api.should eq client MyOtherResource.should_not respond_to :api end end context "with an argument" do before { MyResource.api_client client } it "should reference the defined API client" do subject.api.should eq client MyOtherResource.should_not respond_to :api end end end describe ".schema" do subject { resource.class.schema } context "with a defined API Client" do before do client.stub(:description).and_return description_stub resource.class.api_client client end it "should return the schema for the specific resource" do subject.should == description_stub.resources.schema.my_resource.properties end end context "without a defined API Client" do before { described_class.stub(:respond_to?).with(:api).and_return false } it "should raise an error" do expect { subject }.to raise_error(Frenetic::MissingAPIReference) end end end end