* spelling: access Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: additional Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: administrative Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: aggregate Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: assigns Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: attributes Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: autocomplete Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: because Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: between Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: bootstrap Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: calculating Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: captcha Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: character Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: chosen Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: commenter Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: competitor Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: componentize Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: contrast Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: corresponding Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: description Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: destroyed Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: destroys Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: discussion Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: episode Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: escaped Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: evaluates Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: expired Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: explicitly Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: facebook Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: fragment Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: functionality Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: improper Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: incentive Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: interfere Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: latest Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: message Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: minimum Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: moderator Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: mouseover Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: mutual Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: nonexistent Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: notification Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: occasionally Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: occurrence Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: occurs Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: octokit Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: offset Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: omitted Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: opacity Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: organization Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: organizations Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: overridden Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: override Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: overriding Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: prefill Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: previous Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: profile Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: recycling Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: registered Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: repositories Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: rescuing Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: response Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: returns Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: second Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: separator Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: services Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: subscriber Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: subscription Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: success Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: successful Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: successfully Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: suppress Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: test Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: thought Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: uniqueness Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unknown Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unproductive Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unreachable Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unsuccessful Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: utilities Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: utility Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: valid Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: voluntarily Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: vomited Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: website Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: withholding Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
141 lines
5.5 KiB
Ruby
141 lines
5.5 KiB
Ruby
require "rails_helper"
|
|
|
|
RSpec.describe Tweet, type: :model, vcr: true do
|
|
let(:tweet_id) { "1018911886862057472" }
|
|
let(:tweet_reply_id) { "1242938461784608770" }
|
|
let(:retweet_id) { "1262395854469677058" }
|
|
|
|
it { is_expected.to validate_presence_of(:twitter_id_code) }
|
|
it { is_expected.to validate_presence_of(:full_fetched_object_serialized) }
|
|
|
|
describe ".find_or_fetch" do
|
|
context "when retrieving a tweet", vcr: { cassette_name: "twitter_client_status_extended" } do
|
|
it "saves a new tweet" do
|
|
expect do
|
|
described_class.find_or_fetch(tweet_id)
|
|
end.to change(described_class, :count).by(1)
|
|
end
|
|
|
|
it "retrieves an existing tweet" do
|
|
created_tweet = described_class.find_or_fetch(tweet_id)
|
|
|
|
expect do
|
|
found_tweet = described_class.find_or_fetch(tweet_id)
|
|
expect(found_tweet.id).to eq(created_tweet.id)
|
|
end.not_to change(described_class, :count)
|
|
end
|
|
|
|
it "saves the proper status ID and text" do
|
|
tweet = described_class.find_or_fetch(tweet_id)
|
|
|
|
status = tweet.full_fetched_object_serialized
|
|
|
|
expect(tweet.text).to eq(status[:full_text])
|
|
expect(tweet.twitter_id_code).to eq(status[:id_str])
|
|
end
|
|
|
|
it "saves the proper metadata attributes", :aggregate_failures do
|
|
tweet = described_class.find_or_fetch(tweet_id)
|
|
|
|
status = tweet.full_fetched_object_serialized
|
|
|
|
expect(tweet.favorite_count).to eq(status[:favorite_count])
|
|
expect(tweet.in_reply_to_status_id_code).to be_empty
|
|
expect(tweet.in_reply_to_user_id_code).to be_empty
|
|
expect(tweet.in_reply_to_username).to be_empty
|
|
expect(tweet.is_quote_status).to be(false)
|
|
expect(tweet.quoted_tweet_id_code).to eq(status[:quoted_status_id_str])
|
|
expect(tweet.retweet_count).to eq(status[:retweet_count])
|
|
expect(tweet.source).to eq(status[:source])
|
|
expect(tweet.tweeted_at.to_i).to eq(Time.zone.parse(status[:created_at]).to_i)
|
|
end
|
|
|
|
it "saves the proper serializable attributes", :aggregate_failures do
|
|
tweet = described_class.find_or_fetch(tweet_id)
|
|
|
|
status = tweet.full_fetched_object_serialized
|
|
expect(status).to be_present
|
|
|
|
expect(tweet.extended_entities_serialized).to eq(status[:extended_entities])
|
|
expect(tweet.hashtags_serialized).to eq(status[:entities][:hashtags])
|
|
expect(tweet.media_serialized).to eq(status[:entities][:media])
|
|
expect(tweet.mentioned_usernames_serialized).to be_empty
|
|
expect(tweet.urls_serialized).to eq(status[:entities][:urls])
|
|
end
|
|
|
|
it "saves the proper user attributes", :aggregate_failures do
|
|
tweet = described_class.find_or_fetch(tweet_id)
|
|
|
|
status = tweet.full_fetched_object_serialized
|
|
status_user = status[:user]
|
|
|
|
expect(tweet.remote_profile_image_url.to_s).to eq(status_user[:profile_image_url])
|
|
expect(tweet.twitter_name).to eq(status_user[:name])
|
|
expect(tweet.twitter_uid).to eq(status_user[:id_str])
|
|
expect(tweet.twitter_user_followers_count).to eq(status_user[:followers_count])
|
|
expect(tweet.twitter_user_following_count).to eq(status_user[:friends_count])
|
|
expect(tweet.twitter_username).to eq(status_user[:screen_name].downcase)
|
|
expect(tweet.user_is_verified).to be(status_user[:verified])
|
|
end
|
|
|
|
it "sets #last_fetched_at" do
|
|
tweet = described_class.find_or_fetch(tweet_id)
|
|
expect(tweet.last_fetched_at).to be_present
|
|
end
|
|
|
|
it "is assigns to the existing user if the screen name corresponds" do
|
|
user = create(:user, twitter_username: "ThePracticalDev")
|
|
|
|
tweet = described_class.find_or_fetch(tweet_id)
|
|
expect(tweet.user_id).to eq(user.id)
|
|
end
|
|
end
|
|
|
|
context "when retrieving non existent tweet", vcr: { cassette_name: "twitter_client_status_not_found_extended" } do
|
|
it "raises an error if the tweet does not exist" do
|
|
expect { described_class.find_or_fetch("0") }.to raise_error(TwitterClient::Errors::NotFound)
|
|
end
|
|
end
|
|
|
|
context "when retrieving a reply tweet", vcr: { cassette_name: "twitter_client_status_reply_extended" } do
|
|
it "saves a new tweet" do
|
|
expect do
|
|
described_class.find_or_fetch(tweet_reply_id)
|
|
end.to change(described_class, :count).by(1)
|
|
end
|
|
|
|
it "retrieves an existing tweet" do
|
|
created_tweet = described_class.find_or_fetch(tweet_reply_id)
|
|
|
|
expect do
|
|
found_tweet = described_class.find_or_fetch(tweet_reply_id)
|
|
expect(found_tweet.id).to eq(created_tweet.id)
|
|
end.not_to change(described_class, :count)
|
|
end
|
|
|
|
it "saves the proper reply fields" do
|
|
tweet = described_class.find_or_fetch(tweet_reply_id)
|
|
|
|
status = tweet.full_fetched_object_serialized
|
|
|
|
expect(tweet.in_reply_to_status_id_code).to eq(status[:in_reply_to_status_id_str])
|
|
expect(tweet.in_reply_to_user_id_code).to eq(status[:in_reply_to_user_id_str])
|
|
expect(tweet.in_reply_to_username).to eq(status[:in_reply_to_screen_name])
|
|
end
|
|
end
|
|
|
|
context "when retrieving a reply tweet", vcr: { cassette_name: "twitter_client_status_retweet_extended" } do
|
|
it "saves a new tweet" do
|
|
expect do
|
|
described_class.find_or_fetch(retweet_id)
|
|
end.to change(described_class, :count).by(1)
|
|
end
|
|
|
|
it "saves the proper status ID" do
|
|
tweet = described_class.find_or_fetch(retweet_id)
|
|
|
|
expect(tweet.twitter_id_code).not_to eq(retweet_id) # we fetch the original tweet
|
|
end
|
|
end
|
|
end
|
|
end
|