envato 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +46 -0
  3. data/.rspec +5 -0
  4. data/.rubocop.yml +142 -0
  5. data/Gemfile +5 -0
  6. data/Gemfile.lock +84 -0
  7. data/LICENSE +7 -0
  8. data/README.md +152 -0
  9. data/Rakefile +16 -0
  10. data/envato.gemspec +34 -0
  11. data/lib/envato/client.rb +55 -0
  12. data/lib/envato/collection.rb +25 -0
  13. data/lib/envato/error.rb +6 -0
  14. data/lib/envato/object.rb +25 -0
  15. data/lib/envato/objects/types.rb +19 -0
  16. data/lib/envato/resource.rb +59 -0
  17. data/lib/envato/resources/bookmarks.rb +34 -0
  18. data/lib/envato/resources/item.rb +43 -0
  19. data/lib/envato/resources/market.rb +131 -0
  20. data/lib/envato/resources/markets.rb +42 -0
  21. data/lib/envato/resources/search.rb +21 -0
  22. data/lib/envato/resources/user.rb +60 -0
  23. data/lib/envato/resources/users.rb +10 -0
  24. data/lib/envato/version.rb +8 -0
  25. data/lib/envato.rb +39 -0
  26. data/spec/bookmarks_spec.rb +15 -0
  27. data/spec/envato_spec.rb +26 -0
  28. data/spec/item_spec.rb +90 -0
  29. data/spec/market_spec.rb +100 -0
  30. data/spec/markets_spec.rb +14 -0
  31. data/spec/search_spec.rb +41 -0
  32. data/spec/spec_helper.rb +51 -0
  33. data/spec/user_spec.rb +118 -0
  34. data/spec/users_spec.rb +15 -0
  35. data/spec/vcr/bookmarks_list.yml +87 -0
  36. data/spec/vcr/item_info.yml +88 -0
  37. data/spec/vcr/item_list_purchases.yml +87 -0
  38. data/spec/vcr/item_prices.yml +86 -0
  39. data/spec/vcr/item_purchases.yml +87 -0
  40. data/spec/vcr/item_version.yml +87 -0
  41. data/spec/vcr/market_categories_graphicriver.yml +147 -0
  42. data/spec/vcr/market_categories_themeforest.yml +201 -0
  43. data/spec/vcr/market_features_graphicriver.yml +97 -0
  44. data/spec/vcr/market_features_themeforest.yml +93 -0
  45. data/spec/vcr/market_new_files.yml +86 -0
  46. data/spec/vcr/market_new_files_graphicriver_graphics.yml +115 -0
  47. data/spec/vcr/market_popular_items_themeforest.yml +86 -0
  48. data/spec/vcr/market_total_items.yml +85 -0
  49. data/spec/vcr/search_comments.yml +88 -0
  50. data/spec/vcr/search_item.yml +88 -0
  51. data/spec/vcr/search_more_like_this.yml +88 -0
  52. data/spec/vcr/user_account.yml +86 -0
  53. data/spec/vcr/user_badges.yml +98 -0
  54. data/spec/vcr/user_badges_not_exists.yml +83 -0
  55. data/spec/vcr/user_collection.yml +88 -0
  56. data/spec/vcr/user_collections.yml +90 -0
  57. data/spec/vcr/user_email.yml +85 -0
  58. data/spec/vcr/user_items.yml +86 -0
  59. data/spec/vcr/user_name.yml +85 -0
  60. data/spec/vcr/user_statement.yml +111 -0
  61. data/spec/vcr/users_total.yml +85 -0
  62. metadata +147 -3
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class Resource
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ private
12
+
13
+ def get(url, params: {}, headers: {})
14
+ handle_response client.connection.get(url, params, headers)
15
+ end
16
+
17
+ def post(url, body:, headers: {})
18
+ handle_response client.connection.post(url, body, headers)
19
+ end
20
+
21
+ def patch(url, body:, headers: {})
22
+ handle_response client.connection.patch(url, body, headers)
23
+ end
24
+
25
+ def put(url, body:, headers: {})
26
+ handle_response client.connection.put(url, body, headers)
27
+ end
28
+
29
+ def delete(url, params: {}, headers: {})
30
+ handle_response client.connection.delete(url, params, headers)
31
+ end
32
+ alias delete_request delete
33
+
34
+ # rubocop:disable Metrics/CyclomaticComplexity
35
+ # rubocop:disable Metrics/AbcSize
36
+ def handle_response(response)
37
+ case response.status
38
+ when 400
39
+ raise Error, "Your request was malformed. #{response.body['error']}"
40
+ when 401
41
+ raise Error, "You did not supply valid authentication credentials. #{response.body['error']}"
42
+ when 403
43
+ raise Error, "You are not allowed to perform that action. #{response.body['error']}"
44
+ when 404
45
+ raise Error, "No results were found for your request. #{response.body['error']}"
46
+ when 429
47
+ raise Error, "Your request exceeded the API rate limit. #{response.body['error']}"
48
+ when 500
49
+ raise Error, "We were unable to perform the request due to server-side problems. #{response.body['error']}"
50
+ when 503
51
+ raise Error, "You have been rate limited for sending more requests per second. #{response.body['error']}"
52
+ end
53
+
54
+ response
55
+ end
56
+ # rubocop:enable Metrics/AbcSize
57
+ # rubocop:enable Metrics/CyclomaticComplexity
58
+ end
59
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class BookmarksResource < Resource
5
+ def list
6
+ resp = get("v3/market/user/bookmarks")
7
+ Collection.from_response(resp, key: "bookmarks", type: UserBookmark)
8
+ end
9
+
10
+ # TODO: API error: "reason": "not-found"
11
+ def add(collection_id:, item_id:)
12
+ put("v3/market/user/bookmark_add?collection_id=#{collection_id}&item_id=#{item_id}")
13
+ end
14
+
15
+ def remove(id:)
16
+ delete("v3/market/user/bookmark_remove?id=#{id}")
17
+ end
18
+
19
+ # TODO: bookmarks_for_items
20
+ # TODO: item_ids: comma separated "12312312,123123123,12312312"
21
+ def for_items(item_ids:)
22
+ Object.new get("v3/market/user/bookmarks_for_items?item_ids=#{item_ids}").body
23
+ end
24
+
25
+ # TODO: add to CollectionResource
26
+ # TODO: API error: "reason": "not-found"
27
+ def collection_create(name:, site:, description:, is_public: false)
28
+ Object.new post("v3/market/user/collection_create \
29
+ ?name=#{name}&site=#{site} \
30
+ &public=#{is_public} \
31
+ &description=#{description}".gsub(/\s+/, "")).body
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class ItemResource < Resource
5
+ def prices(item_id:)
6
+ resp = get("v1/market/item-prices:#{item_id}.json")
7
+ Collection.from_response(resp, key: "item-prices", type: ItemPrice)
8
+ end
9
+
10
+ def download(item_id:, purchase_code:, shorten_url: true)
11
+ Object.new get("v3/market/buyer/download \
12
+ ?item_id=#{item_id} \
13
+ &purchase_code=#{purchase_code} \
14
+ &shorten_url=#{shorten_url}".gsub(/\s+/, "")).body
15
+ end
16
+
17
+ # TODO: filter_by: wordpress-plugins | wordpress-themes
18
+ def list_purchases(filter_by: "wordpress-themes", page: 1, details: false)
19
+ resp = get("v3/market/buyer/list-purchases \
20
+ ?filter_by=#{filter_by} \
21
+ &page=#{page} \
22
+ &details=#{details}".gsub(/\s+/, ""))
23
+ Collection.from_response(resp, key: "results", type: Item)
24
+ end
25
+
26
+ def purchase(code:)
27
+ Object.new get("v3/market/buyer/purchase?code=#{code}").body
28
+ end
29
+
30
+ def purchases
31
+ resp = get("v3/market/buyer/purchases")
32
+ Collection.from_response(resp, key: "purchases", type: Item)
33
+ end
34
+
35
+ def version(id:)
36
+ ItemVersion.new get("v3/market/catalog/item-version?id=#{id}").body
37
+ end
38
+
39
+ def info(id:)
40
+ Item.new get("v3/market/catalog/item?id=#{id}").body
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class MarketResource < Resource
5
+ def user(username:)
6
+ Object.new get("v1/market/user:#{username}").body
7
+ end
8
+
9
+ # TODO: move methods to CategoriesResource
10
+ def categories(site:)
11
+ resp = get("v1/market/categories:#{site}.json")
12
+ Collection.from_response(resp, key: "categories", type: Category)
13
+ end
14
+
15
+ def categories_themeforest
16
+ categories(site: "themeforest")
17
+ end
18
+
19
+ def categories_photodune
20
+ categories(site: "photodune")
21
+ end
22
+
23
+ def categories_codecanyon
24
+ categories(site: "codecanyon")
25
+ end
26
+
27
+ def categories_videohive
28
+ categories(site: "videohive")
29
+ end
30
+
31
+ def categories_audiojungle
32
+ categories(site: "audiojungle")
33
+ end
34
+
35
+ def categories_graphicriver
36
+ categories(site: "graphicriver")
37
+ end
38
+
39
+ def categories_3docean
40
+ categories(site: "3docean")
41
+ end
42
+
43
+ # TODO: Features.new
44
+ def features(site:)
45
+ Object.new get("v1/market/features:#{site}.json").body
46
+ end
47
+
48
+ def features_themeforest
49
+ features(site: "themeforest")
50
+ end
51
+
52
+ def features_photodune
53
+ features(site: "photodune")
54
+ end
55
+
56
+ def features_codecanyon
57
+ features(site: "codecanyon")
58
+ end
59
+
60
+ def features_videohive
61
+ features(site: "videohive")
62
+ end
63
+
64
+ def features_audiojungle
65
+ features(site: "audiojungle")
66
+ end
67
+
68
+ def features_graphicriver
69
+ features(site: "graphicriver")
70
+ end
71
+
72
+ def features_3docean
73
+ features(site: "3docean")
74
+ end
75
+
76
+ def popular_items(site:)
77
+ Object.new get("v1/market/popular:#{site}.json").body
78
+ end
79
+
80
+ def popular_items_themeforest
81
+ popular_items(site: "themeforest")
82
+ end
83
+
84
+ def popular_items_photodune
85
+ popular_items(site: "photodune")
86
+ end
87
+
88
+ def popular_items_codecanyon
89
+ popular_items(site: "codecanyon")
90
+ end
91
+
92
+ def popular_items_videohive
93
+ popular_items(site: "videohive")
94
+ end
95
+
96
+ def popular_items_audiojungle
97
+ popular_items(site: "audiojungle")
98
+ end
99
+
100
+ def popular_items_graphicriver
101
+ popular_items(site: "graphicriver")
102
+ end
103
+
104
+ def popular_items_3docean
105
+ popular_items(site: "3docean")
106
+ end
107
+
108
+ # TODO: add themeforest, graphicriver, etc.
109
+ def new_files(site:, category:)
110
+ resp = get("v1/market/new-files:#{site},#{category}.json")
111
+ Collection.from_response(resp, key: "new-files", type: Item)
112
+ end
113
+
114
+ # TODO: add themeforest, etc.
115
+ def new_files_graphicriver(category:)
116
+ new_files(site: "graphicriver", category: category)
117
+ end
118
+
119
+ def new_files_from_user(username:, site:)
120
+ Object.new get("v1/market/new-files-from-user:#{username},#{site}.json")
121
+ end
122
+
123
+ def random_new_files(site:)
124
+ Object.new get("v1/market/random-new-files:#{site}.json")
125
+ end
126
+
127
+ def collection(id:, page: 1)
128
+ Object.new get("v3/market/catalog/collection?id=#{id}&page=#{page}").body
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class MarketsResource < Resource
5
+ def number_of_files(site:)
6
+ Object.new get("v1/market/number-of-files:#{site}.json").body
7
+ end
8
+
9
+ def total_themeforest
10
+ number_of_files(site: "themeforest")
11
+ end
12
+
13
+ def total_photodune
14
+ number_of_files(site: "photodune")
15
+ end
16
+
17
+ def total_codecanyon
18
+ number_of_files(site: "codecanyon")
19
+ end
20
+
21
+ def total_videohive
22
+ number_of_files(site: "videohive")
23
+ end
24
+
25
+ def total_audiojungle
26
+ number_of_files(site: "audiojungle")
27
+ end
28
+
29
+ def total_graphicriver
30
+ number_of_files(site: "graphicriver")
31
+ end
32
+
33
+ def total_3docean
34
+ number_of_files(site: "3docean")
35
+ end
36
+
37
+ def total_items
38
+ Object.new get("v1/market/total-items.json").body
39
+ end
40
+ alias total total_items
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class SearchResource < Resource
5
+ def more_like_this(item_id:, page: 1, page_size: 10)
6
+ resp = get("v1/discovery/search/search/more_like_this?item_id=#{item_id}&page=#{page}&page_size=#{page_size}")
7
+ Collection.from_response(resp, key: "matches", type: Item)
8
+ end
9
+ alias like more_like_this
10
+
11
+ def comments(item_id:, page: 1, page_size: 10)
12
+ resp = get("v1/discovery/search/search/comment?item_id=#{item_id}&page=#{page}&page_size=#{page_size}")
13
+ Collection.from_response(resp, key: "matches", type: Comment)
14
+ end
15
+
16
+ def item
17
+ resp = get("v1/discovery/search/search/item")
18
+ Collection.from_response(resp, key: "matches", type: Item)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class UserResource < Resource
5
+ def statement
6
+ UserStatement.new get("v3/market/user/statement").body
7
+ end
8
+
9
+ def collections
10
+ resp = get("v3/market/user/collections")
11
+ Collection.from_response(resp, key: "collections", type: UserCollection)
12
+ end
13
+
14
+ def collection(id:)
15
+ resp = get("v3/market/user/collection?id=#{id}")
16
+ Collection.from_response(resp, key: "items", type: CollectionItem)
17
+ end
18
+
19
+ def items(username:)
20
+ resp = get("v1/market/user-items-by-site:#{username}.json")
21
+ Collection.from_response(resp, key: "user-items-by-site", type: Item)
22
+ end
23
+
24
+ def badges(username:)
25
+ resp = get("v1/market/user-badges:#{username}.json")
26
+ Collection.from_response(resp, key: "user-badges", type: UserBadge)
27
+ end
28
+
29
+ def earnings_and_sales
30
+ Object.new get("v1/market/private/user/earnings-and-sales-by-month.json").body
31
+ end
32
+ alias sales_and_earnings earnings_and_sales
33
+
34
+ def account
35
+ UserAccount.new get("/v1/market/private/user/account.json").body
36
+ end
37
+
38
+ def name
39
+ Object.new get("v1/market/private/user/username.json").body
40
+ end
41
+ alias username name
42
+
43
+ def email
44
+ Object.new get("v1/market/private/user/email.json").body
45
+ end
46
+
47
+ def sales
48
+ Object.new get("v1/market/private/author/sales").body
49
+ end
50
+
51
+ def sale(code:)
52
+ UserSale.new get("v3/market/author/sale?code=#{code}").body
53
+ end
54
+
55
+ # TODO: rename and move to CollectionResource
56
+ def add_to_favorite(item_id:)
57
+ put("v3/market/user/favourite_collection_add?item_id=#{item_id}")
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ class UsersResource < Resource
5
+ def total
6
+ UsersTotal.new get("v1/market/total-users.json").body
7
+ end
8
+ alias totat_users total
9
+ end
10
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Envato
4
+ major = 1
5
+ minor = 0
6
+ patch = 0
7
+ VERSION = "#{major}.#{minor}.#{patch}"
8
+ end
data/lib/envato.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "addressable/uri"
4
+ require "faraday"
5
+ require "envato/version"
6
+
7
+ module Envato
8
+ autoload :Client, "envato/client"
9
+ autoload :Object, "envato/object"
10
+ autoload :Resource, "envato/resource"
11
+ autoload :Collection, "envato/collection"
12
+ autoload :Error, "envato/error"
13
+
14
+ autoload :UserResource, "envato/resources/user"
15
+ autoload :UsersResource, "envato/resources/users"
16
+ autoload :MarketResource, "envato/resources/market"
17
+ autoload :MarketsResource, "envato/resources/markets"
18
+ autoload :SearchResource, "envato/resources/search"
19
+ autoload :BookmarksResource, "envato/resources/bookmarks"
20
+ autoload :ItemResource, "envato/resources/item"
21
+
22
+ autoload :User, "envato/objects/types"
23
+ autoload :UserAccount, "envato/objects/types"
24
+ autoload :UserStatement, "envato/objects/types"
25
+ autoload :UserList, "envato/objects/types"
26
+ autoload :UserStatement, "envato/objects/types"
27
+ autoload :UserCollection, "envato/objects/types"
28
+ autoload :UserBookmark, "envato/objects/types"
29
+
30
+ autoload :UsersTotal, "envato/objects/types"
31
+
32
+ autoload :SearchMatch, "envato/objects/types"
33
+
34
+ autoload :CollectionItem, "envato/objects/types"
35
+
36
+ autoload :Item, "envato/objects/types"
37
+ autoload :ItemPrice, "envato/objects/types"
38
+ autoload :ItemVersion, "envato/objects/types"
39
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "envato"
5
+
6
+ RSpec.describe "#bookmarks.list" do
7
+ subject(:resp) do
8
+ VCR.use_cassette("bookmarks_list") do
9
+ @envato.bookmarks.list
10
+ end
11
+ end
12
+
13
+ it { expect(resp).to be_instance_of(Envato::Collection) }
14
+ it { expect(resp.data.first).to be_instance_of(Envato::UserBookmark) }
15
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "envato"
5
+
6
+ RSpec.describe Envato::Client do
7
+ context "with valid token" do
8
+ describe "#user", :vcr do
9
+ it "name" do
10
+ allow(@envato.user)
11
+ .to receive(:name)
12
+ .and_return(Envato::UserResource)
13
+ end
14
+ end
15
+ end
16
+
17
+ context "without token" do
18
+ it do
19
+ expect { described_class.new }.to raise_error(ArgumentError)
20
+ end
21
+ end
22
+ end
23
+
24
+ RSpec.describe "#VERSION" do
25
+ it { expect(Envato::VERSION).to eq "1.0.0" }
26
+ end
data/spec/item_spec.rb ADDED
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "envato"
5
+
6
+ RSpec.describe "#item.info" do
7
+ context "with id param" do
8
+ subject(:resp) do
9
+ VCR.use_cassette("item_info") do
10
+ @envato.item.info(id: "5556590")
11
+ end
12
+ end
13
+
14
+ it { expect(resp).to be_an(Envato::Item) }
15
+ it { expect(resp.tags).to be_an(Array) }
16
+ it { expect(resp.attributes).to be_an(Array) }
17
+ it { expect(resp.previews).to be_an(OpenStruct) }
18
+ it { expect(resp.site).to eq("themeforest.net") }
19
+ end
20
+
21
+ context "without id param" do
22
+ subject(:resp) do
23
+ VCR.use_cassette("item_info") do
24
+ @envato.item.info
25
+ end
26
+ end
27
+
28
+ it { expect { resp }.to raise_error(ArgumentError) }
29
+ end
30
+ end
31
+
32
+ RSpec.describe "#item.version" do
33
+ context "with id param" do
34
+ subject(:resp) do
35
+ VCR.use_cassette("item_version") do
36
+ @envato.item.version(id: "5556590")
37
+ end
38
+ end
39
+
40
+ it { expect(resp).to be_instance_of(Envato::ItemVersion) }
41
+ end
42
+
43
+ context "without id param" do
44
+ subject(:resp) do
45
+ VCR.use_cassette("item_version") do
46
+ @envato.item.version
47
+ end
48
+ end
49
+
50
+ it { expect { resp }.to raise_error(ArgumentError) }
51
+ end
52
+ end
53
+
54
+ RSpec.describe "#item.prices" do
55
+ context "with id param" do
56
+ subject(:resp) do
57
+ VCR.use_cassette("item_prices") do
58
+ @envato.item.prices(item_id: "5556590")
59
+ end
60
+ end
61
+
62
+ it { expect(resp).to be_instance_of(Envato::Collection) }
63
+ it { expect(resp.data.first).to be_instance_of(Envato::ItemPrice) }
64
+ end
65
+
66
+ context "without id param" do
67
+ it { expect { @envato.item.prices }.to raise_error(ArgumentError, /missing keyword/) }
68
+ end
69
+ end
70
+
71
+ RSpec.describe "#item.purchases" do
72
+ subject(:resp) do
73
+ VCR.use_cassette("item_purchases") do
74
+ @envato.item.purchases
75
+ end
76
+ end
77
+
78
+ it { expect(resp).to be_instance_of(Envato::Collection) }
79
+ end
80
+
81
+ RSpec.describe "#item.list_purchases" do
82
+ subject(:resp) do
83
+ VCR.use_cassette("item_list_purchases") do
84
+ @envato.item.list_purchases
85
+ end
86
+ end
87
+
88
+ it { expect(resp).to be_instance_of(Envato::Collection) }
89
+ it { expect(resp.data.count).to be_instance_of(Integer) }
90
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "envato"
5
+
6
+ RSpec.describe "#market.categories" do
7
+ context "when site is themeforest" do
8
+ subject(:resp) do
9
+ VCR.use_cassette("market_categories_themeforest") do
10
+ @envato.market.categories site: "themeforest"
11
+ end
12
+ end
13
+
14
+ it { expect(resp).to be_instance_of(Envato::Collection) }
15
+ it { expect(resp.data.first).to be_instance_of(Envato::Category) }
16
+ it { expect(resp.data.first.name).to eq "Site Templates" }
17
+ it { expect(resp.data.first.path).to eq "site-templates" }
18
+ end
19
+
20
+ context "when site is graphicriver" do
21
+ subject(:resp) do
22
+ VCR.use_cassette("market_categories_graphicriver") do
23
+ @envato.market.categories_graphicriver
24
+ end
25
+ end
26
+
27
+ it { expect(resp).to be_instance_of(Envato::Collection) }
28
+ it { expect(resp.data.first).to be_instance_of(Envato::Category) }
29
+ it { expect(resp.data.first.name).to eq "Graphics" }
30
+ it { expect(resp.data.first.path).to eq "graphics" }
31
+ end
32
+ end
33
+
34
+ RSpec.describe "#market.features" do
35
+ context "when site is themeforest" do
36
+ subject(:resp) do
37
+ VCR.use_cassette("market_features_themeforest") do
38
+ @envato.market.features site: "themeforest"
39
+ end
40
+ end
41
+
42
+ # TODO: Object to Features
43
+ it { expect(resp).to be_an(Envato::Object) }
44
+ it { expect(resp.features.free_file).to be_an OpenStruct }
45
+ it { expect(resp.features.featured_file).to be_an OpenStruct }
46
+ it { expect(resp.features.featured_author).to be_an OpenStruct }
47
+ end
48
+
49
+ context "when site is graphicriver" do
50
+ subject(:resp) do
51
+ VCR.use_cassette("market_features_graphicriver") do
52
+ @envato.market.features_graphicriver
53
+ end
54
+ end
55
+
56
+ it { expect(resp).to be_instance_of(Envato::Object) }
57
+ it { expect(resp.features.free_file).to be_an OpenStruct }
58
+ it { expect(resp.features.featured_file).to be_an OpenStruct }
59
+ it { expect(resp.features.featured_author).to be_an OpenStruct }
60
+ end
61
+ end
62
+
63
+ RSpec.describe "#market.new_files" do
64
+ context "when site is themeforest" do
65
+ subject(:resp) do
66
+ VCR.use_cassette("market_new_files") do
67
+ @envato.market.new_files(site: "themeforest", category: "site-templates")
68
+ end
69
+ end
70
+
71
+ it { expect(resp).to be_instance_of(Envato::Collection) }
72
+ it { expect(resp.data.first).to be_an OpenStruct }
73
+ end
74
+
75
+ context "when site is graphicriver" do
76
+ context "ant category is graphics" do
77
+ subject(:resp) do
78
+ VCR.use_cassette("market_new_files_graphicriver_graphics") do
79
+ @envato.market.new_files_graphicriver category: "graphics"
80
+ end
81
+ end
82
+
83
+ it { expect(resp).to be_instance_of(Envato::Collection) }
84
+ it { expect(resp.data.first).to be_an OpenStruct }
85
+ end
86
+ end
87
+ end
88
+
89
+ RSpec.describe "#market.popular_items" do
90
+ subject(:resp) do
91
+ VCR.use_cassette("market_popular_items_themeforest") do
92
+ @envato.market.popular_items site: "themeforest"
93
+ end
94
+ end
95
+
96
+ it { expect(resp).to be_instance_of(Envato::Object) }
97
+ it { expect(resp.popular).to be_instance_of(OpenStruct) }
98
+ it { expect(resp.popular.items_last_week).to be_instance_of(Array) }
99
+ it { expect(resp.popular.items_last_week.first.id).not_to be(nil) }
100
+ end