Prior to this fix, in the production rails console we ran the following:
```ruby
Articles::Feeds::WeightedQueryStrategy
.new(user: nil, page: 1, tags: nil)
.featured_story_and_default_home_feed(user_signed_in: false)
```
The result was: `[nil, []]`. Which in the
[StoriesController#assign_feed_stories][1] is where we have the
following:
```ruby
@featured_story, @stories = feed
.featured_story_and_default_home_feed(
user_signed_in: user_signed_in?)
```
In Blazer, I ran the following query at 2021-12-02 Thu 20:41 EST:
```sql
SELECT * FROM articles
WHERE featured = true
AND published = true
AND published_at > (NOW() - interval '7 days')
AND published_at < NOW()
AND main_image IS NOT NULL
```
So the logic of filtering with `only_featured` resulted in the
`@featured_story` being `nil`. Which then cascaded into the logic for
determining the remainder of the results.
For further discussion see the inline comments and specs that I wrote.
In addition to the above, I'm also reusing
`Articles::Feeds::FindFeaturedStory`
Prior to this commit, the `Articles::Feeds::WeightedQueryStrategy` first
grabbed the featured story, then grabbed the remaining articles. This
is different than the implementation of the
`Articles::Feeds::LargeForemExperimental` in which we first grab all the
articles then claim one as the featured.
In the WeightedQueryStrategy, the articles would not include the
featured. However, in the LargeForemExperimental it would. This
results in upstream logic in [app/javascript/articles/Feed.jsx][2]
going through and removing one of the articles.
[1]:c1a3ba99eb/app/controllers/stories_controller.rb (L237-L271)
[2]:c1a3ba99eb/app/javascript/articles/Feed.jsx (L57-L63)
52 lines
2 KiB
Ruby
52 lines
2 KiB
Ruby
require "rails_helper"
|
|
|
|
RSpec.describe Articles::Feeds do
|
|
describe ".oldest_published_at_to_consider_for" do
|
|
subject(:function_call) { described_class.oldest_published_at_to_consider_for(user: user) }
|
|
|
|
context "when the given user is nil" do
|
|
let(:user) { nil }
|
|
|
|
it "returns Article::Feeds::DEFAULT_DAYS_SINCE_PUBLISHED days ago" do
|
|
# Why the to_date coercion? Because Integer.days.ago is an
|
|
# ActiveSupport::TimeWithZone variable that includes
|
|
# microseconds, and in the time between the function_call and
|
|
# the expectation test, there's a few microseconds that passed
|
|
# (based on your processor). In theory, this test might fail
|
|
# if someone ran the test right around the stroke of midnight.
|
|
expect(function_call.to_date).to eq(Articles::Feeds::DEFAULT_DAYS_SINCE_PUBLISHED.days.ago.to_date)
|
|
end
|
|
end
|
|
|
|
context "when the given user has no page views" do
|
|
let(:user) { instance_double(User) }
|
|
|
|
before do
|
|
allow(user).to receive(:page_views).and_return(nil)
|
|
end
|
|
|
|
it { is_expected.to be_a ActiveSupport::TimeWithZone }
|
|
end
|
|
|
|
context "when the user has page views" do
|
|
let(:user) { instance_double(User) }
|
|
let(:page_viewed_at) { Time.current }
|
|
let(:expected_result) do
|
|
page_viewed_at - described_class::NUMBER_OF_HOURS_TO_OFFSET_USERS_LATEST_ARTICLE_VIEWS.hours
|
|
end
|
|
|
|
before do
|
|
# This is a distinct code smell. The other option is adding a
|
|
# method to user and perhaps to page views and then testing
|
|
# delegation. This is, instead, an ActiveRecord call chain,
|
|
# so I'm going to ask that we accept this smell to ease
|
|
# testing.
|
|
# rubocop:disable RSpec/MessageChain
|
|
allow(user).to receive_message_chain(:page_views, :second_to_last, :created_at).and_return(page_viewed_at)
|
|
# rubocop:enable RSpec/MessageChain
|
|
end
|
|
|
|
it { is_expected.to eq(expected_result) }
|
|
end
|
|
end
|
|
end
|