cardmagic-etsy 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +13 -0
  4. data/Gemfile +11 -0
  5. data/LICENSE +9 -0
  6. data/README.md +348 -0
  7. data/Rakefile +12 -0
  8. data/etsy.gemspec +34 -0
  9. data/lib/etsy.rb +223 -0
  10. data/lib/etsy/about.rb +15 -0
  11. data/lib/etsy/address.rb +47 -0
  12. data/lib/etsy/attribute_value.rb +46 -0
  13. data/lib/etsy/basic_client.rb +32 -0
  14. data/lib/etsy/category.rb +84 -0
  15. data/lib/etsy/country.rb +27 -0
  16. data/lib/etsy/favorite_listing.rb +26 -0
  17. data/lib/etsy/image.rb +44 -0
  18. data/lib/etsy/listing.rb +296 -0
  19. data/lib/etsy/model.rb +127 -0
  20. data/lib/etsy/payment_template.rb +33 -0
  21. data/lib/etsy/profile.rb +49 -0
  22. data/lib/etsy/receipt.rb +37 -0
  23. data/lib/etsy/request.rb +150 -0
  24. data/lib/etsy/response.rb +128 -0
  25. data/lib/etsy/section.rb +16 -0
  26. data/lib/etsy/secure_client.rb +131 -0
  27. data/lib/etsy/shipping_info.rb +27 -0
  28. data/lib/etsy/shipping_template.rb +41 -0
  29. data/lib/etsy/shop.rb +88 -0
  30. data/lib/etsy/transaction.rb +29 -0
  31. data/lib/etsy/user.rb +109 -0
  32. data/lib/etsy/variation/property_set.rb +71 -0
  33. data/lib/etsy/verification_request.rb +17 -0
  34. data/lib/etsy/version.rb +3 -0
  35. data/test/fixtures/about/getAbout.json +16 -0
  36. data/test/fixtures/address/getUserAddresses.json +12 -0
  37. data/test/fixtures/attribute_value/findAllListingPropertyValues.json +44 -0
  38. data/test/fixtures/category/findAllSubCategoryChildren.json +78 -0
  39. data/test/fixtures/category/findAllTopCategory.json +347 -0
  40. data/test/fixtures/category/findAllTopCategory.single.json +18 -0
  41. data/test/fixtures/category/findAllTopCategoryChildren.json +308 -0
  42. data/test/fixtures/category/getCategory.multiple.json +28 -0
  43. data/test/fixtures/category/getCategory.single.json +18 -0
  44. data/test/fixtures/country/getCountry.json +1 -0
  45. data/test/fixtures/favorite_listing/findAllFavoriteListings.json +1 -0
  46. data/test/fixtures/image/findAllListingImages.json +102 -0
  47. data/test/fixtures/listing/findAllListingActive.category.json +827 -0
  48. data/test/fixtures/listing/findAllShopListings.json +69 -0
  49. data/test/fixtures/listing/getListing.multiple.json +1 -0
  50. data/test/fixtures/listing/getListing.single.includeImages.json +1 -0
  51. data/test/fixtures/listing/getListing.single.json +1 -0
  52. data/test/fixtures/payment_template/getPaymentTemplate.json +1 -0
  53. data/test/fixtures/profile/new.json +28 -0
  54. data/test/fixtures/receipt/findAllShopReceipts.json +28 -0
  55. data/test/fixtures/section/getShopSection.json +18 -0
  56. data/test/fixtures/shipping_info/getShippingInfo.json +1 -0
  57. data/test/fixtures/shipping_template/getShippingTemplate.json +1 -0
  58. data/test/fixtures/shop/findAllShop.json +1 -0
  59. data/test/fixtures/shop/findAllShop.single.json +1 -0
  60. data/test/fixtures/shop/getShop.multiple.json +1 -0
  61. data/test/fixtures/shop/getShop.single.json +34 -0
  62. data/test/fixtures/transaction/findAllShopTransactions.json +1 -0
  63. data/test/fixtures/user/getUser.multiple.json +29 -0
  64. data/test/fixtures/user/getUser.single.json +13 -0
  65. data/test/fixtures/user/getUser.single.private.json +18 -0
  66. data/test/fixtures/user/getUser.single.withProfile.json +38 -0
  67. data/test/fixtures/user/getUser.single.withShops.json +41 -0
  68. data/test/test_helper.rb +45 -0
  69. data/test/unit/etsy/address_test.rb +61 -0
  70. data/test/unit/etsy/attribute_value_test.rb +67 -0
  71. data/test/unit/etsy/basic_client_test.rb +30 -0
  72. data/test/unit/etsy/category_test.rb +106 -0
  73. data/test/unit/etsy/country_test.rb +64 -0
  74. data/test/unit/etsy/favorite_listing_test.rb +44 -0
  75. data/test/unit/etsy/image_test.rb +51 -0
  76. data/test/unit/etsy/listing_test.rb +268 -0
  77. data/test/unit/etsy/model_test.rb +64 -0
  78. data/test/unit/etsy/payment_template_test.rb +68 -0
  79. data/test/unit/etsy/profile_test.rb +111 -0
  80. data/test/unit/etsy/receipt_test.rb +107 -0
  81. data/test/unit/etsy/request_test.rb +190 -0
  82. data/test/unit/etsy/response_test.rb +175 -0
  83. data/test/unit/etsy/section_test.rb +28 -0
  84. data/test/unit/etsy/secure_client_test.rb +132 -0
  85. data/test/unit/etsy/shipping_info_test.rb +24 -0
  86. data/test/unit/etsy/shipping_template_test.rb +24 -0
  87. data/test/unit/etsy/shop_about_test.rb +43 -0
  88. data/test/unit/etsy/shop_test.rb +116 -0
  89. data/test/unit/etsy/transaction_test.rb +61 -0
  90. data/test/unit/etsy/user_test.rb +250 -0
  91. data/test/unit/etsy/verification_request_test.rb +26 -0
  92. data/test/unit/etsy_test.rb +173 -0
  93. metadata +293 -0
