twitter-ads 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -0
- data/CONTRIBUTING.md +77 -0
- data/LICENSE +22 -0
- data/README.md +111 -0
- data/Rakefile +86 -0
- data/bin/twitter-ads +42 -0
- data/lib/twitter-ads.rb +54 -0
- data/lib/twitter-ads/account.rb +229 -0
- data/lib/twitter-ads/audiences/tailored_audience.rb +177 -0
- data/lib/twitter-ads/campaign/app_list.rb +42 -0
- data/lib/twitter-ads/campaign/campaign.rb +40 -0
- data/lib/twitter-ads/campaign/funding_instrument.rb +33 -0
- data/lib/twitter-ads/campaign/line_item.rb +91 -0
- data/lib/twitter-ads/campaign/promotable_user.rb +28 -0
- data/lib/twitter-ads/campaign/targeting_criteria.rb +77 -0
- data/lib/twitter-ads/campaign/tweet.rb +83 -0
- data/lib/twitter-ads/client.rb +92 -0
- data/lib/twitter-ads/creative/app_download_card.rb +44 -0
- data/lib/twitter-ads/creative/image_app_download_card.rb +44 -0
- data/lib/twitter-ads/creative/image_conversation_card.rb +44 -0
- data/lib/twitter-ads/creative/lead_gen_card.rb +46 -0
- data/lib/twitter-ads/creative/promoted_account.rb +38 -0
- data/lib/twitter-ads/creative/promoted_tweet.rb +87 -0
- data/lib/twitter-ads/creative/video.rb +43 -0
- data/lib/twitter-ads/creative/video_app_download_card.rb +47 -0
- data/lib/twitter-ads/creative/video_conversation_card.rb +46 -0
- data/lib/twitter-ads/creative/website_card.rb +48 -0
- data/lib/twitter-ads/cursor.rb +127 -0
- data/lib/twitter-ads/enum.rb +135 -0
- data/lib/twitter-ads/error.rb +93 -0
- data/lib/twitter-ads/http/request.rb +127 -0
- data/lib/twitter-ads/http/response.rb +74 -0
- data/lib/twitter-ads/http/ton_upload.rb +140 -0
- data/lib/twitter-ads/legacy.rb +7 -0
- data/lib/twitter-ads/resources/analytics.rb +90 -0
- data/lib/twitter-ads/resources/dsl.rb +108 -0
- data/lib/twitter-ads/resources/persistence.rb +43 -0
- data/lib/twitter-ads/resources/resource.rb +92 -0
- data/lib/twitter-ads/targeting/reach_estimate.rb +69 -0
- data/lib/twitter-ads/utils.rb +76 -0
- data/lib/twitter-ads/version.rb +6 -0
- data/spec/fixtures/accounts_all.json +65 -0
- data/spec/fixtures/accounts_features.json +18 -0
- data/spec/fixtures/accounts_load.json +19 -0
- data/spec/fixtures/app_lists_all.json +22 -0
- data/spec/fixtures/app_lists_load.json +31 -0
- data/spec/fixtures/campaigns_all.json +208 -0
- data/spec/fixtures/campaigns_load.json +27 -0
- data/spec/fixtures/funding_instruments_all.json +74 -0
- data/spec/fixtures/funding_instruments_load.json +28 -0
- data/spec/fixtures/line_items_all.json +292 -0
- data/spec/fixtures/line_items_load.json +36 -0
- data/spec/fixtures/placements.json +35 -0
- data/spec/fixtures/promotable_users_all.json +57 -0
- data/spec/fixtures/promotable_users_load.json +18 -0
- data/spec/fixtures/promoted_tweets_all.json +212 -0
- data/spec/fixtures/promoted_tweets_load.json +19 -0
- data/spec/fixtures/reach_estimate.json +19 -0
- data/spec/fixtures/tailored_audiences_all.json +67 -0
- data/spec/fixtures/tailored_audiences_load.json +29 -0
- data/spec/fixtures/tweet_preview.json +24 -0
- data/spec/fixtures/videos_all.json +50 -0
- data/spec/fixtures/videos_load.json +22 -0
- data/spec/quality_spec.rb +15 -0
- data/spec/shared/properties.rb +20 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/helpers.rb +42 -0
- data/spec/twitter-ads/account_spec.rb +315 -0
- data/spec/twitter-ads/audiences/tailored_audience_spec.rb +45 -0
- data/spec/twitter-ads/campaign/app_list_spec.rb +108 -0
- data/spec/twitter-ads/campaign/line_item_spec.rb +95 -0
- data/spec/twitter-ads/campaign/reach_estimate_spec.rb +98 -0
- data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +39 -0
- data/spec/twitter-ads/campaign/tweet_spec.rb +83 -0
- data/spec/twitter-ads/client_spec.rb +115 -0
- data/spec/twitter-ads/creative/app_download_card_spec.rb +44 -0
- data/spec/twitter-ads/creative/image_app_download_card_spec.rb +43 -0
- data/spec/twitter-ads/creative/image_conversation_card_spec.rb +40 -0
- data/spec/twitter-ads/creative/lead_gen_card_spec.rb +46 -0
- data/spec/twitter-ads/creative/promoted_account_spec.rb +30 -0
- data/spec/twitter-ads/creative/promoted_tweet_spec.rb +46 -0
- data/spec/twitter-ads/creative/video_app_download_card_spec.rb +42 -0
- data/spec/twitter-ads/creative/video_conversation_card_spec.rb +52 -0
- data/spec/twitter-ads/creative/video_legacy_spec.rb +43 -0
- data/spec/twitter-ads/creative/video_spec.rb +43 -0
- data/spec/twitter-ads/creative/website_card_spec.rb +37 -0
- data/spec/twitter-ads/cursor_spec.rb +67 -0
- data/spec/twitter-ads/placements_spec.rb +36 -0
- data/spec/twitter-ads/utils_spec.rb +101 -0
- data/twitter-ads.gemspec +37 -0
- metadata +247 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data_type": "tailored_audiences",
|
|
3
|
+
"data": {
|
|
4
|
+
"targetable": false,
|
|
5
|
+
"name": "TA #2",
|
|
6
|
+
"targetable_types": [
|
|
7
|
+
"WEB",
|
|
8
|
+
"EXCLUDED_WEB"
|
|
9
|
+
],
|
|
10
|
+
"audience_type": "WEB",
|
|
11
|
+
"id": "abc2",
|
|
12
|
+
"reasons_not_targetable": [
|
|
13
|
+
"TOO_SMALL"
|
|
14
|
+
],
|
|
15
|
+
"list_type": null,
|
|
16
|
+
"created_at": "2014-03-09T20:35:41Z",
|
|
17
|
+
"updated_at": "2014-06-11T09:38:06Z",
|
|
18
|
+
"partner_source": "OTHER",
|
|
19
|
+
"deleted": false,
|
|
20
|
+
"audience_size": null
|
|
21
|
+
},
|
|
22
|
+
"request": {
|
|
23
|
+
"params": {
|
|
24
|
+
"account_id": "2iqph",
|
|
25
|
+
"name": "TA #2",
|
|
26
|
+
"list_type": "EMAIL"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data_type": "tweet_preview",
|
|
3
|
+
"data": [
|
|
4
|
+
{
|
|
5
|
+
"platform": "web",
|
|
6
|
+
"preview": " <div><img><div><div><div><a>AdsAPI</a><a>@AdsAPI</a></div></div><div>Hello World!</div><div><div><img><div><div></div><div><span> Ratings/pricing not available for preview </span><span> Ratings/pricing not available for preview </span></div><div></div> INSTALL </div></div></div><a><img></a><div><div><span></span><span>Promoted by AdsAPI</span></div></div></div></div>"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"platform": "android",
|
|
10
|
+
"preview": " <div><img><div><div><div><a>AdsAPI</a><a>@AdsAPI</a></div></div><div>Hello World!</div><div><div><img><div><div></div><div><span> Ratings/pricing not available for preview </span><span> Ratings/pricing not available for preview </span></div><div></div> INSTALL </div></div></div><a><img></a><div><div><span></span><span>Promoted by AdsAPI</span></div></div></div></div>"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"platform": "iphone",
|
|
14
|
+
"preview": " <div><img><div><div><div><a>AdsAPI</a><a>@AdsAPI</a></div></div><div>Hello World!</div><div><div><img><div><div></div><div><span> Ratings/pricing not available for preview </span><span> Ratings/pricing not available for preview </span></div><div></div> INSTALL </div></div></div><a><img></a><div><div><span></span><span>Promoted by AdsAPI</span></div></div></div></div>"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"request": {
|
|
18
|
+
"params": {
|
|
19
|
+
"status": "Hello World!",
|
|
20
|
+
"card_id": "pfs",
|
|
21
|
+
"account_id": "2iqph"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data_type": "video",
|
|
3
|
+
"data": [
|
|
4
|
+
{
|
|
5
|
+
"tweeted": false,
|
|
6
|
+
"ready_to_tweet": true,
|
|
7
|
+
"duration": 289149,
|
|
8
|
+
"reasons_not_servable": [],
|
|
9
|
+
"description": "youtubz",
|
|
10
|
+
"preview_url": "https://amp.twimg.com/prod/multibr_v_1/video/2015/09/24/21/d5e3ae4d-34c4-4f49-894e-0c17735916a4-libx264-baseline-2528k.mp4?rYDB9GoYJcfWyizjXnBZra4UnGQMTkzUkIuW6OKjlXw%3D",
|
|
11
|
+
"id": "d5e3ae4d-34c4-4f49-894e-0c17735916a4",
|
|
12
|
+
"created_at": "2015-09-24T21:21:00Z",
|
|
13
|
+
"title": "video #1",
|
|
14
|
+
"updated_at": "2015-09-24T21:25:42Z",
|
|
15
|
+
"deleted": false
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"tweeted": false,
|
|
19
|
+
"ready_to_tweet": true,
|
|
20
|
+
"duration": 16517,
|
|
21
|
+
"reasons_not_servable": [],
|
|
22
|
+
"description": "my favorite video",
|
|
23
|
+
"preview_url": "https://amp.twimg.com/prod/multibr_v_1/video/2015/09/24/21/a6d50810-c0bd-408e-b703-b789a82981ce-libx264-baseline-2528k.mp4?rYDB9GoYJcfWyizjXnBZra4UnGQMTkzUkIuW6OKjlXw%3D",
|
|
24
|
+
"id": "a6d50810-c0bd-408e-b703-b789a82981ce",
|
|
25
|
+
"created_at": "2015-09-24T21:11:01Z",
|
|
26
|
+
"title": "video #2",
|
|
27
|
+
"updated_at": "2015-09-24T21:11:41Z",
|
|
28
|
+
"deleted": false
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"tweeted": false,
|
|
32
|
+
"ready_to_tweet": false,
|
|
33
|
+
"duration": 16517,
|
|
34
|
+
"reasons_not_servable": ["ERROR"],
|
|
35
|
+
"description": "another great video",
|
|
36
|
+
"preview_url": "https://amp.twimg.com/prod/multibr_v_1/video/2015/09/24/21/3beaeaca-0f2f-4aff-a025-e0d53a0aef2c-libx264-baseline-2528k.mp4?rYDB9GoYJcfWyizjXnBZra4UnGQMTkzUkIuW6OKjlXw%3D",
|
|
37
|
+
"id": "3beaeaca-0f2f-4aff-a025-e0d53a0aef2c",
|
|
38
|
+
"created_at": "2015-09-24T21:08:55Z",
|
|
39
|
+
"title": "video #3",
|
|
40
|
+
"updated_at": "2015-09-24T21:10:01Z",
|
|
41
|
+
"deleted": true
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"request": {
|
|
45
|
+
"params": {
|
|
46
|
+
"account_id": "2iqph"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"next_cursor": null
|
|
50
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"data_type": "video",
|
|
3
|
+
"data": {
|
|
4
|
+
"tweeted": false,
|
|
5
|
+
"ready_to_tweet": true,
|
|
6
|
+
"duration": 289149,
|
|
7
|
+
"reasons_not_servable": [],
|
|
8
|
+
"description": "youtubz",
|
|
9
|
+
"preview_url": "https://amp.twimg.com/prod/multibr_v_1/video/2015/09/24/21/d5e3ae4d-34c4-4f49-894e-0c17735916a4-libx264-baseline-2528k.mp4?rYDB9GoYJcfWyizjXnBZra4UnGQMTkzUkIuW6OKjlXw%3D",
|
|
10
|
+
"id": "d5e3ae4d-34c4-4f49-894e-0c17735916a4",
|
|
11
|
+
"created_at": "2015-09-24T21:21:00Z",
|
|
12
|
+
"title": "video #1",
|
|
13
|
+
"updated_at": "2015-09-24T21:25:42Z",
|
|
14
|
+
"deleted": false
|
|
15
|
+
},
|
|
16
|
+
"request": {
|
|
17
|
+
"params": {
|
|
18
|
+
"video_id": "d5e3ae4d-34c4-4f49-894e-0c17735916a4",
|
|
19
|
+
"account_id": "2iqph"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
require 'spec_helper'
|
|
5
|
+
|
|
6
|
+
describe 'Code Style & Quality', :quality do
|
|
7
|
+
|
|
8
|
+
# If this test fails, you need to run 'rubocop' to see what needs to be fixed.
|
|
9
|
+
# Please see the CONTRIBUTING.md file for additional style guide information.
|
|
10
|
+
it 'has no style guide or quality violations', :style do
|
|
11
|
+
result = silence { RuboCop::CLI.new.run([]) }
|
|
12
|
+
expect(result).to eq(0)
|
|
13
|
+
end unless RUBY_ENGINE =~ /rbx/
|
|
14
|
+
|
|
15
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
RSpec.shared_examples 'object property check' do |read, write|
|
|
5
|
+
|
|
6
|
+
it 'has all the correct write properties' do
|
|
7
|
+
write.each do |prop|
|
|
8
|
+
expect(subject.respond_to?(prop)).to be true
|
|
9
|
+
expect(subject.respond_to?("#{prop}=")).to be true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'has all the correct read-only properties' do
|
|
14
|
+
read.each do |prop|
|
|
15
|
+
expect(subject.respond_to?(prop)).to be true
|
|
16
|
+
expect(subject.respond_to?("#{prop}=")).not_to be true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
unless RUBY_PLATFORM =~ /java/ || RUBY_ENGINE =~ /rbx/
|
|
5
|
+
require 'simplecov'
|
|
6
|
+
require 'codeclimate-test-reporter'
|
|
7
|
+
|
|
8
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
|
9
|
+
SimpleCov::Formatter::HTMLFormatter,
|
|
10
|
+
CodeClimate::TestReporter::Formatter
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
SimpleCov.start do
|
|
14
|
+
add_filter '/spec/'
|
|
15
|
+
minimum_coverage(80.00)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require 'rubocop'
|
|
20
|
+
require 'faker'
|
|
21
|
+
|
|
22
|
+
require 'webmock/rspec'
|
|
23
|
+
WebMock.disable_net_connect!(allow: 'codeclimate.com')
|
|
24
|
+
|
|
25
|
+
require 'twitter-ads'
|
|
26
|
+
include TwitterAds
|
|
27
|
+
|
|
28
|
+
# Require All Support Files
|
|
29
|
+
Dir['./spec/support/*.rb'].sort.each { |file| require file }
|
|
30
|
+
|
|
31
|
+
ADS_API = 'https://ads-api.twitter.com/0'.freeze
|
|
32
|
+
TON_API = 'https://ton.twitter.com'.freeze
|
|
33
|
+
UPLOAD_API = 'https://upload.twitter.com/1.1'.freeze
|
|
34
|
+
|
|
35
|
+
RSpec.configure do |config|
|
|
36
|
+
# Helpers & Custom Matchers
|
|
37
|
+
include Helpers
|
|
38
|
+
|
|
39
|
+
# General
|
|
40
|
+
config.color = true
|
|
41
|
+
config.fail_fast = true unless ENV['CI']
|
|
42
|
+
config.formatter = ENV['CI'] ? 'documentation' : 'progress'
|
|
43
|
+
config.profile_examples = 5
|
|
44
|
+
|
|
45
|
+
# Expectations
|
|
46
|
+
config.expect_with :rspec do |expectations|
|
|
47
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Mocking
|
|
51
|
+
config.mock_with :rspec do |mocks|
|
|
52
|
+
mocks.verify_partial_doubles = true
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Test Order & Filtering
|
|
56
|
+
config.order = :random
|
|
57
|
+
Kernel.srand config.seed
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Require All Shared Examples
|
|
61
|
+
Dir['./spec/shared/*.rb'].sort.each { |file| require file }
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
# Helper module for custom test matchers and utilities.
|
|
5
|
+
module Helpers
|
|
6
|
+
|
|
7
|
+
# Helper method to temporarily redirect stdout and stderr for
|
|
8
|
+
# a given block of code.
|
|
9
|
+
#
|
|
10
|
+
# @param &block [Block] The code block to be executed.
|
|
11
|
+
#
|
|
12
|
+
# @return [Object] The result of the block.
|
|
13
|
+
def silence(&block)
|
|
14
|
+
original_stdout = $stdout
|
|
15
|
+
original_stderr = $stderr
|
|
16
|
+
$stdout = $stderr = File.new('/dev/null', 'w')
|
|
17
|
+
yield block
|
|
18
|
+
ensure
|
|
19
|
+
$stdout = original_stdout
|
|
20
|
+
$stderr = original_stderr
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Helper method for returning a JSON fixture file.
|
|
24
|
+
#
|
|
25
|
+
# @param name [Symbol] The name of the fixture file to be returned.
|
|
26
|
+
#
|
|
27
|
+
# @return [File] The file instance of the fixture specified.
|
|
28
|
+
def fixture(name)
|
|
29
|
+
File.new(File.expand_path("../../fixtures/#{name}.json", __FILE__))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Helper method to stub a request with a fixture by name.
|
|
33
|
+
#
|
|
34
|
+
# @param method [Symbol] The HTTP method (:get, :put, :post, :delete)
|
|
35
|
+
# @param name [String] The fixture name.
|
|
36
|
+
# @param url [String] The URL match pattern or regular expression.
|
|
37
|
+
# @param status [Integer] The response code to return with the fixture.
|
|
38
|
+
def stub_fixture(method, name, url, status = 200)
|
|
39
|
+
stub_request(method, url).to_return(body: fixture(name), status: status)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Copyright (C) 2015 Twitter, Inc.
|
|
3
|
+
|
|
4
|
+
require 'spec_helper'
|
|
5
|
+
|
|
6
|
+
describe TwitterAds::Account do
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
stub_fixture(:get, :accounts_all, "#{ADS_API}/accounts")
|
|
10
|
+
stub_fixture(:get, :accounts_load, "#{ADS_API}/accounts/2iqph")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
let(:client) do
|
|
14
|
+
Client.new(
|
|
15
|
+
Faker::Lorem.characters(15),
|
|
16
|
+
Faker::Lorem.characters(40),
|
|
17
|
+
"123456-#{Faker::Lorem.characters(40)}",
|
|
18
|
+
Faker::Lorem.characters(40)
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:account) { client.accounts.first }
|
|
23
|
+
|
|
24
|
+
describe '#initialize' do
|
|
25
|
+
|
|
26
|
+
let(:account) { TwitterAds::Account.new(client) }
|
|
27
|
+
let(:methods) {
|
|
28
|
+
%w(features promotable_users funding_instruments campaigns line_items)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
it 'raises an ArgumentError error if used without initialization' do
|
|
32
|
+
expect(account).to receive(:validate_loaded).and_call_original.exactly(methods.size).times
|
|
33
|
+
methods.each { |meth| expect { account.send(meth) }.to raise_error(ArgumentError) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#inspect' do
|
|
39
|
+
|
|
40
|
+
it 'includes the object id value' do
|
|
41
|
+
expect(account.inspect).to include(account.object_id.to_s)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'includes the class.name value' do
|
|
45
|
+
expect(account.inspect).to include(account.class.name)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'includes the Account ID value' do
|
|
49
|
+
expect(account.inspect).to include(account.id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '#features' do
|
|
55
|
+
|
|
56
|
+
before(:each) do
|
|
57
|
+
stub_fixture(:get, :accounts_features, "#{ADS_API}/accounts/#{account.id}/features")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'successfully returns a list of features available' do
|
|
61
|
+
features = account.features
|
|
62
|
+
expect(features).not_to be_nil
|
|
63
|
+
expect(features).to all(be_a(String))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe '#promotable_users' do
|
|
69
|
+
|
|
70
|
+
before(:each) do
|
|
71
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/promotable_users"
|
|
72
|
+
stub_fixture(:get, :promotable_users_all, resource_collection)
|
|
73
|
+
|
|
74
|
+
resource = "#{ADS_API}/accounts/#{account.id}/promotable_users/4k"
|
|
75
|
+
stub_fixture(:get, :promotable_users_load, /#{resource}\?.*/)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context 'with an id specified' do
|
|
79
|
+
|
|
80
|
+
it 'succesfully loads the specified promoted tweet' do
|
|
81
|
+
result = account.promotable_users('4k')
|
|
82
|
+
expect(result).not_to be_nil
|
|
83
|
+
expect(result.class).to eq(TwitterAds::PromotableUser)
|
|
84
|
+
expect(result.id).to eq('4k')
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context 'without an id specified' do
|
|
90
|
+
|
|
91
|
+
it 'succesfully returns a Cursor with all promoted tweets' do
|
|
92
|
+
result = account.promotable_users
|
|
93
|
+
expect(result.size).to eq(5)
|
|
94
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
95
|
+
expect(result.first.class).to eq(TwitterAds::PromotableUser)
|
|
96
|
+
expect(result.first.id).to eq('4k')
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe '#funding_instruments' do
|
|
104
|
+
|
|
105
|
+
before(:each) do
|
|
106
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/funding_instruments"
|
|
107
|
+
stub_fixture(:get, :funding_instruments_all, resource_collection)
|
|
108
|
+
|
|
109
|
+
resource = "#{ADS_API}/accounts/#{account.id}/funding_instruments/5aa0p"
|
|
110
|
+
stub_fixture(:get, :funding_instruments_load, /#{resource}\?.*/)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
context 'with an id specified' do
|
|
114
|
+
|
|
115
|
+
it 'succesfully loads the specified promoted tweet' do
|
|
116
|
+
result = account.funding_instruments('5aa0p')
|
|
117
|
+
expect(result).not_to be_nil
|
|
118
|
+
expect(result.class).to eq(TwitterAds::FundingInstrument)
|
|
119
|
+
expect(result.id).to eq('5aa0p')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context 'without an id specified' do
|
|
125
|
+
|
|
126
|
+
it 'succesfully returns a Cursor with all promoted tweets' do
|
|
127
|
+
result = account.funding_instruments
|
|
128
|
+
expect(result.size).to eq(3)
|
|
129
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
130
|
+
expect(result.first.class).to eq(TwitterAds::FundingInstrument)
|
|
131
|
+
expect(result.first.id).to eq('5aa0p')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe '#campaigns' do
|
|
139
|
+
|
|
140
|
+
before(:each) do
|
|
141
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/campaigns"
|
|
142
|
+
stub_fixture(:get, :campaigns_all, resource_collection)
|
|
143
|
+
|
|
144
|
+
resource = "#{ADS_API}/accounts/#{account.id}/campaigns/2wap7"
|
|
145
|
+
stub_fixture(:get, :campaigns_load, /#{resource}\?.*/)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context 'with an id specified' do
|
|
149
|
+
|
|
150
|
+
it 'succesfully loads the specified promoted tweet' do
|
|
151
|
+
result = account.campaigns('2wap7')
|
|
152
|
+
expect(result).not_to be_nil
|
|
153
|
+
expect(result.class).to eq(TwitterAds::Campaign)
|
|
154
|
+
expect(result.id).to eq('2wap7')
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
context 'without an id specified' do
|
|
160
|
+
|
|
161
|
+
it 'succesfully returns a Cursor with all promoted tweets' do
|
|
162
|
+
result = account.campaigns
|
|
163
|
+
expect(result.size).to eq(10)
|
|
164
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
165
|
+
expect(result.first.class).to eq(TwitterAds::Campaign)
|
|
166
|
+
expect(result.first.id).to eq('2wap7')
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
describe '#line_items' do
|
|
174
|
+
|
|
175
|
+
before(:each) do
|
|
176
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/line_items"
|
|
177
|
+
stub_fixture(:get, :line_items_all, resource_collection)
|
|
178
|
+
|
|
179
|
+
resource = "#{ADS_API}/accounts/#{account.id}/line_items/bw2"
|
|
180
|
+
stub_fixture(:get, :line_items_load, /#{resource}\?.*/)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
context 'with an id specified' do
|
|
184
|
+
|
|
185
|
+
it 'succesfully loads the specified promoted tweet' do
|
|
186
|
+
result = account.line_items('bw2')
|
|
187
|
+
expect(result).not_to be_nil
|
|
188
|
+
expect(result.class).to eq(TwitterAds::LineItem)
|
|
189
|
+
expect(result.id).to eq('bw2')
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
context 'without an id specified' do
|
|
195
|
+
|
|
196
|
+
it 'succesfully returns a Cursor with all promoted tweets' do
|
|
197
|
+
result = account.line_items
|
|
198
|
+
expect(result.size).to eq(10)
|
|
199
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
200
|
+
expect(result.first.class).to eq(TwitterAds::LineItem)
|
|
201
|
+
expect(result.first.id).to eq('bw2')
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe '#app_lists' do
|
|
209
|
+
|
|
210
|
+
before(:each) do
|
|
211
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/app_lists"
|
|
212
|
+
stub_fixture(:get, :app_lists_all, resource_collection)
|
|
213
|
+
|
|
214
|
+
resource = "#{ADS_API}/accounts/#{account.id}/app_lists/abc2"
|
|
215
|
+
stub_fixture(:get, :app_lists_load, /#{resource}\?.*/)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context 'with an id specified' do
|
|
219
|
+
|
|
220
|
+
it 'successfully loads the specified app list' do
|
|
221
|
+
result = account.app_lists('abc2')
|
|
222
|
+
expect(result).not_to be_nil
|
|
223
|
+
expect(result.class).to eq(TwitterAds::AppList)
|
|
224
|
+
expect(result.id).to eq('abc2')
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
context 'without an id specified' do
|
|
230
|
+
|
|
231
|
+
it 'succesfully returns a cursor with all app lists' do
|
|
232
|
+
result = account.app_lists
|
|
233
|
+
expect(result.to_a.size).to eq(3)
|
|
234
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
235
|
+
expect(result.first.class).to eq(TwitterAds::AppList)
|
|
236
|
+
expect(result.first.id).to eq('abc2')
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe '#tailored_audiences' do
|
|
244
|
+
|
|
245
|
+
before(:each) do
|
|
246
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/tailored_audiences"
|
|
247
|
+
stub_fixture(:get, :tailored_audiences_all, resource_collection)
|
|
248
|
+
|
|
249
|
+
resource = "#{ADS_API}/accounts/#{account.id}/tailored_audiences/abc2"
|
|
250
|
+
stub_fixture(:get, :tailored_audiences_load, /#{resource}\?.*/)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
context 'with an id specified' do
|
|
254
|
+
|
|
255
|
+
it 'successfully loads the specified tailored audience' do
|
|
256
|
+
result = account.tailored_audiences('abc2')
|
|
257
|
+
expect(result).not_to be_nil
|
|
258
|
+
expect(result.class).to eq(TwitterAds::TailoredAudience)
|
|
259
|
+
expect(result.id).to eq('abc2')
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
context 'without an id specified' do
|
|
265
|
+
|
|
266
|
+
it 'succesfully returns a cursor with all tailored audiences' do
|
|
267
|
+
result = account.tailored_audiences
|
|
268
|
+
expect(result.to_a.size).to eq(3)
|
|
269
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
270
|
+
expect(result.first.class).to eq(TwitterAds::TailoredAudience)
|
|
271
|
+
expect(result.first.id).to eq('abc2')
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe '#videos' do
|
|
279
|
+
|
|
280
|
+
let!(:video_id) { 'd5e3ae4d-34c4-4f49-894e-0c17735916a4' }
|
|
281
|
+
|
|
282
|
+
before(:each) do
|
|
283
|
+
resource_collection = "#{ADS_API}/accounts/#{account.id}/videos"
|
|
284
|
+
stub_fixture(:get, :videos_all, resource_collection)
|
|
285
|
+
|
|
286
|
+
resource = "#{ADS_API}/accounts/#{account.id}/videos/#{video_id}"
|
|
287
|
+
stub_fixture(:get, :videos_load, /#{resource}\?.*/)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
context 'with an id specified' do
|
|
291
|
+
|
|
292
|
+
it 'successfully loads the specified video' do
|
|
293
|
+
result = account.videos(video_id)
|
|
294
|
+
expect(result).not_to be_nil
|
|
295
|
+
expect(result.class).to eq(TwitterAds::Video)
|
|
296
|
+
expect(result.id).to eq(video_id)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
context 'without an id specified' do
|
|
302
|
+
|
|
303
|
+
it 'succesfully returns a cursor with all videos' do
|
|
304
|
+
result = account.videos
|
|
305
|
+
expect(result.to_a.size).to eq(3)
|
|
306
|
+
expect(result.class).to eq(TwitterAds::Cursor)
|
|
307
|
+
expect(result.first.class).to eq(TwitterAds::Video)
|
|
308
|
+
expect(result.first.id).to eq(video_id)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
end
|