mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-10-31 03:09:06 -04:00
Admins switch features on and off at /admin/features, kept in Flipper. Job ideas (the page, the banners and the overlay) only show while its flag is on. Features are off until switched on. Closes #5050
224 lines
6.6 KiB
Ruby
224 lines
6.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe JobIdeasController, flipper: :job_ideas do
|
|
include ActiveSupport::Testing::TimeHelpers
|
|
|
|
let(:member) { create(:member) }
|
|
let(:today) { Date.new(2026, 10, 23) }
|
|
let(:crop) { create(:crop, name: 'garlic', perennial: false) }
|
|
|
|
before do
|
|
travel_to(today.in_time_zone.change(hour: 12))
|
|
sign_in member
|
|
create(:job, :finished_without_time, owner: member, name: 'Snip off scapes', due_date: Date.new(2025, 10, 28), jobbable: crop)
|
|
end
|
|
|
|
describe 'GET /job_ideas' do
|
|
before { get job_ideas_path }
|
|
|
|
it 'responds with ok' do
|
|
expect(response).to have_http_status(:ok)
|
|
end
|
|
|
|
it 'suggests the job' do
|
|
expect(Capybara.string(response.body)).to have_css('.job-ideas', text: 'Snip off scapes')
|
|
end
|
|
|
|
it 'says why' do
|
|
expect(response.body).to include('You did this on 28 Oct.')
|
|
end
|
|
|
|
it 'does not point to itself with the yellow box' do
|
|
expect(Capybara.string(response.body)).to have_no_css('.notepad-ideas')
|
|
end
|
|
|
|
it 'shows the notepad beside the ideas' do
|
|
expect(response.body).to include('notepad-groups')
|
|
end
|
|
|
|
it 'names the section' do
|
|
expect(response.body).to include('At this time of year')
|
|
end
|
|
end
|
|
|
|
describe 'GET /job_ideas with a source switched off' do
|
|
before { get job_ideas_path(skip: ['mine']) }
|
|
|
|
it 'leaves out what that source suggests' do
|
|
expect(Capybara.string(response.body)).to have_no_css('.job-ideas', text: 'Snip off scapes')
|
|
end
|
|
end
|
|
|
|
describe 'GET /job_ideas with a template for a crop they grow' do
|
|
let(:page) { Capybara.string(response.body) }
|
|
let(:tomato) { create(:crop, name: 'tomato') }
|
|
let(:template) { create(:crop_job_template, crop: tomato, status: 'published') }
|
|
|
|
before do
|
|
create(:planting, owner: member, crop: tomato, planted_at: today - 1.day)
|
|
create(:crop_job_step, crop_job_template: template, name: 'Stake', offset_amount: 2)
|
|
create(:crop_job_step, crop_job_template: template, name: 'Feed', offset_amount: 4)
|
|
get job_ideas_path
|
|
end
|
|
|
|
it 'offers to add all its jobs' do
|
|
expect(page).to have_button('Add all 2')
|
|
end
|
|
|
|
it 'lists the jobs before they are added' do
|
|
expect(page).to have_css('.idea-preview li', count: 2, visible: :all)
|
|
end
|
|
|
|
it 'gives each job\'s day' do
|
|
expect(page).to have_css('.idea-preview li', text: '5 Nov Stake', visible: :all)
|
|
end
|
|
end
|
|
|
|
describe 'GET /job_ideas from the overlay' do
|
|
before { get job_ideas_path, headers: { 'X-Requested-With' => 'XMLHttpRequest' } }
|
|
|
|
it 'sends the ideas' do
|
|
expect(response.body).to include('Snip off scapes')
|
|
end
|
|
|
|
it 'sends no page around them' do
|
|
expect(response.body).not_to include('<html')
|
|
end
|
|
end
|
|
|
|
describe 'POST /job_ideas from the overlay' do
|
|
let(:json) { response.parsed_body }
|
|
let(:crop_key) { "past_job:snip off scapes:#{crop.id}" }
|
|
|
|
before { post job_ideas_path, params: { key: crop_key }, headers: { 'X-Requested-With' => 'XMLHttpRequest' } }
|
|
|
|
it 'adds the job' do
|
|
expect(member.jobs.active.pluck(:name)).to eq ['Snip off scapes']
|
|
end
|
|
|
|
it 'says what was added' do
|
|
expect(json['added'].pluck('name')).to eq ['Snip off scapes']
|
|
end
|
|
|
|
it 'sends the ideas that are left' do
|
|
expect(json['list']).not_to include('Snip off scapes')
|
|
end
|
|
|
|
it 'sends the jobs as they now are' do
|
|
expect(json['groups']).to include('Snip off scapes')
|
|
end
|
|
|
|
it 'sends how many ideas there are' do
|
|
expect(json['count']).to eq 0
|
|
end
|
|
|
|
it 'says it in words' do
|
|
expect(json['added_label']).to eq 'Added 1 job to your list'
|
|
end
|
|
end
|
|
|
|
describe 'POST /job_ideas/hide from the overlay' do
|
|
let(:params) { { key: "past_job:snip off scapes:#{crop.id}", length: 'week' } }
|
|
|
|
before { post hide_job_ideas_path, params:, headers: { 'X-Requested-With' => 'XMLHttpRequest' } }
|
|
|
|
it 'adds nothing' do
|
|
expect(response.parsed_body['added']).to be_empty
|
|
end
|
|
|
|
it 'sends the ideas that are left' do
|
|
expect(response.parsed_body['list']).not_to include('Snip off scapes')
|
|
end
|
|
end
|
|
|
|
describe 'GET /job_ideas when signed out' do
|
|
before do
|
|
sign_out member
|
|
get job_ideas_path
|
|
end
|
|
|
|
it 'sends them to sign in' do
|
|
expect(response).to redirect_to(new_member_session_path)
|
|
end
|
|
end
|
|
|
|
describe 'GET /job_ideas when job ideas are switched off', flipper: [] do
|
|
before { get job_ideas_path }
|
|
|
|
it 'is not found' do
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
end
|
|
|
|
describe 'POST /job_ideas' do
|
|
let(:key) { "past_job:snip off scapes:#{crop.id}" }
|
|
|
|
before { post job_ideas_path, params: { key: } }
|
|
|
|
it 'adds the job' do
|
|
expect(member.jobs.active.pluck(:name)).to eq ['Snip off scapes']
|
|
end
|
|
|
|
it 'adds it about the crop' do
|
|
expect(member.jobs.active.first.jobbable).to eq crop
|
|
end
|
|
|
|
it 'goes back to the ideas' do
|
|
expect(response).to redirect_to(job_ideas_path)
|
|
end
|
|
|
|
context 'with an idea that is not on offer' do
|
|
let(:key) { 'past_job:something else:' }
|
|
|
|
it 'adds nothing' do
|
|
expect(member.jobs.active).to be_empty
|
|
end
|
|
end
|
|
|
|
context 'with a planting idea' do
|
|
let(:key) { "past_planting:#{crop.id}" }
|
|
|
|
before do
|
|
create(:planting, owner: member, crop:, planted_at: Date.new(2025, 10, 28))
|
|
post job_ideas_path, params: { key: }
|
|
end
|
|
|
|
it 'adds a job to plant the crop' do
|
|
expect(member.jobs.action_plant.pluck(:name)).to eq ['Plant garlic']
|
|
end
|
|
|
|
it 'no longer suggests it' do
|
|
expect(JobIdeas.new(member, today:).ideas.map(&:key)).not_to include(key)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /job_ideas/hide' do
|
|
let(:key) { "past_job:snip off scapes:#{crop.id}" }
|
|
let(:hidden) { member.job_idea_dismissals.hiding.find_by(key:) }
|
|
|
|
it 'snoozes for a week' do
|
|
post hide_job_ideas_path, params: { key:, length: 'week' }
|
|
expect(hidden.hidden_until).to be_within(1.minute).of(1.week.from_now)
|
|
end
|
|
|
|
it 'dismisses for a year without a length' do
|
|
post hide_job_ideas_path, params: { key: }
|
|
expect(hidden.hidden_until).to be_within(1.minute).of(1.year.from_now)
|
|
end
|
|
|
|
it 'dismisses for a year with a length it does not offer' do
|
|
post hide_job_ideas_path, params: { key:, length: 'decade' }
|
|
expect(hidden.hidden_until).to be_within(1.minute).of(1.year.from_now)
|
|
end
|
|
|
|
it 'stops suggesting it' do
|
|
post hide_job_ideas_path, params: { key: }
|
|
get job_ideas_path
|
|
expect(Capybara.string(response.body)).to have_no_css('.job-ideas', text: 'Snip off scapes')
|
|
end
|
|
end
|
|
end
|