@@ -0,0 +1,175 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ResponseTest < Test::Unit::TestCase
5
+
6
+ context "An instance of the Response class" do
7
+
8
+ should "be able to return the total" do
9
+ r = Response.new(stub(:body => '{ "count": 42 }'))
10
+
11
+ r.total.should == 42
12
+ end
13
+
14
+ should "be able to decode the JSON data to a hash" do
15
+ data = '{ "foo":"bar" }'
16
+
17
+ r = Response.new(stub(:body => data))
18
+ r.to_hash.should == {'foo' => 'bar'}
19
+ end
20
+
21
+ should "only decode the JSON data once" do
22
+ JSON.expects(:parse).once.returns({})
23
+
24
+ r = Response.new(stub(:body => '{ "foo":"bar" }'))
25
+ 2.times { r.to_hash }
26
+ end
27
+
28
+ should "have a record count when the response is not paginated" do
29
+ raw_response = mock
30
+ raw_response.stubs(:body => '{ "count": 1 }')
31
+ r = Response.new(raw_response)
32
+
33
+ r.count.should == 1
34
+ end
35
+
36
+ should "have a record count when the response is paginated" do
37
+ raw_response = mock
38
+ raw_response.stubs(:body => '{ "count": 100, "results": [{},{}], "pagination": {} }')
39
+ r = Response.new(raw_response)
40
+
41
+ r.count.should == 2
42
+ end
43
+
44
+ should "return a count of 0 when the response is paginated and the results are empty" do
45
+ raw_response = mock
46
+ raw_response.stubs(:body => '{ "count": 100, "results": null, "pagination": {} }')
47
+ r = Response.new(raw_response)
48
+
49
+ r.count.should == 0
50
+ end
51
+
52
+ should "return an array if there are multiple results entries" do
53
+ r = Response.new('')
54
+ r.expects(:code).with().returns('200')
55
+ r.expects(:count).with().returns(2)
56
+ r.expects(:to_hash).with().returns('results' => %w(one two))
57
+
58
+ r.result.should == %w(one two)
59
+ end
60
+
61
+ should "return a single value for results if there is only 1 result" do
62
+ r = Response.new('')
63
+ r.expects(:code).with().returns('200')
64
+ r.expects(:count).with().returns(1)
65
+ r.expects(:to_hash).with().returns('results' => ['foo'])
66
+
67
+ r.result.should == 'foo'
68
+ end
69
+
70
+ should "provide the complete raw body" do
71
+ raw_response = mock
72
+ raw_response.stubs(:body => "I am not JSON")
73
+ r = Response.new(raw_response)
74
+
75
+ r.body.should == 'I am not JSON'
76
+ end
77
+
78
+ should "raise an invalid JSON exception if the response is not json" do
79
+ raw_response = mock
80
+ raw_response.stubs(:body => "I am not JSON", :code => 500)
81
+ r = Response.new(raw_response)
82
+
83
+ exception = assert_raises(Etsy::EtsyJSONInvalid) { r.to_hash }
84
+ assert_equal( 500, exception.code )
85
+ assert_equal( "I am not JSON", exception.data )
86
+ end
87
+
88
+ should "raise OAuthTokenRevoked" do
89
+ raw_response = mock
90
+ raw_response.stubs(:body => "oauth_problem=token_revoked")
91
+ r = Response.new(raw_response)
92
+
93
+ lambda { r.to_hash }.should raise_error(Etsy::OAuthTokenRevoked)
94
+ end
95
+
96
+ should "raise MissingShopID" do
97
+ raw_response = mock
98
+ raw_response.stubs(:body => "something Shop with PK shop_id something")
99
+ r = Response.new(raw_response)
100
+
101
+ lambda { r.to_hash }.should raise_error(Etsy::MissingShopID)
102
+ end
103
+
104
+ should "raise InvalidUserID" do
105
+ raw_response = mock
106
+ raw_response.stubs(:body => "'someguy' is not a valid user_id")
107
+ r = Response.new(raw_response)
108
+
109
+ lambda { r.to_hash }.should raise_error(Etsy::InvalidUserID)
110
+ end
111
+
112
+ should "raise TemporaryIssue" do
113
+ raw_response = mock
114
+ raw_response.stubs(:body => "something Temporary Etsy issue something")
115
+ r = Response.new(raw_response)
116
+
117
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
118
+ end
119
+
120
+ should "raise ResourceUnavailable" do
121
+ raw_response = mock
122
+ raw_response.stubs(:body => "something Resource temporarily unavailable something")
123
+ r = Response.new(raw_response)
124
+
125
+ lambda { r.to_hash }.should raise_error(Etsy::ResourceUnavailable)
126
+ end
127
+
128
+ should "raise ExceededRateLimit" do
129
+ raw_response = mock
130
+ raw_response.stubs(:body => "something You have exceeded your API limit something")
131
+ r = Response.new(raw_response)
132
+
133
+ lambda { r.to_hash }.should raise_error(Etsy::ExceededRateLimit)
134
+ end
135
+
136
+ should "provide the code" do
137
+ raw_response = mock
138
+ raw_response.expects(:code => "400")
139
+ r = Response.new(raw_response)
140
+
141
+ r.code.should == '400'
142
+ end
143
+
144
+ should "consider a code of 2xx successful" do
145
+ raw_response = mock
146
+
147
+ raw_response.expects(:code => "200")
148
+ r = Response.new(raw_response)
149
+ r.should be_success
150
+
151
+ raw_response.expects(:code => "201")
152
+ r = Response.new(raw_response)
153
+ r.should be_success
154
+ end
155
+
156
+ should "consider a code of 4xx unsuccessful" do
157
+ raw_response = mock
158
+
159
+ raw_response.expects(:code => "404")
160
+ r = Response.new(raw_response)
161
+ r.should_not be_success
162
+ end
163
+
164
+ should "consider a code of 5xx unsuccessful" do
165
+ raw_response = mock
166
+
167
+ raw_response.expects(:code => "500")
168
+ r = Response.new(raw_response)
169
+ r.should_not be_success
170
+ end
171
+ end
172
+
173
+
174
+ end
175
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class SectionTest < Test::Unit::TestCase
5
+ context "An instance of the Section class" do
6
+ setup do
7
+ data = read_fixture('section/getShopSection.json')
8
+ @section = Section.new(data.first)
9
+ end
10
+
11
+ should "have an id" do
12
+ @section.id.should == 11045327
13
+ end
14
+
15
+ should "have an title" do
16
+ @section.title.should == "Blue Items"
17
+ end
18
+
19
+ should "have an user_id" do
20
+ @section.user_id.should == 9569349
21
+ end
22
+
23
+ should "have an active_listing_count" do
24
+ @section.active_listing_count.should == 7
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,132 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class SecureClientTest < Test::Unit::TestCase
5
+
6
+ context "An instance of the SecureClient class" do
7
+
8
+ should "be able to generate an OAuth consumer for the sandbox" do
9
+ Etsy.stubs(:environment).returns :sandbox
10
+ Etsy.stubs(:host).returns 'sandbox'
11
+ Etsy.stubs(:api_key).returns('key')
12
+ Etsy.stubs(:api_secret).returns('secret')
13
+ Etsy.stubs(:permission_scopes).returns(['scope_one', 'scope_two'])
14
+
15
+ OAuth::Consumer.stubs(:new).with('key', 'secret', {
16
+ :site => 'https://sandbox',
17
+ :request_token_path => '/v2/oauth/request_token?scope=scope_one+scope_two',
18
+ :access_token_path => '/v2/oauth/access_token',
19
+ }).returns('consumer')
20
+
21
+ client = SecureClient.new
22
+
23
+ client.consumer.should == 'consumer'
24
+ end
25
+
26
+ should "be able to generate an OAuth consumer in production" do
27
+ Etsy.stubs(:environment).returns :production
28
+ Etsy.stubs(:host).returns 'production'
29
+ Etsy.stubs(:api_key).returns('key')
30
+ Etsy.stubs(:api_secret).returns('secret')
31
+ Etsy.stubs(:permission_scopes).returns(['scope_one', 'scope_two'])
32
+
33
+ OAuth::Consumer.stubs(:new).with('key', 'secret', {
34
+ :site => 'https://production',
35
+ :request_token_path => '/v2/oauth/request_token?scope=scope_one+scope_two',
36
+ :access_token_path => '/v2/oauth/access_token',
37
+ }).returns('consumer')
38
+
39
+ client = SecureClient.new
40
+
41
+ client.consumer.should == 'consumer'
42
+ end
43
+
44
+
45
+
46
+ should "be able to generate a request token" do
47
+ Etsy.stubs(:callback_url).with().returns('callback_url')
48
+ consumer = stub() {|c| c.stubs(:get_request_token).with(:oauth_callback => 'callback_url').returns('toke') }
49
+
50
+ client = SecureClient.new
51
+ client.stubs(:consumer).returns(consumer)
52
+
53
+ client.request_token.should == 'toke'
54
+ end
55
+
56
+ context "with request data" do
57
+ setup do
58
+ @client = SecureClient.new(:request_token => 'toke', :request_secret => 'secret', :verifier => 'verify')
59
+ @client.stubs(:consumer).returns('consumer')
60
+ end
61
+
62
+ should "be able to generate an oauth client" do
63
+ request_token = stub()
64
+ request_token.stubs(:get_access_token).with(:oauth_verifier => 'verify').returns('client')
65
+
66
+ OAuth::RequestToken.stubs(:new).with('consumer', 'toke', 'secret').returns(request_token)
67
+
68
+ @client.client_from_request_data.should == 'client'
69
+ end
70
+
71
+ should "know to generate a client from request data" do
72
+ @client.stubs(:client_from_request_data).returns('client')
73
+ @client.client.should == 'client'
74
+ end
75
+ end
76
+
77
+ context "with access data" do
78
+ setup do
79
+ @client = SecureClient.new(:access_token => 'toke', :access_secret => 'secret')
80
+ @client.stubs(:consumer).returns('consumer')
81
+ end
82
+
83
+ should "know the :access_token" do
84
+ @client.access_token.should == 'toke'
85
+ end
86
+
87
+ should "know the access secret" do
88
+ @client.access_secret.should == 'secret'
89
+ end
90
+
91
+ should "be able to generate an oauth client" do
92
+ OAuth::AccessToken.stubs(:new).with('consumer', 'toke', 'secret').returns('client')
93
+ @client.client_from_access_data.should == 'client'
94
+ end
95
+
96
+ should "be able to generate a client" do
97
+ @client.stubs(:client_from_access_data).returns('client')
98
+ @client.client.should == 'client'
99
+ end
100
+ end
101
+
102
+ context "with a client" do
103
+ setup do
104
+ @client = SecureClient.new
105
+ @client.stubs(:client).returns(stub(:token => 'toke', :secret => 'secret'))
106
+ end
107
+
108
+ should "know the access token" do
109
+ @client.access_token.should == 'toke'
110
+ end
111
+
112
+ should "know the access_secret" do
113
+ @client.access_secret.should == 'secret'
114
+ end
115
+ end
116
+
117
+ should "delegate :get to :client" do
118
+ url = 'http://etsy.com/'
119
+
120
+ oauth_client = stub()
121
+ oauth_client.stubs(:get).with(url).returns('something')
122
+
123
+ client = SecureClient.new
124
+ client.stubs(:client).returns(oauth_client)
125
+
126
+ client.get(url).should == 'something'
127
+ end
128
+
129
+ end
130
+
131
+ end
132
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ShippingInfoTest < Test::Unit::TestCase
5
+ context "An instance of the ShippingInfo class" do
6
+ setup do
7
+ data = read_fixture('shipping_info/getShippingInfo.json')
8
+ @shipping_info = ShippingInfo.new(data.first)
9
+ end
10
+
11
+ should "have an id" do
12
+ @shipping_info.id.should == 212
13
+ end
14
+
15
+ should "have an title" do
16
+ @shipping_info.primary_cost.should == "$9.99"
17
+ end
18
+
19
+ should "have an listing_id" do
20
+ @shipping_info.listing_id.should == 14888443
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ShippingTemplateTest < Test::Unit::TestCase
5
+ context "An instance of the ShippingTemplate class" do
6
+ setup do
7
+ data = read_fixture('shipping_template/getShippingTemplate.json')
8
+ @shipping_template = ShippingTemplate.new(data.first)
9
+ end
10
+
11
+ should "have an id" do
12
+ @shipping_template.id.should == 212
13
+ end
14
+
15
+ should "have an title" do
16
+ @shipping_template.title.should == "Small Items"
17
+ end
18
+
19
+ should "have an user_id" do
20
+ @shipping_template.user_id.should == 14888443
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class AboutTest < Test::Unit::TestCase
5
+ context "An instance of the About class" do
6
+ setup do
7
+ data = read_fixture('about/getAbout.json')
8
+ @about = About.new(data.first)
9
+ end
10
+
11
+ should "have a shop id" do
12
+ @about.shop_id.should == 8740774
13
+ end
14
+
15
+ should "have a status" do
16
+ @about.status.should == "active"
17
+ end
18
+
19
+ should "have a story_headline" do
20
+ @about.story_headline.should == 'A shop long in the making...'
21
+ end
22
+
23
+ should "have a story_leading_paragraph" do
24
+ @about.story_leading_paragraph.should == 'This is the leading paragraph'
25
+ end
26
+
27
+ should "have a story" do
28
+ @about.story.should == "I grew up with strong women in my family who all had a love of creating. My mom and grandma always encouraged a lifelong love of creating Working with glass, wire, and mineral components brings back my graduate school days, when I studied these items from a scientific point-of-view. Here&#39;s hoping I can create something that gives you a little sparkle in your life!"
29
+ end
30
+
31
+ should "have a related_links" do
32
+ @about.related_links.should == {
33
+ "link-0"=> {"title"=> "facebook", "url"=> "https://www.facebook.com/pebbleplusmetal/"},
34
+ "link-1"=> {"title"=> "pinterest", "url"=> "https://www.pinterest.com/PebblePlusMetal/pebble%2Bmetal/"}
35
+ }
36
+ end
37
+
38
+ should "have a url" do
39
+ @about.url.should == 'https://www.etsy.com/shop/PebblePlusMetal/about'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,116 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ShopTest < Test::Unit::TestCase
5
+
6
+ context "The Shop class" do
7
+
8
+ should "be able to find a single shop" do
9
+ shops = mock_request('/shops/littletjane', {}, 'Shop', 'getShop.single.json')
10
+ Shop.find('littletjane').should == shops.first
11
+ end
12
+
13
+ should "be able to find multiple shops" do
14
+ shops = mock_request('/shops/littletjane,reagent', {}, 'Shop', 'getShop.multiple.json')
15
+ Shop.find('littletjane', 'reagent').should == shops
16
+ end
17
+
18
+ should "be able to find all shops" do
19
+ shops = mock_request('/shops', {}, 'Shop', 'findAllShop.json')
20
+ Shop.all.should == shops
21
+ end
22
+
23
+ should "return an array of shops if there is only 1 result returned" do
24
+ shops = mock_request('/shops', {}, 'Shop', 'findAllShop.single.json')
25
+ Shop.all.should == shops
26
+ end
27
+
28
+ should "allow a configurable limit when finding all shops" do
29
+ shops = mock_request('/shops', {:limit => 100, :offset => 0}, 'Shop', 'findAllShop.json')
30
+ Shop.all(:limit => 100).should == shops
31
+ end
32
+
33
+ end
34
+
35
+ context "An instance of the Shop class" do
36
+
37
+ context "with response data" do
38
+ setup do
39
+ data = read_fixture('shop/getShop.single.json')
40
+ @shop = Shop.new(data.first)
41
+ end
42
+
43
+ should "have a value for :id" do
44
+ @shop.id.should == 5500349
45
+ end
46
+
47
+ should "have a value for :user_id" do
48
+ @shop.user_id.should == 5327518
49
+ end
50
+
51
+ should "have a value for :image_url" do
52
+ @shop.image_url.should == "http://ny-image3.etsy.com/iusb_760x100.8484779.jpg"
53
+ end
54
+
55
+ should "have a value for :icon_url" do
56
+ @shop.icon_url.should == "https://img0.etsystatic.com/173/0/8740774/isla_fullxfull.22739584_nydzpho0.jpg"
57
+ end
58
+
59
+ should "have a value for :url" do
60
+ @shop.url.should == "http://www.etsy.com/shop/littletjane"
61
+ end
62
+
63
+ should "have a value for :favorers_count" do
64
+ @shop.favorers_count.should == 684
65
+ end
66
+
67
+ should "have a value for :active_listings_count" do
68
+ @shop.active_listings_count.should == 0
69
+ end
70
+
71
+ should "have a value for :updated_at" do
72
+ @shop.updated_at.should == Time.at(1274923984)
73
+ end
74
+
75
+ should "have a value for :created_at" do
76
+ @shop.created_at.should == Time.at(1237430331)
77
+ end
78
+
79
+ should "have a value for :name" do
80
+ @shop.name.should == "littletjane"
81
+ end
82
+
83
+ should "have a value for :title" do
84
+ @shop.title.should == "a cute and crafty mix of handmade goods."
85
+ end
86
+
87
+ should "have a value for :message" do
88
+ @shop.message.should == "thanks!"
89
+ end
90
+
91
+ should "have a value for :announcement" do
92
+ @shop.announcement.should == "announcement"
93
+ end
94
+
95
+ end
96
+
97
+ should "have a collection of listings" do
98
+ shop = Shop.new
99
+ shop.stubs(:id).with().returns(1)
100
+
101
+ Listing.stubs(:find_all_by_shop_id).with(1, {}).returns('listings')
102
+
103
+ shop.listings.should == 'listings'
104
+ end
105
+
106
+ should "have an About object" do
107
+ shop = Shop.new
108
+
109
+ About.stubs(:find_by_shop).with(shop).returns('about')
110
+
111
+ shop.about.should == 'about'
112
+ end
113
+ end
114
+
115
+ end
116
+ end