mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-18 13:38:24 -04:00
Merge remote-tracking branch 'upstream/dev' into feature/memcachier
This commit is contained in:
15
Gemfile
15
Gemfile
@@ -21,6 +21,8 @@ gem 'font-awesome-sass'
|
||||
|
||||
gem 'uglifier' # JavaScript compressor
|
||||
|
||||
gem 'oj' # Speeds up json
|
||||
|
||||
# planting and harvest predictions
|
||||
# based on median values for the crop
|
||||
gem 'active_median', '0.1.4' # needs postgresql update https://github.com/Growstuff/growstuff/issues/1757
|
||||
@@ -78,17 +80,12 @@ gem 'omniauth-facebook'
|
||||
gem 'omniauth-flickr', '>= 0.0.15'
|
||||
gem 'omniauth-twitter'
|
||||
|
||||
# Pretty charts
|
||||
gem "chartkick"
|
||||
|
||||
# client for Elasticsearch. Elasticsearch is a flexible
|
||||
# and powerful, distributed, real-time search and analytics engine.
|
||||
# An example of the use in the project is fuzzy crop search.
|
||||
# Project does not use semver, so we want to be in sync with the version of
|
||||
# elasticsearch we use
|
||||
# See https://github.com/elastic/elasticsearch-ruby#compatibility
|
||||
gem "elasticsearch-api", "~> 6.0.0"
|
||||
gem "elasticsearch-model", "~> 6.0.0"
|
||||
gem "elasticsearch-rails", "~> 6.0.0"
|
||||
# clever elastic search
|
||||
gem 'searchkick'
|
||||
|
||||
gem "hashie", ">= 3.5.3"
|
||||
|
||||
gem 'rake', '>= 10.0.0'
|
||||
|
||||
52
Gemfile.lock
52
Gemfile.lock
@@ -79,8 +79,8 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (11.0.1)
|
||||
cancancan (2.3.0)
|
||||
capybara (3.15.0)
|
||||
cancancan (3.0.1)
|
||||
capybara (3.16.2)
|
||||
addressable
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (~> 1.8)
|
||||
@@ -134,7 +134,7 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
dalli (2.7.10)
|
||||
database_cleaner (1.7.0)
|
||||
devise (4.6.1)
|
||||
devise (4.6.2)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0, < 6.0)
|
||||
@@ -142,17 +142,17 @@ GEM
|
||||
warden (~> 1.2.3)
|
||||
diff-lcs (1.3)
|
||||
docile (1.1.5)
|
||||
elasticsearch (6.0.3)
|
||||
elasticsearch-api (= 6.0.3)
|
||||
elasticsearch-transport (= 6.0.3)
|
||||
elasticsearch-api (6.0.3)
|
||||
elasticsearch (6.2.0)
|
||||
elasticsearch-api (= 6.2.0)
|
||||
elasticsearch-transport (= 6.2.0)
|
||||
elasticsearch-api (6.2.0)
|
||||
multi_json
|
||||
elasticsearch-model (6.0.0)
|
||||
activesupport (> 3)
|
||||
elasticsearch (> 1)
|
||||
hashie
|
||||
elasticsearch-rails (6.0.0)
|
||||
elasticsearch-transport (6.0.3)
|
||||
elasticsearch-transport (6.2.0)
|
||||
faraday
|
||||
multi_json
|
||||
erubi (1.8.0)
|
||||
@@ -212,7 +212,7 @@ GEM
|
||||
excon
|
||||
moneta
|
||||
multi_json (>= 1.9.2)
|
||||
highline (2.0.0)
|
||||
highline (2.0.1)
|
||||
html2haml (2.2.0)
|
||||
erubis (~> 2.7.0)
|
||||
haml (>= 4.0, < 6)
|
||||
@@ -223,7 +223,7 @@ GEM
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (1.6.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-tasks (0.9.28)
|
||||
i18n-tasks (0.9.29)
|
||||
activesupport (>= 4.0.2)
|
||||
ast (>= 2.1.0)
|
||||
erubi
|
||||
@@ -240,11 +240,11 @@ GEM
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (6.0.1)
|
||||
railties (>= 3.2.16)
|
||||
js-routes (1.4.4)
|
||||
railties (>= 3.2)
|
||||
js-routes (1.4.6)
|
||||
railties (>= 4)
|
||||
sprockets-rails
|
||||
json (2.1.0)
|
||||
jsonapi-resources (0.9.5)
|
||||
jsonapi-resources (0.9.6)
|
||||
activerecord (>= 4.1)
|
||||
concurrent-ruby
|
||||
railties (>= 4.1)
|
||||
@@ -265,7 +265,7 @@ GEM
|
||||
kramdown (2.1.0)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
leaflet-rails (1.3.1)
|
||||
leaflet-rails (1.4.0)
|
||||
rails (>= 4.2.0)
|
||||
letter_opener (1.7.0)
|
||||
launchy (~> 2.2)
|
||||
@@ -296,7 +296,7 @@ GEM
|
||||
multipart-post (2.0.0)
|
||||
newrelic_rpm (6.2.0.354)
|
||||
nio4r (2.3.1)
|
||||
nokogiri (1.10.1)
|
||||
nokogiri (1.10.2)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
oauth (0.5.4)
|
||||
oauth2 (1.4.1)
|
||||
@@ -305,6 +305,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.7.11)
|
||||
omniauth (1.9.0)
|
||||
hashie (>= 3.4.6, < 3.7.0)
|
||||
rack (>= 1.6.2, < 3)
|
||||
@@ -323,10 +324,10 @@ GEM
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
orm_adapter (0.5.0)
|
||||
parallel (1.14.0)
|
||||
parallel (1.17.0)
|
||||
paranoia (2.4.1)
|
||||
activerecord (>= 4.0, < 5.3)
|
||||
parser (2.6.0.0)
|
||||
parser (2.6.2.1)
|
||||
ast (~> 2.4.0)
|
||||
pg (0.21.0)
|
||||
platform-api (2.2.0)
|
||||
@@ -339,7 +340,7 @@ GEM
|
||||
psych (3.1.0)
|
||||
public_suffix (3.0.3)
|
||||
puma (3.12.1)
|
||||
rack (2.0.6)
|
||||
rack (2.0.7)
|
||||
rack-protection (2.0.5)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
@@ -390,7 +391,7 @@ GEM
|
||||
rb-inotify (0.10.0)
|
||||
ffi (~> 1.0)
|
||||
redis (4.1.0)
|
||||
regexp_parser (1.3.0)
|
||||
regexp_parser (1.4.0)
|
||||
responders (2.4.1)
|
||||
actionpack (>= 4.2.0, < 6.0)
|
||||
railties (>= 4.2.0, < 6.0)
|
||||
@@ -415,7 +416,7 @@ GEM
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-support (3.8.0)
|
||||
rubocop (0.66.0)
|
||||
rubocop (0.67.2)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.5, != 2.5.1.1)
|
||||
@@ -452,11 +453,15 @@ GEM
|
||||
sprockets-rails
|
||||
tilt
|
||||
scout_apm (2.4.24)
|
||||
searchkick (3.1.2)
|
||||
activemodel (>= 4.2)
|
||||
elasticsearch (>= 5)
|
||||
hashie
|
||||
selenium-webdriver (3.141.0)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.2, >= 1.2.2)
|
||||
sexp_processor (4.12.0)
|
||||
sidekiq (5.2.5)
|
||||
sidekiq (5.2.6)
|
||||
connection_pool (~> 2.2, >= 2.2.2)
|
||||
rack (>= 1.5.0)
|
||||
rack-protection (>= 1.5.0)
|
||||
@@ -536,9 +541,6 @@ DEPENDENCIES
|
||||
dalli
|
||||
database_cleaner
|
||||
devise
|
||||
elasticsearch-api (~> 6.0.0)
|
||||
elasticsearch-model (~> 6.0.0)
|
||||
elasticsearch-rails (~> 6.0.0)
|
||||
factory_bot_rails
|
||||
faker
|
||||
figaro
|
||||
@@ -565,6 +567,7 @@ DEPENDENCIES
|
||||
loofah (>= 2.2.1)
|
||||
memcachier
|
||||
newrelic_rpm
|
||||
oj
|
||||
omniauth (~> 1.3)
|
||||
omniauth-facebook
|
||||
omniauth-flickr (>= 0.0.15)
|
||||
@@ -588,6 +591,7 @@ DEPENDENCIES
|
||||
ruby-units
|
||||
sass-rails
|
||||
scout_apm
|
||||
searchkick
|
||||
selenium-webdriver
|
||||
sidekiq
|
||||
timecop
|
||||
|
||||
@@ -17,7 +17,7 @@ encourage participation from people of all backgrounds and skill levels.
|
||||
|
||||
## Important links
|
||||
|
||||
* [Issues](http://github.com/Growstuff/growstuff/issues) (features we're
|
||||
* [Issues](https://github.com/orgs/Growstuff/projects/1) (features we're
|
||||
working on, known bugs, etc)
|
||||
* [IRC](https://webchat.freenode.net/) growstuff channel (general chat, brainstorming and troubleshooting) or [Gitter](https://gitter.im/Growstuff/growstuff)
|
||||
* [Wiki](https://github.com/Growstuff/growstuff/wiki) (general documentation, etc. Help by migrating from the [old wiki](https://web.archive.org/web/*/wiki.growstuff.org))
|
||||
@@ -44,9 +44,9 @@ You might like to check out:
|
||||
|
||||
Here on Github, you might find these useful:
|
||||
|
||||
* [Waffle](http://waffle.io/Growstuff/growstuff) has stories in "ready" that can be worked on.
|
||||
* [Github Project Board](https://github.com/orgs/Growstuff/projects/1) has stories in "ready" that can be worked on.
|
||||
* [needs: design](https://github.com/Growstuff/growstuff/labels/needs:%20design) - tasks requiring high-level design
|
||||
* [needs: visual design](https://github.com/Growstuff/growstuff/labels/needs:%20visual design) - tasks requiring visual/graphical design
|
||||
* [needs: visual design](https://github.com/Growstuff/growstuff/labels/needs:%20visual+design) - tasks requiring visual/graphical design
|
||||
* [needs: documentation](https://github.com/Growstuff/growstuff/labels/needs:%20documentation)
|
||||
* [needs: data](https://github.com/Growstuff/growstuff/labels/needs:%20data) - tasks requiring data entry, data design, data import, or similar
|
||||
* [curated:beginner](https://github.com/Growstuff/growstuff/labels/curated:%20beginner) - tasks that are ideal for beginner programmers or people new to the project
|
||||
|
||||
@@ -42,14 +42,18 @@ class CropsController < ApplicationController
|
||||
|
||||
def search
|
||||
@term = params[:term]
|
||||
@matches = Crop.search(@term)
|
||||
@paginated_matches = @matches.paginate(page: params[:page])
|
||||
|
||||
respond_with @matches
|
||||
@crops = CropSearchService.search(
|
||||
@term, page: params[:page],
|
||||
per_page: 12,
|
||||
current_member: current_member
|
||||
)
|
||||
respond_with @crops
|
||||
end
|
||||
|
||||
def show
|
||||
@crop = Crop.includes(:scientific_names, plantings: :photos).find_by!(slug: params[:slug])
|
||||
@crop = Crop.includes(:scientific_names, plantings: :photos)
|
||||
.find_by!(slug: params[:slug])
|
||||
@posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
|
||||
|
||||
@photos = Photo.by_crop(@crop)
|
||||
|
||||
51
app/controllers/garden_types_controller.rb
Normal file
51
app/controllers/garden_types_controller.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
class GardenTypesController < ApplicationController
|
||||
respond_to :html, :json
|
||||
load_and_authorize_resource
|
||||
|
||||
# GET /garden_types
|
||||
def index
|
||||
@garden_types = GardenType.all.paginate(page: params[:page])
|
||||
respond_with @garden_types
|
||||
end
|
||||
|
||||
# GET /garden_types/1
|
||||
def show
|
||||
respond_with @garden_type
|
||||
end
|
||||
|
||||
# GET /garden_types/new
|
||||
def new
|
||||
@garden_type = GardenType.new
|
||||
end
|
||||
|
||||
# GET /garden_types/1/edit
|
||||
def edit; end
|
||||
|
||||
# POST /garden_types
|
||||
def create
|
||||
@garden_type = GardenType.create(garden_type_params)
|
||||
respond_with(@garden_type)
|
||||
end
|
||||
|
||||
# PATCH/PUT /garden_types/1
|
||||
def update
|
||||
@garden_type.update(garden_type_params)
|
||||
respond_with @garden_type
|
||||
end
|
||||
|
||||
# DELETE /garden_types/1
|
||||
def destroy
|
||||
@garden_type.destroy
|
||||
respond_with @garden_type
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_garden_type
|
||||
@garden_type = GardenType.find(params[:id])
|
||||
end
|
||||
|
||||
def garden_type_params
|
||||
params.require(:garden_type).permit(:description, :slug)
|
||||
end
|
||||
end
|
||||
@@ -13,6 +13,7 @@ class GardensController < ApplicationController
|
||||
@gardens = @gardens.active unless @show_all
|
||||
@gardens = @gardens.where(owner: @owner) if @owner.present?
|
||||
@gardens = @gardens.joins(:owner).order(:name).paginate(page: params[:page])
|
||||
@gardens = @gardens.includes(:owner, plantings: [:owner, crop: :parent])
|
||||
respond_with(@gardens)
|
||||
end
|
||||
|
||||
@@ -67,6 +68,6 @@ class GardensController < ApplicationController
|
||||
|
||||
def garden_params
|
||||
params.require(:garden).permit(:name, :slug, :description, :active,
|
||||
:location, :latitude, :longitude, :area, :area_unit)
|
||||
:location, :latitude, :longitude, :area, :area_unit, :garden_type_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,11 +27,9 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def required_field_help_text
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
asterisk = content_tag :span, '*', class: ['red']
|
||||
text = content_tag :em, 'denotes a required field'
|
||||
content_tag :div, asterisk + ' '.html_safe + text, class: ['margin-bottom']
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
@@ -10,8 +10,7 @@ module AutoSuggestHelper
|
||||
end
|
||||
|
||||
resource = resource.class.name.downcase
|
||||
source_path = Rails.application.routes.url_helpers.send("search_#{source}s_path")
|
||||
|
||||
source_path = Rails.application.routes.url_helpers.send("search_#{source}s_path", format: :json)
|
||||
%(
|
||||
<input id="#{source}" class="auto-suggest #{options[:class]}"
|
||||
type="text" value="#{default}" data-source-url="#{source_path}",
|
||||
|
||||
@@ -42,6 +42,10 @@ class Ability
|
||||
can :read, AlternateName do |an|
|
||||
an.crop.approved?
|
||||
end
|
||||
|
||||
cannot :create, GardenType
|
||||
cannot :update, GardenType
|
||||
cannot :destroy, GardenType
|
||||
end
|
||||
|
||||
def member_abilities(member) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
||||
@@ -124,6 +128,10 @@ class Ability
|
||||
|
||||
can :destroy, Follow
|
||||
cannot :destroy, Follow, followed_id: member.id # can't unfollow yourself
|
||||
|
||||
cannot :create, GardenType
|
||||
cannot :update, GardenType
|
||||
cannot :destroy, GardenType
|
||||
end
|
||||
|
||||
def admin_abilities(member)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
class AlternateName < ApplicationRecord
|
||||
after_commit { |an| an.crop.__elasticsearch__.index_document if an.crop && ENV['GROWSTUFF_ELASTICSEARCH'] == "true" }
|
||||
belongs_to :crop
|
||||
belongs_to :creator, class_name: 'Member', inverse_of: :created_alternate_names
|
||||
validates :name, presence: true
|
||||
validates :crop, presence: true
|
||||
|
||||
after_commit :reindex if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
|
||||
delegate :reindex, to: :crop
|
||||
end
|
||||
|
||||
@@ -8,9 +8,9 @@ class Crop < ApplicationRecord
|
||||
|
||||
##
|
||||
## Relationships
|
||||
has_many :scientific_names, after_add: :update_index, after_remove: :update_index, dependent: :destroy
|
||||
has_many :scientific_names, dependent: :destroy
|
||||
accepts_nested_attributes_for :scientific_names, allow_destroy: true, reject_if: :all_blank
|
||||
has_many :alternate_names, after_add: :update_index, after_remove: :update_index, dependent: :destroy
|
||||
has_many :alternate_names, dependent: :destroy
|
||||
has_many :plantings, dependent: :destroy
|
||||
has_many :seeds, dependent: :destroy
|
||||
has_many :harvests, dependent: :destroy
|
||||
@@ -34,6 +34,9 @@ class Crop < ApplicationRecord
|
||||
scope :interesting, -> { approved.has_photos }
|
||||
scope :has_photos, -> { includes(:photos).where.not(photos: { id: nil }) }
|
||||
|
||||
# Special scope to control if it's in the search index
|
||||
scope :search_import, -> { approved }
|
||||
|
||||
##
|
||||
## Validations
|
||||
# Reasons are only necessary when rejecting
|
||||
@@ -53,47 +56,7 @@ class Crop < ApplicationRecord
|
||||
####################################
|
||||
# Elastic search configuration
|
||||
if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
include Elasticsearch::Model
|
||||
include Elasticsearch::Model::Callbacks
|
||||
# In order to avoid clashing between different environments,
|
||||
# use Rails.env as a part of index name (eg. development_growstuff)
|
||||
index_name [Rails.env, "growstuff"].join('_')
|
||||
settings index: { number_of_shards: 1 },
|
||||
analysis: {
|
||||
tokenizer: {
|
||||
gs_edgeNGram_tokenizer: {
|
||||
type: "edgeNGram", # edgeNGram: NGram match from the start of a token
|
||||
min_gram: 3,
|
||||
max_gram: 10,
|
||||
# token_chars: Elasticsearch will split on characters
|
||||
# that don't belong to any of these classes
|
||||
token_chars: %w(letter digit)
|
||||
}
|
||||
},
|
||||
analyzer: {
|
||||
gs_edgeNGram_analyzer: {
|
||||
tokenizer: "gs_edgeNGram_tokenizer",
|
||||
filter: ["lowercase"]
|
||||
}
|
||||
}
|
||||
} do
|
||||
mappings dynamic: 'false' do
|
||||
indexes :id, type: 'long'
|
||||
indexes :name, type: 'text', analyzer: 'gs_edgeNGram_analyzer'
|
||||
indexes :approval_status, type: 'text'
|
||||
indexes :scientific_names do
|
||||
indexes :name,
|
||||
type: 'text',
|
||||
analyzer: 'gs_edgeNGram_analyzer',
|
||||
# Disabling field-length norm (norm). If the norm option is turned on(by default),
|
||||
# higher weigh would be given for shorter fields, which in our case is irrelevant.
|
||||
norms: { enabled: false }
|
||||
end
|
||||
indexes :alternate_names do
|
||||
indexes :name, type: 'text', analyzer: 'gs_edgeNGram_analyzer'
|
||||
end
|
||||
end
|
||||
end
|
||||
searchkick word_start: %i(name alternate_names scientific_names), case_sensitive: false
|
||||
end
|
||||
|
||||
def planting_photos
|
||||
@@ -108,13 +71,6 @@ class Crop < ApplicationRecord
|
||||
Photo.joins(:seeds).where("seeds.crop_id": id)
|
||||
end
|
||||
|
||||
# update the Elasticsearch index (only if we're using it in this
|
||||
# environment)
|
||||
def update_index(_name_obj)
|
||||
__elasticsearch__.index_document if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
end
|
||||
# End Elasticsearch section
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
@@ -210,14 +166,24 @@ class Crop < ApplicationRecord
|
||||
update(median_days_to_last_harvest: Planting.where(crop: self).median(:days_to_last_harvest))
|
||||
end
|
||||
|
||||
def self.search(query)
|
||||
CropSearchService.search(query)
|
||||
end
|
||||
|
||||
def self.case_insensitive_name(name)
|
||||
where(["lower(crops.name) = :value", { value: name.downcase }])
|
||||
end
|
||||
|
||||
def should_index?
|
||||
approved?
|
||||
end
|
||||
|
||||
def search_data
|
||||
{
|
||||
name: name,
|
||||
alternate_names: alternate_names.pluck(:name),
|
||||
scientific_names: scientific_names.pluck(:name),
|
||||
plantings_count: plantings_count, # boost the crops that are planted the most
|
||||
planters_ids: plantings.pluck(:owner_id) # boost this product for these members
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def count_uses_of_property(col_name)
|
||||
|
||||
@@ -8,6 +8,8 @@ class Garden < ApplicationRecord
|
||||
has_many :plantings, dependent: :destroy
|
||||
has_many :crops, through: :plantings
|
||||
|
||||
belongs_to :garden_type, optional: true
|
||||
|
||||
# set up geocoding
|
||||
geocoded_by :location
|
||||
after_validation :geocode
|
||||
@@ -17,6 +19,7 @@ class Garden < ApplicationRecord
|
||||
default_scope { joins(:owner) } # Ensures owner exists
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :inactive, -> { where(active: false) }
|
||||
scope :order_by_name, -> { order("lower(name) asc") }
|
||||
|
||||
validates :location, length: { maximum: 255 }
|
||||
validates :slug, uniqueness: true
|
||||
@@ -43,7 +46,6 @@ class Garden < ApplicationRecord
|
||||
}.freeze
|
||||
validates :area_unit, inclusion: { in: AREA_UNITS_VALUES.values,
|
||||
message: "%<value>s is not a valid area unit" },
|
||||
allow_nil: true,
|
||||
allow_blank: true
|
||||
|
||||
after_validation :cleanup_area
|
||||
|
||||
19
app/models/garden_type.rb
Normal file
19
app/models/garden_type.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
class GardenType < ApplicationRecord
|
||||
extend FriendlyId
|
||||
friendly_id :name, use: %i(slugged finders)
|
||||
|
||||
has_many :gardens, dependent: :nullify
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
validates :slug, presence: true, uniqueness: true
|
||||
|
||||
def garden_type_slug
|
||||
name.gsub!(/[^A-Za-z]/, '')
|
||||
end
|
||||
|
||||
def subtitler(garden_type)
|
||||
num = garden_type.gardens.uniq.count
|
||||
s = num > 1 || num.zero? ? "s are" : " is"
|
||||
"#{num} garden#{s} using this garden type"
|
||||
end
|
||||
end
|
||||
@@ -57,11 +57,11 @@ class Harvest < ApplicationRecord
|
||||
validates :quantity, allow_nil: true, numericality: {
|
||||
only_integer: false, greater_than_or_equal_to: 0
|
||||
}
|
||||
validates :unit, allow_nil: true, allow_blank: true, inclusion: {
|
||||
validates :unit, allow_blank: true, inclusion: {
|
||||
in: UNITS_VALUES.values, message: "%<value>s is not a valid unit"
|
||||
}
|
||||
validates :weight_quantity, allow_nil: true, numericality: { only_integer: false }
|
||||
validates :weight_unit, allow_nil: true, allow_blank: true, inclusion: {
|
||||
validates :weight_unit, allow_blank: true, inclusion: {
|
||||
in: WEIGHT_UNITS_VALUES.values, message: "%<value>s is not a valid unit"
|
||||
}
|
||||
validate :crop_must_match_planting
|
||||
|
||||
@@ -23,7 +23,7 @@ class Planting < ApplicationRecord
|
||||
# Ancestry of food
|
||||
belongs_to :parent_seed, class_name: 'Seed', # parent
|
||||
foreign_key: 'parent_seed_id',
|
||||
required: false,
|
||||
optional: true,
|
||||
inverse_of: :child_plantings
|
||||
has_many :child_seeds, class_name: 'Seed', # children
|
||||
foreign_key: 'parent_planting_id',
|
||||
@@ -56,10 +56,10 @@ class Planting < ApplicationRecord
|
||||
validates :quantity, allow_nil: true, numericality: {
|
||||
only_integer: true, greater_than_or_equal_to: 0
|
||||
}
|
||||
validates :sunniness, allow_nil: true, allow_blank: true, inclusion: {
|
||||
validates :sunniness, allow_blank: true, inclusion: {
|
||||
in: SUNNINESS_VALUES, message: "%<value>s is not a valid sunniness value"
|
||||
}
|
||||
validates :planted_from, allow_nil: true, allow_blank: true, inclusion: {
|
||||
validates :planted_from, allow_blank: true, inclusion: {
|
||||
in: PLANTED_FROM_VALUES, message: "%<value>s is not a valid planting method"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
class ScientificName < ApplicationRecord
|
||||
after_commit { |sn| sn.crop.__elasticsearch__.index_document if sn.crop && ENV['GROWSTUFF_ELASTICSEARCH'] == "true" }
|
||||
belongs_to :crop
|
||||
belongs_to :creator, class_name: 'Member', inverse_of: :created_scientific_names
|
||||
validates :name, presence: true
|
||||
validates :crop, presence: true
|
||||
after_commit :reindex if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
delegate :reindex, to: :crop
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ class Seed < ApplicationRecord
|
||||
# Relationships
|
||||
belongs_to :crop
|
||||
belongs_to :parent_planting, class_name: 'Planting', foreign_key: 'parent_planting_id',
|
||||
required: false, inverse_of: :child_seeds # parent
|
||||
optional: true, inverse_of: :child_seeds # parent
|
||||
has_many :child_plantings, class_name: 'Planting',
|
||||
foreign_key: 'parent_seed_id', dependent: :nullify,
|
||||
inverse_of: :parent_seed # children
|
||||
@@ -29,17 +29,17 @@ class Seed < ApplicationRecord
|
||||
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
validates :days_until_maturity_max, allow_nil: true,
|
||||
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||
validates :tradable_to, allow_nil: false, allow_blank: false,
|
||||
inclusion: { in: TRADABLE_TO_VALUES, message: "You may only trade seed nowhere, "\
|
||||
validates :tradable_to, allow_blank: false,
|
||||
inclusion: { in: TRADABLE_TO_VALUES, message: "You may only trade seed nowhere, "\
|
||||
"locally, nationally, or internationally" }
|
||||
validates :organic, allow_nil: false, allow_blank: false,
|
||||
inclusion: { in: ORGANIC_VALUES, message: "You must say whether the seeds "\
|
||||
validates :organic, allow_blank: false,
|
||||
inclusion: { in: ORGANIC_VALUES, message: "You must say whether the seeds "\
|
||||
"are organic or not, or that you don't know" }
|
||||
validates :gmo, allow_nil: false, allow_blank: false,
|
||||
inclusion: { in: GMO_VALUES, message: "You must say whether the seeds are "\
|
||||
validates :gmo, allow_blank: false,
|
||||
inclusion: { in: GMO_VALUES, message: "You must say whether the seeds are "\
|
||||
"genetically modified or not, or that you don't know" }
|
||||
validates :heirloom, allow_nil: false, allow_blank: false,
|
||||
inclusion: { in: HEIRLOOM_VALUES, message: "You must say whether the seeds"\
|
||||
validates :heirloom, allow_blank: false,
|
||||
inclusion: { in: HEIRLOOM_VALUES, message: "You must say whether the seeds"\
|
||||
"are heirloom, hybrid, or unknown" }
|
||||
|
||||
#
|
||||
|
||||
@@ -1,40 +1,49 @@
|
||||
class CropSearchService
|
||||
# Crop.search(string)
|
||||
def self.search(query)
|
||||
if ENV['GROWSTUFF_ELASTICSEARCH'] == "true"
|
||||
search_str = query.nil? ? "" : query.downcase
|
||||
response = Crop.__elasticsearch__.search(
|
||||
query: {
|
||||
bool: {
|
||||
filter: {
|
||||
term: { "approval_status" => "approved" }
|
||||
},
|
||||
must: {
|
||||
query_string: {
|
||||
query: "*#{search_str}*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
response.records.to_a
|
||||
def self.search(query, page: 1, per_page: 12, current_member: nil)
|
||||
if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
elasticsearch(query, page: page, per_page: per_page, current_member: current_member)
|
||||
else
|
||||
# if we don't have elasticsearch, just do a basic SQL query.
|
||||
# also, make sure it's an actual array not an activerecord
|
||||
# collection, so it matches what we get from elasticsearch and we can
|
||||
# manipulate it in the same ways (eg. deleting elements without deleting
|
||||
# the whole record from the db)
|
||||
matches = Crop.approved.where("name ILIKE ?", "%#{query}%").to_a
|
||||
|
||||
# we want to make sure that exact matches come first, even if not
|
||||
# using elasticsearch (eg. in development)
|
||||
exact_match = Crop.approved.find_by(name: query)
|
||||
if exact_match
|
||||
matches.delete(exact_match)
|
||||
matches.unshift(exact_match)
|
||||
end
|
||||
|
||||
matches
|
||||
dbsearch(query, page: page, per_page: per_page)
|
||||
end
|
||||
end
|
||||
|
||||
def self.elasticsearch(query, page: 1, per_page: 12, current_member: nil)
|
||||
search_params = {
|
||||
page: page,
|
||||
per_page: per_page,
|
||||
fields: %i(name^5 alternate_names scientific_names),
|
||||
match: :word_start,
|
||||
boost_by: [:plantings_count],
|
||||
includes: %i(scientific_names alternate_names),
|
||||
misspellings: { edit_distance: 2 }
|
||||
}
|
||||
# prioritise crops the member has planted
|
||||
search_params[:boost_where] = { planters_ids: current_member.id } if current_member
|
||||
|
||||
Crop.search(query, search_params)
|
||||
end
|
||||
|
||||
def self.dbsearch(query, page: 1, per_page: 12)
|
||||
# if we don't have elasticsearch, just do a basic SQL query.
|
||||
# also, make sure it's an actual array not an activerecord
|
||||
# collection, so it matches what we get from elasticsearch and we can
|
||||
# manipulate it in the same ways (eg. deleting elements without deleting
|
||||
# the whole record from the db)
|
||||
matcher = "%#{query}%"
|
||||
matches = Crop.approved
|
||||
.left_outer_joins(:alternate_names, :scientific_names)
|
||||
.where("crops.name ILIKE ? OR alternate_names.name ILIKE ? OR scientific_names.name ILIKE ?",
|
||||
matcher, matcher, matcher)
|
||||
|
||||
matches = matches.to_a
|
||||
# we want to make sure that exact matches come first, even if not
|
||||
# using elasticsearch (eg. in development)
|
||||
exact_match = Crop.approved.find_by(name: query)
|
||||
if exact_match
|
||||
matches.delete(exact_match)
|
||||
matches.unshift(exact_match)
|
||||
end
|
||||
matches.paginate(page: page, per_page: per_page)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
.row
|
||||
.col-md-4
|
||||
%h2 Site admin
|
||||
|
||||
%ul#site_admin
|
||||
%li= link_to "Roles", roles_path
|
||||
%li= link_to "Forums", forums_path
|
||||
%li= link_to "CMS", comfy_admin_cms_path
|
||||
%li= link_to t('.garden_types'), garden_types_path
|
||||
|
||||
.col-md-4
|
||||
%h2 Crop data admin
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
- unless crop.scientific_names.empty?
|
||||
.scientificname
|
||||
= crop.scientific_names.first.name
|
||||
.plantingcount
|
||||
Planted
|
||||
= pluralize(crop.plantings.size, "time")
|
||||
- if crop.annual? && crop.median_lifespan.present?
|
||||
.planting-lifespan
|
||||
lifespan
|
||||
%strong= crop.median_lifespan
|
||||
days
|
||||
|
||||
@@ -1,20 +1,5 @@
|
||||
.varieties
|
||||
- if crop.parent
|
||||
%p
|
||||
= crop.name
|
||||
is a variety of
|
||||
= succeed "." do
|
||||
= link_to crop.parent, crop.parent
|
||||
|
||||
- unless crop.varieties.empty?
|
||||
%p
|
||||
Varieties of #{crop.name}:
|
||||
|
||||
- max = 5
|
||||
= render partial: 'hierarchy', locals: { display_crops: [crop], max: max }
|
||||
- if max != 0 && @count > max
|
||||
= button_tag "Show all #{@count - 1} varieties", class: 'btn btn-link toggle crop-hierarchy'
|
||||
= button_tag "Show less varieties", class: 'btn btn-link toggle crop-hierarchy hide'
|
||||
|
||||
- if !crop.parent && crop.varieties.empty?
|
||||
%p None known.
|
||||
- if crop.varieties.size.positive?
|
||||
%h3 Varieties
|
||||
.row
|
||||
- crop.varieties.order(:name).each do |v|
|
||||
.col-md-2.six-across= render 'crops/thumbnail', crop: v
|
||||
@@ -1,7 +1,7 @@
|
||||
- if @term
|
||||
- content_for :title, "Crops matching \"#{@term}\""
|
||||
- if @matches
|
||||
- content_for :subtitle, "#{@matches.size} total"
|
||||
- if @crops
|
||||
- content_for :subtitle, "#{@crops.size} total"
|
||||
- else
|
||||
- content_for :title, "Crop search"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
value: @term
|
||||
= submit_tag "Search", class: 'btn btn-primary'
|
||||
|
||||
- if @matches.empty?
|
||||
- if @crops.empty?
|
||||
%h2 No results found
|
||||
%p
|
||||
Sorry, we couldn't find any crops that matched your search for "#{@term}".
|
||||
@@ -26,13 +26,12 @@
|
||||
|
||||
- else
|
||||
.pagination
|
||||
= will_paginate @paginated_matches
|
||||
= will_paginate @crops
|
||||
|
||||
#paginated_matches
|
||||
.row
|
||||
- @paginated_matches.each do |c|
|
||||
.col-md-2.six-across
|
||||
= render partial: "thumbnail", locals: { crop: c }
|
||||
- @crops.each do |c|
|
||||
.col-md-2.six-across= render partial: "thumbnail", locals: { crop: c }
|
||||
|
||||
.pagination
|
||||
= will_paginate @paginated_matches
|
||||
= will_paginate @crops
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
%h2 Photos
|
||||
%p= render 'crops/photos', photos: @photos
|
||||
%p= link_to 'more photos', crop_photos_path(@crop)
|
||||
|
||||
|
||||
.row
|
||||
.col-md-3
|
||||
%h3 Sunniness
|
||||
@@ -48,6 +48,7 @@
|
||||
%h3 Harvested for
|
||||
= pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom"
|
||||
|
||||
.varieties= render 'varieties', crop: @crop
|
||||
|
||||
%h3 Crop Map
|
||||
%p
|
||||
@@ -90,8 +91,13 @@
|
||||
= render 'scientific_names', crop: @crop
|
||||
= render 'alternate_names', crop: @crop
|
||||
|
||||
%h4 #{@crop.name.capitalize} varieties
|
||||
= render 'varieties', crop: @crop
|
||||
- if @crop.parent
|
||||
.parent-crop
|
||||
= @crop.name
|
||||
is a variety of
|
||||
= succeed "." do
|
||||
= link_to @crop.parent, @crop.parent
|
||||
= render 'crops/thumbnail', crop: @crop.parent
|
||||
|
||||
= render 'plantings', crop: @crop
|
||||
= render 'harvests', crop: @crop
|
||||
|
||||
4
app/views/garden_types/_actions.html.haml
Normal file
4
app/views/garden_types/_actions.html.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
.btn-group.garden_type-actions
|
||||
= render 'shared/buttons/edit', path: edit_garden_type_path(garden_type)
|
||||
.pull-right
|
||||
= render 'shared/buttons/delete', path: garden_type_path(garden_type)
|
||||
20
app/views/garden_types/_form.html.haml
Normal file
20
app/views/garden_types/_form.html.haml
Normal file
@@ -0,0 +1,20 @@
|
||||
= form_for @garden_type, html: { class: 'form-horizontal', role: "form" } do |f|
|
||||
- if @garden_type.errors.any?
|
||||
#error_explanation
|
||||
%h2= "#{pluralize(@garden_type.errors.count, "error")} prohibited this garden_type from being saved:"
|
||||
%ul
|
||||
- @garden_type.errors.full_messages.each do |message|
|
||||
%li= message
|
||||
|
||||
%h2 Basic information
|
||||
|
||||
.form-group
|
||||
= f.label :name, class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_field :name, class: 'form-control'
|
||||
%span.help-block
|
||||
The name for the garden_type, i.e. "organic", in English (required).
|
||||
|
||||
.form-group
|
||||
.form-actions.col-md-offset-2.col-md-8
|
||||
= f.submit 'Save', class: 'btn btn-primary'
|
||||
7
app/views/garden_types/_thumbnail.html.haml
Normal file
7
app/views/garden_types/_thumbnail.html.haml
Normal file
@@ -0,0 +1,7 @@
|
||||
- cache cache_key_for(GardenType, garden_type.id) do
|
||||
.thumbnail
|
||||
.garden_type-thumbnail
|
||||
- if garden_type
|
||||
.garden_typeinfo
|
||||
.garden_typename
|
||||
= link_to garden_type.name, garden_type
|
||||
4
app/views/garden_types/edit.html.haml
Normal file
4
app/views/garden_types/edit.html.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
- content_for :title, "Edit GardenType"
|
||||
|
||||
- if can? :update, @garden_type
|
||||
= render 'form'
|
||||
17
app/views/garden_types/index.html.haml
Normal file
17
app/views/garden_types/index.html.haml
Normal file
@@ -0,0 +1,17 @@
|
||||
- content_for :title, 'GardenTypes'
|
||||
|
||||
%p
|
||||
#{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where.
|
||||
View any garden_type page to see which of our members have used it.
|
||||
|
||||
.row
|
||||
- @garden_types.each do |garden_type|
|
||||
.col-md-2.six-across
|
||||
= render partial: "thumbnail", locals: { garden_type: garden_type }
|
||||
|
||||
- if can? :create, GardenType
|
||||
%div
|
||||
= link_to 'New GardenType', new_garden_type_path, class: 'btn btn-primary'
|
||||
|
||||
.pagination
|
||||
= will_paginate @garden_types
|
||||
4
app/views/garden_types/new.html.haml
Normal file
4
app/views/garden_types/new.html.haml
Normal file
@@ -0,0 +1,4 @@
|
||||
- content_for :title, "New GardenType"
|
||||
|
||||
- if can? :create, @garden_type
|
||||
= render 'form'
|
||||
12
app/views/garden_types/show.html.haml
Normal file
12
app/views/garden_types/show.html.haml
Normal file
@@ -0,0 +1,12 @@
|
||||
- content_for :title, @garden_type.name.capitalize
|
||||
- content_for :subtitle, @garden_type.subtitler(@garden_type)
|
||||
|
||||
- if can?(:create, @garden_type) && can?(:edit, @garden_type) && can?(:destroy, @garden_type)
|
||||
- content_for :buttonbar do
|
||||
= render 'garden_types/actions', garden_type: @garden_type
|
||||
|
||||
- if @garden_type.gardens.uniq.empty?
|
||||
%p There are no gardens to display.
|
||||
- else
|
||||
- @garden_type.gardens.uniq.each do |garden|
|
||||
= render 'gardens/overview', garden: garden
|
||||
@@ -43,6 +43,15 @@
|
||||
.col-md-2
|
||||
= f.select(:area_unit, Garden::AREA_UNITS_VALUES, { include_blank: false }, class: 'form-control')
|
||||
|
||||
.form-group
|
||||
= f.label :garden_type, class: 'control-label col-md-2'
|
||||
.col-md-2
|
||||
= collection_select(:garden, :garden_type_id,
|
||||
GardenType.all.order(:name),
|
||||
:id, :name,
|
||||
selected: @garden.garden_type_id,
|
||||
class: 'form-control')
|
||||
|
||||
.form-group
|
||||
= f.label :active, 'Active? ', class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
= f.label :garden_id, 'Where did you plant it?', class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= collection_select(:planting, :garden_id,
|
||||
current_member.gardens.active.order("lower(gardens.name)"),
|
||||
current_member.gardens.active.order_by_name,
|
||||
:id, :name,
|
||||
selected: @planting.garden_id || @garden.id,
|
||||
class: 'form-control')
|
||||
|
||||
@@ -89,7 +89,7 @@ Rails.application.configure do
|
||||
config.active_record.dump_schema_after_migration = false
|
||||
|
||||
# Growstuff configuration
|
||||
config.action_mailer.default_url_options = { host: ENV['MAIL_SENDER_HOST'] }
|
||||
config.action_mailer.default_url_options = { host: ENV['HOST'] }
|
||||
|
||||
config.action_mailer.smtp_settings = {
|
||||
user_name: ENV['SENDGRID_USERNAME'],
|
||||
|
||||
@@ -202,6 +202,8 @@ en:
|
||||
browse_members: Browse Members
|
||||
community: Community
|
||||
community_map: Community Map
|
||||
garden_type: Garden Type
|
||||
garden_types: Garden Types
|
||||
crop_wrangling: Crop Wrangling
|
||||
crops: Crops
|
||||
current_memberlogin_name: "%{current_memberlogin_name}"
|
||||
@@ -309,6 +311,7 @@ en:
|
||||
planting: Please sign in or sign up to plant something.
|
||||
post: Please sign in or sign up to post.
|
||||
seed: Please sign in or sign up to add seeds.
|
||||
garden_type: Not authorized. Only admins can create garden types.
|
||||
manage:
|
||||
all: Not authorized to %{action} %{subject}.
|
||||
read:
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
Rails.application.routes.draw do
|
||||
get '/robots.txt' => 'robots#robots'
|
||||
|
||||
resources :garden_types
|
||||
resources :plant_parts
|
||||
|
||||
devise_for :members, controllers: {
|
||||
registrations: "registrations",
|
||||
passwords: "passwords",
|
||||
|
||||
17
db/migrate/20190326063855_create_garden_types.rb
Normal file
17
db/migrate/20190326063855_create_garden_types.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class CreateGardenTypes < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :garden_types do |t|
|
||||
t.text :name, null: false, unique: true
|
||||
t.text :slug, null: false, unique: true
|
||||
t.timestamps null: false
|
||||
end
|
||||
add_column :gardens, :garden_type_id, :integer
|
||||
add_index :gardens, :garden_type_id
|
||||
['organic', 'conventional', 'container', 'vertical', 'greenhouse', 'rooftop', 'no-dig', 'raised bed',
|
||||
'wicking bed', 'permaculture', 'hydroponic', 'aquaponic', 'orchard', 'food forest',
|
||||
'biodynamic'].each do |name|
|
||||
say "Creating #{name}"
|
||||
GardenType.create! name: name
|
||||
end
|
||||
end
|
||||
end
|
||||
11
db/schema.rb
11
db/schema.rb
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2019_03_17_023129) do
|
||||
ActiveRecord::Schema.define(version: 2019_03_26_063855) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -200,6 +200,13 @@ ActiveRecord::Schema.define(version: 2019_03_17_023129) do
|
||||
t.index ["slug"], name: "index_forums_on_slug", unique: true
|
||||
end
|
||||
|
||||
create_table "garden_types", force: :cascade do |t|
|
||||
t.text "name", null: false
|
||||
t.text "slug", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "gardens", id: :serial, force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.integer "owner_id"
|
||||
@@ -213,6 +220,8 @@ ActiveRecord::Schema.define(version: 2019_03_17_023129) do
|
||||
t.float "longitude"
|
||||
t.decimal "area"
|
||||
t.string "area_unit"
|
||||
t.integer "garden_type_id"
|
||||
t.index ["garden_type_id"], name: "index_gardens_on_garden_type_id"
|
||||
t.index ["owner_id"], name: "index_gardens_on_owner_id"
|
||||
t.index ["slug"], name: "index_gardens_on_slug", unique: true
|
||||
end
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
namespace :search do
|
||||
desc "Create elastic search index"
|
||||
task create: :environment do
|
||||
puts Crop.__elasticsearch__.create_index! force: true
|
||||
end
|
||||
|
||||
desc 'Refresh elastic search index'
|
||||
task refresh: :environment do
|
||||
puts Crop.__elasticsearch__.refresh_index!
|
||||
desc 'reindex'
|
||||
task reindex: :environment do
|
||||
puts Crop.reindex
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,10 +40,21 @@ describe CropsController do
|
||||
|
||||
describe "GET crop search" do
|
||||
describe 'fetches the crop search page' do
|
||||
before { get :search }
|
||||
let!(:tomato) { FactoryBot.create :tomato }
|
||||
let!(:maize) { FactoryBot.create :maize }
|
||||
before { Crop.reindex if ENV["GROWSTUFF_ELASTICSEARCH"] == "true" }
|
||||
describe 'search form page' do
|
||||
before { get :search }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
it { is_expected.to render_template("crops/search") }
|
||||
it { is_expected.to be_success }
|
||||
it { is_expected.to render_template("crops/search") }
|
||||
end
|
||||
|
||||
describe 'perform a search' do
|
||||
before { get :search, params: { term: 'tom' } }
|
||||
it { expect(assigns(:term)).to eq 'tom' }
|
||||
it { expect(assigns(:crops).map(&:name)).to eq ['tomato'] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
90
spec/controllers/garden_types_controller_spec.rb
Normal file
90
spec/controllers/garden_types_controller_spec.rb
Normal file
@@ -0,0 +1,90 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe GardenTypesController, type: :controller do
|
||||
include Devise::Test::ControllerHelpers
|
||||
let(:valid_params) { { name: 'My second GardenType' } }
|
||||
let(:garden_type) { FactoryBot.create :garden_type }
|
||||
|
||||
let(:member) { FactoryBot.create(:member) }
|
||||
let(:admin_member) { FactoryBot.create(:admin) }
|
||||
|
||||
context "when not signed in" do
|
||||
describe 'GET new' do
|
||||
before { get :new, params: { id: garden_type.to_param } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
|
||||
describe 'PUT create' do
|
||||
before { put :create, params: { garden_type: valid_params } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
|
||||
describe 'changing existing records' do
|
||||
before do
|
||||
allow(GardenType).to receive(:find).and_return(:garden_type)
|
||||
expect(garden_type).not_to receive(:save)
|
||||
expect(garden_type).not_to receive(:save!)
|
||||
expect(garden_type).not_to receive(:update)
|
||||
expect(garden_type).not_to receive(:update!)
|
||||
expect(garden_type).not_to receive(:destroy)
|
||||
end
|
||||
|
||||
describe 'GET edit' do
|
||||
before { get :edit, params: { id: garden_type.to_param } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
|
||||
describe 'POST update' do
|
||||
before { post :update, params: { id: garden_type.to_param, garden_type: valid_params } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
|
||||
describe 'DELETE' do
|
||||
before { delete :destroy, params: { id: garden_type.to_param, params: { garden_type: valid_params } } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when signed in as a member" do
|
||||
before { sign_in member }
|
||||
|
||||
let!(:member) { FactoryBot.create(:member) }
|
||||
|
||||
describe "for any garden_type" do
|
||||
let(:any_garden_type) { double('garden_type') }
|
||||
|
||||
before do
|
||||
expect(GardenType).to receive(:find).and_return(:any_garden_type)
|
||||
expect(any_garden_type).not_to receive(:save)
|
||||
expect(any_garden_type).not_to receive(:save!)
|
||||
expect(any_garden_type).not_to receive(:update)
|
||||
expect(any_garden_type).not_to receive(:update!)
|
||||
expect(any_garden_type).not_to receive(:destroy)
|
||||
end
|
||||
|
||||
describe 'GET edit' do
|
||||
before { get :edit, params: { id: any_garden_type.to_param } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
|
||||
describe 'POST update' do
|
||||
before { post :update, params: { id: any_garden_type.to_param, garden_type: valid_params } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
|
||||
describe 'DELETE' do
|
||||
before { delete :destroy, params: { id: any_garden_type.to_param, params: { garden_type: valid_params } } }
|
||||
|
||||
it { expect(response).to redirect_to(root_path) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
5
spec/factories/garden_types.rb
Normal file
5
spec/factories/garden_types.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
FactoryBot.define do
|
||||
factory :garden_type do
|
||||
name { "homemade swamp" }
|
||||
end
|
||||
end
|
||||
@@ -4,7 +4,7 @@ FactoryBot.define do
|
||||
factory :photo do
|
||||
owner
|
||||
flickr_photo_id { 1 }
|
||||
title { Faker::HarryPotter.quote }
|
||||
title { Faker::Movies::HarryPotter.quote }
|
||||
license_name { "CC-BY" }
|
||||
license_url { "http://example.com/license.html" }
|
||||
thumbnail_url { "http://example.com/#{Faker::File.file_name}.jpg" }
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "forums", js: true do
|
||||
describe "forums", js: true do
|
||||
context "as an admin user" do
|
||||
let(:member) { create :admin_member }
|
||||
let(:forum) { create :forum }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
end
|
||||
|
||||
scenario "navigating to forum admin without js", js: false do
|
||||
it "navigating to forum admin without js", js: false do
|
||||
visit root_path
|
||||
click_link "Admin"
|
||||
expect(current_path).to eq admin_path
|
||||
@@ -20,7 +20,7 @@ feature "forums", js: true do
|
||||
expect(page).to have_content "New forum"
|
||||
end
|
||||
|
||||
scenario "navigating to forum admin with js" do
|
||||
it "navigating to forum admin with js" do
|
||||
visit root_path
|
||||
click_link member.login_name
|
||||
click_link "Admin"
|
||||
@@ -32,7 +32,7 @@ feature "forums", js: true do
|
||||
expect(page).to have_content "New forum"
|
||||
end
|
||||
|
||||
scenario "adding a forum" do
|
||||
it "adding a forum" do
|
||||
visit forums_path
|
||||
click_link "New forum"
|
||||
expect(current_path).to eq new_forum_path
|
||||
@@ -43,7 +43,7 @@ feature "forums", js: true do
|
||||
expect(page).to have_content 'Forum was successfully created'
|
||||
end
|
||||
|
||||
scenario 'editing forum' do
|
||||
it 'editing forum' do
|
||||
visit forum_path forum
|
||||
click_link 'Edit'
|
||||
fill_in 'Name', with: 'Something else'
|
||||
@@ -54,7 +54,7 @@ feature "forums", js: true do
|
||||
expect(page).to have_content 'Something else'
|
||||
end
|
||||
|
||||
scenario 'deleting forum' do
|
||||
it 'deleting forum' do
|
||||
visit forum_path forum
|
||||
click_link 'Delete'
|
||||
expect(current_path).to eq forums_path
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "cms admin" do
|
||||
describe "cms admin" do
|
||||
let(:member) { create :member }
|
||||
let(:admin_member) { create :admin_member }
|
||||
|
||||
scenario "can't view CMS admin if not signed in" do
|
||||
it "can't view CMS admin if not signed in" do
|
||||
visit comfy_admin_cms_path
|
||||
expect(current_path).to eq root_path
|
||||
expect(page).to have_content "Please sign in as an admin user"
|
||||
end
|
||||
|
||||
scenario "can't view CMS admin if not an admin member" do
|
||||
it "can't view CMS admin if not an admin member" do
|
||||
# sign in as an ordinary member
|
||||
login_as member
|
||||
visit comfy_admin_cms_path
|
||||
@@ -18,7 +18,7 @@ feature "cms admin" do
|
||||
expect(page).to have_content "Please sign in as an admin user"
|
||||
end
|
||||
|
||||
scenario "admin members can view CMS admin area" do
|
||||
it "admin members can view CMS admin area" do
|
||||
login_as admin_member
|
||||
visit comfy_admin_cms_path
|
||||
expect(current_path).to match(/#{comfy_admin_cms_path}/) # match any CMS admin page
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Commenting on a post' do
|
||||
describe 'Commenting on a post' do
|
||||
let(:member) { create :member }
|
||||
let(:post) { create :post, author: member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_comment_path post_id: post.id
|
||||
end
|
||||
|
||||
scenario "creating a comment" do
|
||||
it "creating a comment" do
|
||||
fill_in "comment_body", with: "This is a sample test for comment"
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content "comment was successfully created."
|
||||
@@ -19,11 +19,11 @@ feature 'Commenting on a post' do
|
||||
context "editing a comment" do
|
||||
let(:existing_comment) { create :comment, post: post, author: member }
|
||||
|
||||
background do
|
||||
before do
|
||||
visit edit_comment_path existing_comment
|
||||
end
|
||||
|
||||
scenario "saving edit" do
|
||||
it "saving edit" do
|
||||
fill_in "comment_body", with: "Testing edit for comment"
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content "comment was successfully updated."
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Alternate names", js: true do
|
||||
describe "Alternate names", js: true do
|
||||
let!(:alternate_eggplant) { create :alternate_eggplant }
|
||||
let(:crop) { alternate_eggplant.crop }
|
||||
|
||||
scenario "Display alternate names on crop page" do
|
||||
it "Display alternate names on crop page" do
|
||||
visit crop_path(alternate_eggplant.crop)
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_content alternate_eggplant.name
|
||||
end
|
||||
|
||||
scenario "Index page for alternate names" do
|
||||
it "Index page for alternate names" do
|
||||
visit alternate_names_path
|
||||
expect(page).to have_content alternate_eggplant.name
|
||||
end
|
||||
@@ -19,11 +19,11 @@ feature "Alternate names", js: true do
|
||||
let!(:crop_wranglers) { create_list :crop_wrangling_member, 3 }
|
||||
let(:member) { crop_wranglers.first }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
end
|
||||
|
||||
scenario "Crop wranglers can edit alternate names" do
|
||||
it "Crop wranglers can edit alternate names" do
|
||||
visit crop_path(crop)
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_content "CROP WRANGLER"
|
||||
@@ -39,7 +39,7 @@ feature "Alternate names", js: true do
|
||||
expect(page).to have_content 'Alternate name was successfully updated'
|
||||
end
|
||||
|
||||
scenario "Crop wranglers can delete alternate names" do
|
||||
it "Crop wranglers can delete alternate names" do
|
||||
visit crop_path(alternate_eggplant.crop)
|
||||
expect(page).to have_link "Delete",
|
||||
href: alternate_name_path(alternate_eggplant)
|
||||
@@ -49,7 +49,7 @@ feature "Alternate names", js: true do
|
||||
expect(page).to have_content 'Alternate name was successfully deleted'
|
||||
end
|
||||
|
||||
scenario "Crop wranglers can add alternate names" do
|
||||
it "Crop wranglers can add alternate names" do
|
||||
visit crop_path(crop)
|
||||
expect(page).to have_link "Add",
|
||||
href: new_alternate_name_path(crop_id: crop.id)
|
||||
@@ -63,7 +63,7 @@ feature "Alternate names", js: true do
|
||||
expect(page).to have_content 'Alternate name was successfully created'
|
||||
end
|
||||
|
||||
scenario "The show-alternate-name page works" do
|
||||
it "The show-alternate-name page works" do
|
||||
visit alternate_name_path(alternate_eggplant)
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_content alternate_eggplant.crop.name
|
||||
@@ -73,7 +73,7 @@ feature "Alternate names", js: true do
|
||||
let(:rejected_crop) { create :rejected_crop }
|
||||
let(:pending_alt_name) { create :alternate_name, crop: rejected_crop }
|
||||
|
||||
scenario "Displays crop rejection message" do
|
||||
it "Displays crop rejection message" do
|
||||
visit alternate_name_path(pending_alt_name)
|
||||
expect(page).to have_content "This crop was rejected for the following reason: Totally fake"
|
||||
end
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "browse crops" do
|
||||
describe "browse crops" do
|
||||
let(:tomato) { create :tomato }
|
||||
let(:maize) { create :maize }
|
||||
let(:pending_crop) { create :crop_request }
|
||||
let(:rejected_crop) { create :rejected_crop }
|
||||
|
||||
scenario "has a form for sorting by" do
|
||||
it "has a form for sorting by" do
|
||||
visit crops_path
|
||||
expect(page).to have_css "select#sort"
|
||||
end
|
||||
|
||||
scenario "shows a list of crops" do
|
||||
it "shows a list of crops" do
|
||||
crop1 = tomato
|
||||
visit crops_path
|
||||
expect(page).to have_content crop1.name
|
||||
end
|
||||
|
||||
scenario "pending crops are not listed" do
|
||||
it "pending crops are not listed" do
|
||||
visit crops_path
|
||||
expect(page).not_to have_content pending_crop.name
|
||||
end
|
||||
|
||||
scenario "rejected crops are not listed" do
|
||||
it "rejected crops are not listed" do
|
||||
visit crops_path
|
||||
expect(page).not_to have_content rejected_crop.name
|
||||
end
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Crop - " do
|
||||
describe "Crop - " do
|
||||
let!(:crop_wrangler) { FactoryBot.create :crop_wrangling_member }
|
||||
let!(:member) { FactoryBot.create :member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_crop_path
|
||||
end
|
||||
|
||||
scenario "creating a crop with multiple scientific and alternate name", :js do
|
||||
it "creating a crop with multiple scientific and alternate name", :js do
|
||||
within "form#new_crop" do
|
||||
fill_in "crop_name", with: "Philippine flower"
|
||||
fill_in "en_wikipedia_url", with: "https://en.wikipedia.org/wiki/Jasminum_sambac"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "crop detail page", js: true do
|
||||
describe "crop detail page", js: true do
|
||||
subject do
|
||||
# Update the medians after all the
|
||||
# data has been loaded
|
||||
@@ -14,82 +14,11 @@ feature "crop detail page", js: true do
|
||||
let(:crop) { create :crop }
|
||||
|
||||
context "varieties" do
|
||||
scenario "The crop DOES NOT have varieties" do
|
||||
it "The crop DOES NOT have varieties" do
|
||||
visit crop_path(crop)
|
||||
|
||||
within ".varieties" do
|
||||
expect(page).to have_no_selector('li', text: /tomato/i)
|
||||
expect(page).to have_no_selector('button', text: /Show+/i)
|
||||
end
|
||||
end
|
||||
|
||||
scenario "The crop has one variety" do
|
||||
create :crop, name: 'Roma tomato 1', parent: crop
|
||||
|
||||
subject
|
||||
|
||||
within ".varieties" do
|
||||
# It lists all 2 items (note: including the top level item.)
|
||||
expect(page).to have_selector('li', text: /tomato/i, count: 2)
|
||||
# It DOES NOT have "Show all/less" toggle link
|
||||
expect(page).to have_no_selector('button', text: /Show+/i)
|
||||
end
|
||||
end
|
||||
|
||||
context "many" do
|
||||
let!(:roma1) { create :crop, name: 'Roma tomato 1', parent: crop }
|
||||
let!(:roma2) { create :crop, name: 'Roma tomato 2', parent: crop }
|
||||
let!(:roma3) { create :crop, name: 'Roma tomato 3', parent: crop }
|
||||
let!(:roma4) { create :crop, name: 'Roma tomato 4', parent: crop }
|
||||
|
||||
scenario "The crop has 4 varieties" do
|
||||
subject
|
||||
|
||||
within ".varieties" do
|
||||
# It lists all 5 items (note: including the top level item.)
|
||||
expect(page).to have_selector('li', text: /tomato/i, count: 5)
|
||||
# It DOES NOT have "Show all/less" toggle link
|
||||
expect(page).to have_no_selector('button', text: /Show+/i)
|
||||
end
|
||||
end
|
||||
|
||||
scenario "The crop has 5 varieties, including grandchild", js: true do
|
||||
create :crop, name: 'Roma tomato child 1', parent: roma4
|
||||
|
||||
subject
|
||||
|
||||
within ".varieties" do
|
||||
# It lists the first 5 items (note: including the top level item.)
|
||||
# It HAS have "Show all" toggle link but not "Show less" link
|
||||
expect(page).to have_selector('li', text: /tomato/i, count: 5)
|
||||
expect(page).to have_selector('li', text: 'Roma tomato 4')
|
||||
expect(page).to have_no_selector('li', text: 'Roma tomato child 1')
|
||||
# It shows the total number (5) correctly
|
||||
expect(page).to have_selector('button', text: /Show all 5 +/i)
|
||||
expect(page).to have_no_selector('button', text: /Show less+/i)
|
||||
|
||||
# Clik "Show all" link
|
||||
page.find('button', text: /Show all+/).click
|
||||
|
||||
# It lists all 6 items (note: including the top level item.)
|
||||
# It HAS have "Show less" toggle link but not "Show all" link
|
||||
expect(page).to have_selector('li', text: /tomato/i, count: 6)
|
||||
expect(page).to have_selector('li', text: 'Roma tomato 4')
|
||||
expect(page).to have_selector('li', text: 'Roma tomato child 1')
|
||||
expect(page).to have_no_selector('button', text: /Show all+/i)
|
||||
expect(page).to have_selector('button', text: /Show less+/i)
|
||||
|
||||
# Clik "Show less" link
|
||||
page.find('button', text: /Show less+/).click
|
||||
|
||||
# It lists 5 items (note: including the top level item.)
|
||||
# It HAS have "Show all" toggle link but not "Show less" link
|
||||
expect(page).to have_selector('li', text: /tomato/i, count: 5)
|
||||
expect(page).to have_selector('li', text: 'Roma tomato 4')
|
||||
expect(page).to have_no_selector('li', text: 'Roma tomato child 1')
|
||||
expect(page).to have_selector('button', text: /Show all 5 +/i)
|
||||
expect(page).to have_no_selector('button', text: /Show less+/i)
|
||||
end
|
||||
expect(page).not_to have_text 'tomato'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -97,54 +26,54 @@ feature "crop detail page", js: true do
|
||||
context "signed in member" do
|
||||
let(:member) { create :member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as(member)
|
||||
end
|
||||
|
||||
context "action buttons" do
|
||||
background { subject }
|
||||
before { subject }
|
||||
|
||||
scenario "has a link to plant the crop" do
|
||||
it "has a link to plant the crop" do
|
||||
expect(page).to have_link "Plant #{crop.name}", href: new_planting_path(crop_id: crop.id)
|
||||
end
|
||||
scenario "has a link to harvest the crop" do
|
||||
it "has a link to harvest the crop" do
|
||||
expect(page).to have_link "Harvest #{crop.name}", href: new_harvest_path(crop_id: crop.id)
|
||||
end
|
||||
scenario "has a link to add seeds" do
|
||||
it "has a link to add seeds" do
|
||||
expect(page).to have_link "Add #{crop.name} seeds to stash", href: new_seed_path(crop_id: crop.id)
|
||||
end
|
||||
end
|
||||
|
||||
context "SEO" do
|
||||
background { subject }
|
||||
before { subject }
|
||||
|
||||
scenario "has seed heading with SEO" do
|
||||
it "has seed heading with SEO" do
|
||||
expect(page).to have_content "Find #{crop.name} seeds"
|
||||
end
|
||||
|
||||
scenario "has harvest heading with SEO" do
|
||||
it "has harvest heading with SEO" do
|
||||
expect(page).to have_content "#{crop.name.capitalize} harvests"
|
||||
end
|
||||
|
||||
scenario "has planting heading with SEO" do
|
||||
it "has planting heading with SEO" do
|
||||
expect(page).to have_content "See who's planted #{crop.name.pluralize}"
|
||||
end
|
||||
|
||||
scenario "has planting advice with SEO" do
|
||||
it "has planting advice with SEO" do
|
||||
expect(page).to have_content "How to grow #{crop.name}"
|
||||
end
|
||||
|
||||
scenario "has a link to Wikipedia with SEO" do
|
||||
it "has a link to Wikipedia with SEO" do
|
||||
expect(page).to have_content "Learn more about #{crop.name}"
|
||||
expect(page).to have_link "Wikipedia (English)", href: crop.en_wikipedia_url
|
||||
end
|
||||
|
||||
scenario "has a link to OpenFarm" do
|
||||
it "has a link to OpenFarm" do
|
||||
expect(page).to have_link "OpenFarm - Growing guide",
|
||||
href: "https://openfarm.cc/en/crops/#{CGI.escape crop.name}"
|
||||
end
|
||||
|
||||
scenario "has a link to gardenate" do
|
||||
it "has a link to gardenate" do
|
||||
expect(page).to have_link "Gardenate - Planting reminders",
|
||||
href: "http://www.gardenate.com/plant/#{CGI.escape crop.name}"
|
||||
end
|
||||
@@ -155,18 +84,18 @@ feature "crop detail page", js: true do
|
||||
let(:member) { create :member }
|
||||
let(:seed) { create :seed, crop: crop, quantity: 20, owner: member }
|
||||
|
||||
scenario "User not signed in" do
|
||||
it "User not signed in" do
|
||||
visit crop_path(seed.crop)
|
||||
expect(page).not_to have_content "You have 20 seeds"
|
||||
end
|
||||
|
||||
scenario "User signed in" do
|
||||
it "User signed in" do
|
||||
login_as(member)
|
||||
visit crop_path(seed.crop)
|
||||
expect(page).to have_link "You have 20 seeds of this crop."
|
||||
end
|
||||
|
||||
scenario "click link to your owned seeds" do
|
||||
it "click link to your owned seeds" do
|
||||
login_as(member)
|
||||
visit crop_path(seed.crop)
|
||||
click_link "You have 20 seeds of this crop."
|
||||
@@ -190,7 +119,7 @@ feature "crop detail page", js: true do
|
||||
end
|
||||
|
||||
it "predicts harvest" do
|
||||
is_expected.to have_text("First harvest expected 20 days after planting")
|
||||
expect(subject).to have_text("First harvest expected 20 days after planting")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -213,12 +142,12 @@ feature "crop detail page", js: true do
|
||||
end
|
||||
|
||||
it "predicts lifespan" do
|
||||
is_expected.to have_text "Median lifespan"
|
||||
is_expected.to have_text "99 days"
|
||||
expect(subject).to have_text "Median lifespan"
|
||||
expect(subject).to have_text "99 days"
|
||||
end
|
||||
|
||||
it "describes annual crops" do
|
||||
is_expected.to have_text(
|
||||
expect(subject).to have_text(
|
||||
"#{crop.name} is an annual crop (living and reproducing in a single year or less)"
|
||||
)
|
||||
end
|
||||
@@ -235,7 +164,7 @@ feature "crop detail page", js: true do
|
||||
end
|
||||
|
||||
it "describes perennial crops" do
|
||||
is_expected.to have_text("#{crop.name} is a perennial crop (living more than two years)")
|
||||
expect(subject).to have_text("#{crop.name} is a perennial crop (living more than two years)")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "crop detail page", js: true do
|
||||
describe "crop detail page", js: true do
|
||||
subject { page }
|
||||
|
||||
let!(:member) { FactoryBot.create :member }
|
||||
@@ -50,12 +50,14 @@ feature "crop detail page", js: true do
|
||||
end
|
||||
|
||||
context "when signed in" do
|
||||
background { login_as(FactoryBot.create(:member)) }
|
||||
before { login_as(FactoryBot.create(:member)) }
|
||||
|
||||
include_examples "shows photos"
|
||||
end
|
||||
|
||||
context "when signed in as photos owner" do
|
||||
background { login_as(member) }
|
||||
before { login_as(member) }
|
||||
|
||||
include_examples "shows photos"
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "crop search" do
|
||||
scenario "search results show the search term in title" do
|
||||
describe "crop search" do
|
||||
it "search results show the search term in title" do
|
||||
visit root_path
|
||||
within "form#navbar-search" do
|
||||
fill_in "term", with: "tomato"
|
||||
@@ -10,12 +10,12 @@ feature "crop search" do
|
||||
expect(page).to have_css "h1", text: "Crops matching \"tomato\""
|
||||
end
|
||||
|
||||
scenario "search page with no search term shows suitable title" do
|
||||
it "search page with no search term shows suitable title" do
|
||||
visit search_crops_path
|
||||
expect(page).to have_css "h1", text: "Crop search"
|
||||
end
|
||||
|
||||
scenario "search page has a search form on it" do
|
||||
it "search page has a search form on it" do
|
||||
visit search_crops_path
|
||||
expect(page).to have_css "form#crop-search"
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "crop wranglers", js: true do
|
||||
describe "crop wranglers", js: true do
|
||||
context "signed in wrangler" do
|
||||
let!(:crop_wranglers) { create_list :crop_wrangling_member, 3 }
|
||||
let(:wrangler) { crop_wranglers.first }
|
||||
@@ -8,9 +8,9 @@ feature "crop wranglers", js: true do
|
||||
let!(:requested_crop) { create :crop_request }
|
||||
let!(:rejected_crop) { create :rejected_crop }
|
||||
|
||||
background { login_as wrangler }
|
||||
before { login_as wrangler }
|
||||
|
||||
scenario "sees crop wranglers listed on the crop wrangler page" do
|
||||
it "sees crop wranglers listed on the crop wrangler page" do
|
||||
visit root_path
|
||||
click_link wrangler.login_name
|
||||
click_link 'Crop Wrangling'
|
||||
@@ -23,7 +23,7 @@ feature "crop wranglers", js: true do
|
||||
end
|
||||
end
|
||||
|
||||
scenario "can see list of crops with extra detail of who created a crop" do
|
||||
it "can see list of crops with extra detail of who created a crop" do
|
||||
visit root_path
|
||||
click_link wrangler.login_name
|
||||
click_link 'Crop Wrangling'
|
||||
@@ -40,7 +40,7 @@ feature "crop wranglers", js: true do
|
||||
it { expect(page).to have_link 'Delete' }
|
||||
end
|
||||
|
||||
scenario "can create a new crop" do
|
||||
it "can create a new crop" do
|
||||
visit root_path
|
||||
click_link wrangler.login_name
|
||||
click_link 'Crop Wrangling'
|
||||
@@ -53,13 +53,13 @@ feature "crop wranglers", js: true do
|
||||
expect(page).to have_content 'planticus maximus'
|
||||
end
|
||||
|
||||
scenario "View pending crops" do
|
||||
it "View pending crops" do
|
||||
visit crop_path(requested_crop)
|
||||
expect(page).to have_content "This crop is currently pending approval."
|
||||
expect(page).to have_content "Please approve this even though it's fake."
|
||||
end
|
||||
|
||||
scenario "View rejected crops" do
|
||||
it "View rejected crops" do
|
||||
visit crop_path(rejected_crop)
|
||||
expect(page).to have_content "This crop was rejected for the following reason: Totally fake"
|
||||
end
|
||||
@@ -69,14 +69,14 @@ feature "crop wranglers", js: true do
|
||||
let!(:crop_wranglers) { create_list :crop_wrangling_member, 3 }
|
||||
let(:member) { create :member }
|
||||
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
scenario "can't see wrangling page without js", js: false do
|
||||
it "can't see wrangling page without js", js: false do
|
||||
visit root_path
|
||||
expect(page).not_to have_link "Crop Wrangling"
|
||||
end
|
||||
|
||||
scenario "can't see wrangling page with js" do
|
||||
it "can't see wrangling page with js" do
|
||||
visit root_path
|
||||
click_link member.login_name
|
||||
expect(page).not_to have_link "Crop Wrangling"
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "crop wrangling button" do
|
||||
describe "crop wrangling button" do
|
||||
let(:crop_wrangler) { create :crop_wrangling_member }
|
||||
let(:member) { create :member }
|
||||
|
||||
context "crop wrangling button" do
|
||||
background do
|
||||
before do
|
||||
login_as crop_wrangler
|
||||
visit crops_path
|
||||
end
|
||||
|
||||
scenario "has a link to crop wrangling page" do
|
||||
it "has a link to crop wrangling page" do
|
||||
expect(page).to have_link "Wrangle Crops", href: wrangle_crops_path
|
||||
end
|
||||
end
|
||||
|
||||
context "crop wrangling button" do
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit crops_path
|
||||
end
|
||||
|
||||
scenario "has no link to crop wrangling page" do
|
||||
it "has no link to crop wrangling page" do
|
||||
expect(page).to have_no_link "Wrangle Crops", href: wrangle_crops_path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Delete crop spec" do
|
||||
describe "Delete crop spec" do
|
||||
context "As a crop wrangler" do
|
||||
let(:wrangler) { FactoryBot.create :crop_wrangling_member }
|
||||
let!(:pending_crop) { FactoryBot.create :crop_request }
|
||||
let!(:approved_crop) { FactoryBot.create :crop }
|
||||
|
||||
background { login_as wrangler }
|
||||
before { login_as wrangler }
|
||||
|
||||
scenario "Delete approved crop" do
|
||||
it "Delete approved crop" do
|
||||
visit crop_path(approved_crop)
|
||||
click_link 'Delete'
|
||||
expect(page).to have_content "crop was successfully destroyed"
|
||||
end
|
||||
|
||||
scenario "Delete pending crop" do
|
||||
it "Delete pending crop" do
|
||||
visit crop_path(pending_crop)
|
||||
click_link 'Delete'
|
||||
expect(page).to have_content "crop was successfully destroyed"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "irregular crop inflections" do
|
||||
describe "irregular crop inflections" do
|
||||
# We're just testing a couple of representative crops to
|
||||
# check that inflection works: you don't need to add
|
||||
# every crop here.
|
||||
scenario "crops which are mass nouns" do
|
||||
it "crops which are mass nouns" do
|
||||
expect("kale".pluralize).to eq "kale"
|
||||
expect("broccoli".pluralize).to eq "broccoli"
|
||||
expect("square foot".pluralize).to eq "square feet"
|
||||
@@ -26,29 +26,29 @@ feature "irregular crop inflections" do
|
||||
expect("star anise".pluralize).to eq "star anise"
|
||||
end
|
||||
|
||||
scenario "crops which are particularly irregular" do
|
||||
it "crops which are particularly irregular" do
|
||||
expect("curry leaf".pluralize).to eq "curry leaves"
|
||||
end
|
||||
|
||||
scenario "crops which require -es" do
|
||||
it "crops which require -es" do
|
||||
expect("mango".pluralize).to eq "mangoes"
|
||||
expect("potato".pluralize).to eq "potatoes"
|
||||
end
|
||||
|
||||
scenario "crops where the first crop would normally be pluralized" do
|
||||
it "crops where the first crop would normally be pluralized" do
|
||||
expect("Potato Onion".pluralize).to eq "Potato Onions"
|
||||
expect("pear tomato".pluralize).to eq "pear tomatoes"
|
||||
expect("chilli pepper".pluralize).to eq "chilli peppers"
|
||||
end
|
||||
|
||||
scenario "crops where the proper name succeeds the crop that would normally be pluralized" do
|
||||
it "crops where the proper name succeeds the crop that would normally be pluralized" do
|
||||
expect("potato Taranaki".pluralize).to eq "potato Taranaki"
|
||||
expect("potato Gladstone".pluralize).to eq "potato Gladstone"
|
||||
expect("potato matariki".pluralize).to eq "potato matariki"
|
||||
expect("spinach Santana".pluralize).to eq "spinach Santana"
|
||||
end
|
||||
|
||||
scenario "crops of Māori origin" do
|
||||
it "crops of Māori origin" do
|
||||
expect("kūmara".pluralize).to eq "kūmara"
|
||||
expect("pūhā".pluralize).to eq "pūhā"
|
||||
end
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Requesting a new crop" do
|
||||
describe "Requesting a new crop" do
|
||||
context "As a regular member" do
|
||||
let(:member) { create :member }
|
||||
let!(:wrangler) { create :crop_wrangling_member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
end
|
||||
|
||||
scenario "Submit request" do
|
||||
it "Submit request" do
|
||||
visit new_crop_path
|
||||
fill_in "Name", with: "Couch potato"
|
||||
fill_in "request_notes", with: "Couch potatoes are real for real."
|
||||
@@ -24,9 +24,9 @@ feature "Requesting a new crop" do
|
||||
let!(:crop) { create :crop_request }
|
||||
let!(:already_approved) { create :crop }
|
||||
|
||||
background { login_as wrangler }
|
||||
before { login_as wrangler }
|
||||
|
||||
scenario "Approve a request" do
|
||||
it "Approve a request" do
|
||||
visit edit_crop_path(crop)
|
||||
select "approved", from: "Approval status"
|
||||
click_button "Save"
|
||||
@@ -36,7 +36,7 @@ feature "Requesting a new crop" do
|
||||
expect(page).to have_content "crop was successfully updated."
|
||||
end
|
||||
|
||||
scenario "Rejecting a crop" do
|
||||
it "Rejecting a crop" do
|
||||
visit edit_crop_path(crop)
|
||||
select "rejected", from: "Approval status"
|
||||
select "not edible", from: "Reason for rejection"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Crop - " do
|
||||
describe "Crop - " do
|
||||
let(:member) { create :member }
|
||||
let!(:requested_crop) { create :crop, requester: member, approval_status: 'pending', name: 'puha for dinner' }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit requested_crops_path
|
||||
end
|
||||
|
||||
scenario "creating a crop with multiple scientific and alternate name", :js do
|
||||
it "creating a crop with multiple scientific and alternate name", :js do
|
||||
expect(page).to have_content "puha for dinner"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "browse crops" do
|
||||
describe "browse crops" do
|
||||
let(:tomato) { create :tomato }
|
||||
let(:maize) { create :maize }
|
||||
let(:pending_crop) { create :crop_request }
|
||||
let(:rejected_crop) { create :rejected_crop }
|
||||
|
||||
scenario "Show crop info" do
|
||||
it "Show crop info" do
|
||||
visit crop_path(tomato)
|
||||
expect(page).to have_text 'tomato'
|
||||
end
|
||||
@@ -18,7 +18,7 @@ feature "browse crops" do
|
||||
FactoryBot.create :harvest, crop: tomato, harvested_at: 60.minutes.ago, created_at: 10.minutes.ago
|
||||
end
|
||||
|
||||
scenario "Shows most recently harvested harvest" do
|
||||
it "Shows most recently harvested harvest" do
|
||||
visit crop_path(tomato)
|
||||
expect(page).to have_link(href: harvest_path(most_recent_harvest))
|
||||
end
|
||||
@@ -31,7 +31,7 @@ feature "browse crops" do
|
||||
FactoryBot.create :planting, crop: tomato, planted_at: 60.minutes.ago, created_at: 10.minutes.ago
|
||||
end
|
||||
|
||||
scenario "Shows most recently planted planting" do
|
||||
it "Shows most recently planted planting" do
|
||||
visit crop_path(tomato)
|
||||
expect(page).to have_link(href: planting_path(most_recent_planting))
|
||||
end
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "follows", :js do
|
||||
describe "follows", :js do
|
||||
context "when signed out" do
|
||||
let(:member) { create :member }
|
||||
|
||||
scenario "follow buttons on member profile page" do
|
||||
it "follow buttons on member profile page" do
|
||||
visit member_path(member)
|
||||
expect(page).not_to have_link "Follow"
|
||||
expect(page).not_to have_link "Unfollow"
|
||||
@@ -15,36 +15,36 @@ feature "follows", :js do
|
||||
let(:member) { create :member }
|
||||
let(:other_member) { create :member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as(member)
|
||||
end
|
||||
|
||||
scenario "your profile doesn't have a follow button" do
|
||||
it "your profile doesn't have a follow button" do
|
||||
visit member_path(member)
|
||||
expect(page).not_to have_link "Follow"
|
||||
expect(page).not_to have_link "Unfollow"
|
||||
end
|
||||
|
||||
context "following another member" do
|
||||
background { visit member_path(other_member) }
|
||||
before { visit member_path(other_member) }
|
||||
|
||||
scenario "has a follow button" do
|
||||
it "has a follow button" do
|
||||
expect(page).to have_link "Follow", href: follows_path(followed: other_member.slug)
|
||||
end
|
||||
|
||||
scenario "has correct message and unfollow button" do
|
||||
it "has correct message and unfollow button" do
|
||||
click_link 'Follow'
|
||||
expect(page).to have_content "Followed #{other_member.login_name}"
|
||||
expect(page).to have_link "Unfollow", href: follow_path(member.get_follow(other_member))
|
||||
end
|
||||
|
||||
scenario "has a followed member listed in the following page" do
|
||||
it "has a followed member listed in the following page" do
|
||||
click_link 'Follow'
|
||||
visit member_follows_path(member)
|
||||
expect(page).to have_content other_member.login_name
|
||||
end
|
||||
|
||||
scenario "has correct message and follow button after unfollow" do
|
||||
it "has correct message and follow button after unfollow" do
|
||||
click_link 'Follow'
|
||||
click_link 'Unfollow'
|
||||
expect(page).to have_content "Unfollowed #{other_member.login_name}"
|
||||
@@ -52,19 +52,19 @@ feature "follows", :js do
|
||||
expect(page).to have_link "Follow", href: follows_path(followed: other_member.slug)
|
||||
end
|
||||
|
||||
scenario "has member in following list" do
|
||||
it "has member in following list" do
|
||||
click_link 'Follow'
|
||||
visit member_follows_path(member)
|
||||
expect(page).to have_content other_member.login_name
|
||||
end
|
||||
|
||||
scenario "appears in in followed member's followers list" do
|
||||
it "appears in in followed member's followers list" do
|
||||
click_link 'Follow'
|
||||
visit member_followers_path(other_member)
|
||||
expect(page).to have_content member.login_name
|
||||
end
|
||||
|
||||
scenario "removes members from following and followers lists after unfollow" do
|
||||
it "removes members from following and followers lists after unfollow" do
|
||||
click_link 'Follow'
|
||||
click_link 'Unfollow'
|
||||
visit member_follows_path(member)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "footer", js: true do
|
||||
describe "footer", js: true do
|
||||
before { visit root_path }
|
||||
|
||||
scenario "footer is on home page" do
|
||||
it "footer is on home page" do
|
||||
expect(page).to have_css 'footer'
|
||||
end
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Gardens" do
|
||||
describe "Gardens" do
|
||||
context 'logged in' do
|
||||
subject { page }
|
||||
|
||||
let(:member) { FactoryBot.create :member }
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
let(:garden) { member.gardens.first }
|
||||
let(:other_member_garden) { FactoryBot.create :garden }
|
||||
@@ -15,9 +15,9 @@ feature "Gardens" do
|
||||
shared_examples "has buttons bar at top" do
|
||||
it "has buttons bar at top" do
|
||||
within '.layout-actions' do
|
||||
is_expected.to have_link 'Add a garden'
|
||||
is_expected.to have_link 'My gardens'
|
||||
is_expected.to have_link "Everyone's gardens"
|
||||
expect(subject).to have_link 'Add a garden'
|
||||
expect(subject).to have_link 'My gardens'
|
||||
expect(subject).to have_link "Everyone's gardens"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -27,11 +27,11 @@ feature "Gardens" do
|
||||
|
||||
include_examples "has buttons bar at top"
|
||||
it "has actions on garden" do
|
||||
is_expected.to have_link 'Plant something here'
|
||||
is_expected.to have_link 'Mark as inactive'
|
||||
is_expected.to have_link 'Edit'
|
||||
is_expected.to have_link 'Add photo'
|
||||
is_expected.to have_link 'Delete'
|
||||
expect(subject).to have_link 'Plant something here'
|
||||
expect(subject).to have_link 'Mark as inactive'
|
||||
expect(subject).to have_link 'Edit'
|
||||
expect(subject).to have_link 'Add photo'
|
||||
expect(subject).to have_link 'Delete'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -72,36 +72,4 @@ feature "Gardens" do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# background do
|
||||
# login_as member
|
||||
# visit new_garden_path
|
||||
# end
|
||||
|
||||
# it "has the required fields help text" do
|
||||
# expect(page).to have_content "* denotes a required field"
|
||||
# end
|
||||
|
||||
# it "displays required and optional fields properly" do
|
||||
# expect(page).to have_selector ".form-group.required", text: "Name"
|
||||
# expect(page).to have_optional 'textarea#garden_description'
|
||||
# expect(page).to have_optional 'input#garden_location'
|
||||
# expect(page).to have_optional 'input#garden_area'
|
||||
# end
|
||||
|
||||
# scenario "Create new garden" do
|
||||
# fill_in "Name", with: "New garden"
|
||||
# click_button "Save"
|
||||
# expect(page).to have_content "Garden was successfully created"
|
||||
# expect(page).to have_content "New garden"
|
||||
# end
|
||||
|
||||
# scenario "Refuse to create new garden with negative area" do
|
||||
# visit new_garden_path
|
||||
# fill_in "Name", with: "Negative Garden"
|
||||
# fill_in "Area", with: -5
|
||||
# click_button "Save"
|
||||
# expect(page).not_to have_content "Garden was successfully created"
|
||||
# expect(page).to have_content "Area must be greater than or equal to 0"
|
||||
# end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'rails_helper'
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Gardens", :js do
|
||||
describe "Gardens", :js do
|
||||
let(:member) { FactoryBot.create :member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_garden_path
|
||||
end
|
||||
@@ -20,14 +20,14 @@ feature "Gardens", :js do
|
||||
expect(page).to have_optional 'input#garden_area'
|
||||
end
|
||||
|
||||
scenario "Create new garden" do
|
||||
it "Create new garden" do
|
||||
fill_in "Name", with: "New garden"
|
||||
click_button "Save"
|
||||
expect(page).to have_content "Garden was successfully created"
|
||||
expect(page).to have_content "New garden"
|
||||
end
|
||||
|
||||
scenario "Refuse to create new garden with negative area" do
|
||||
it "Refuse to create new garden with negative area" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "Negative Garden"
|
||||
fill_in "Area", with: -5
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
require 'rails_helper'
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Gardens#index", :js do
|
||||
describe "Gardens#index", :js do
|
||||
context "Logged in as member" do
|
||||
let(:member) { FactoryBot.create :member, login_name: 'shadow' }
|
||||
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
context "with 10 gardens" do
|
||||
before do
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Planting a crop", js: true do
|
||||
describe "Planting a crop", js: true do
|
||||
# name is aaa to ensure it is ordered first
|
||||
let!(:garden) { create :garden, name: 'aaa' }
|
||||
let!(:planting) { create :planting, garden: garden, owner: garden.owner, planted_at: Date.parse("2013-3-10") }
|
||||
let!(:tomato) { create :tomato }
|
||||
let!(:finished_planting) { create :finished_planting, owner: garden.owner, garden: garden, crop: tomato }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as garden.owner
|
||||
end
|
||||
|
||||
scenario "View gardens" do
|
||||
it "View gardens" do
|
||||
visit gardens_path
|
||||
expect(page).to have_content "Everyone's gardens"
|
||||
within '.layout-actions' do
|
||||
@@ -24,7 +24,7 @@ feature "Planting a crop", js: true do
|
||||
expect(page).to have_content "Everyone's gardens"
|
||||
end
|
||||
|
||||
scenario "Marking a garden as inactive" do
|
||||
it "Marking a garden as inactive" do
|
||||
visit garden_path(garden)
|
||||
click_link "Mark as inactive"
|
||||
expect(page).to have_content "Garden was successfully updated"
|
||||
@@ -33,14 +33,14 @@ feature "Planting a crop", js: true do
|
||||
expect(page).not_to have_content "Mark as inactive"
|
||||
end
|
||||
|
||||
scenario "List only active gardens" do
|
||||
it "List only active gardens" do
|
||||
visit garden_path(garden)
|
||||
click_link "Mark as inactive"
|
||||
visit gardens_path
|
||||
expect(page).not_to have_link garden_path(garden)
|
||||
end
|
||||
|
||||
scenario "Create new garden" do
|
||||
it "Create new garden" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "New garden"
|
||||
click_button "Save"
|
||||
@@ -48,7 +48,7 @@ feature "Planting a crop", js: true do
|
||||
expect(page).to have_content "New garden"
|
||||
end
|
||||
|
||||
scenario "Refuse to create new garden with negative area" do
|
||||
it "Refuse to create new garden with negative area" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "Negative Garden"
|
||||
fill_in "Area", with: -5
|
||||
@@ -58,17 +58,17 @@ feature "Planting a crop", js: true do
|
||||
end
|
||||
|
||||
context "Clicking edit from the index page" do
|
||||
background do
|
||||
before do
|
||||
visit gardens_path
|
||||
end
|
||||
|
||||
scenario "button on index to edit garden" do
|
||||
it "button on index to edit garden" do
|
||||
click_link href: edit_garden_path(garden)
|
||||
expect(page).to have_content 'Edit garden'
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Edit garden" do
|
||||
it "Edit garden" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "New garden"
|
||||
click_button "Save"
|
||||
@@ -81,7 +81,7 @@ feature "Planting a crop", js: true do
|
||||
expect(page).to have_content "Different name"
|
||||
end
|
||||
|
||||
scenario "Delete garden" do
|
||||
it "Delete garden" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "New garden"
|
||||
click_button "Save"
|
||||
@@ -98,7 +98,7 @@ feature "Planting a crop", js: true do
|
||||
it_behaves_like "append date"
|
||||
end
|
||||
|
||||
scenario "List only active plantings on a garden" do
|
||||
it "List only active plantings on a garden" do
|
||||
visit gardens_path
|
||||
expect(page).not_to have_content finished_planting.crop_name
|
||||
end
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "browse harvests" do
|
||||
describe "browse harvests" do
|
||||
subject { page }
|
||||
|
||||
let!(:member) { create :member }
|
||||
let!(:harvest) { create :harvest, owner: member }
|
||||
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
feature 'blank optional fields' do
|
||||
describe 'blank optional fields' do
|
||||
let!(:harvest) { create :harvest, :no_description }
|
||||
|
||||
before { visit harvests_path }
|
||||
|
||||
scenario 'read more' do
|
||||
is_expected.not_to have_link "Read more"
|
||||
it 'read more' do
|
||||
expect(subject).not_to have_link "Read more"
|
||||
end
|
||||
end
|
||||
|
||||
feature "filled in optional fields" do
|
||||
describe "filled in optional fields" do
|
||||
let!(:harvest) { create :harvest, :long_description }
|
||||
|
||||
before do
|
||||
visit harvests_path
|
||||
end
|
||||
|
||||
scenario 'read more' do
|
||||
is_expected.to have_link "Read more"
|
||||
it 'read more' do
|
||||
expect(subject).to have_link "Read more"
|
||||
end
|
||||
|
||||
it 'links to #show' do
|
||||
is_expected.to have_link harvest.crop.name, href: harvest_path(harvest)
|
||||
expect(subject).to have_link harvest.crop.name, href: harvest_path(harvest)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
require 'rails_helper'
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Harvesting a crop", :js, :elasticsearch do
|
||||
describe "Harvesting a crop", :js, :elasticsearch do
|
||||
let(:member) { create :member }
|
||||
let!(:maize) { create :maize }
|
||||
let!(:plant_part) { create :plant_part }
|
||||
let(:planting) { create :planting, crop: maize, owner: member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_harvest_path
|
||||
sync_elasticsearch [maize]
|
||||
end
|
||||
|
||||
it_behaves_like "crop suggest", "harvest", "crop"
|
||||
@@ -19,14 +18,14 @@ feature "Harvesting a crop", :js, :elasticsearch do
|
||||
expect(page).to have_content "* denotes a required field"
|
||||
end
|
||||
|
||||
it "displays required and optional fields properly" do
|
||||
expect(page).to have_selector ".form-group.required", text: "What did you harvest?"
|
||||
expect(page).to have_optional 'input#harvest_quantity'
|
||||
expect(page).to have_optional 'input#harvest_weight_quantity'
|
||||
expect(page).to have_optional 'textarea#harvest_description'
|
||||
describe "displays required and optional fields properly" do
|
||||
it { expect(page).to have_selector ".form-group.required", text: "What did you harvest?" }
|
||||
it { expect(page).to have_optional 'input#harvest_quantity' }
|
||||
it { expect(page).to have_optional 'input#harvest_weight_quantity' }
|
||||
it { expect(page).to have_optional 'textarea#harvest_description' }
|
||||
end
|
||||
|
||||
scenario "Creating a new harvest", :js do
|
||||
it "Creating a new harvest", :js do
|
||||
fill_autocomplete "crop", with: "mai"
|
||||
select_from_autocomplete "maize"
|
||||
|
||||
@@ -45,63 +44,67 @@ feature "Harvesting a crop", :js, :elasticsearch do
|
||||
context "Clicking edit from the index page" do
|
||||
let!(:harvest) { create :harvest, crop: maize, owner: member }
|
||||
|
||||
background do
|
||||
before do
|
||||
visit harvests_path
|
||||
end
|
||||
|
||||
scenario "button on index to edit harvest" do
|
||||
it "button on index to edit harvest" do
|
||||
click_link "edit_harvest_glyphicon"
|
||||
expect(current_path).to eq edit_harvest_path(harvest)
|
||||
expect(page).to have_content 'Editing harvest'
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Clicking link to owner's profile" do
|
||||
it "Clicking link to owner's profile" do
|
||||
visit member_harvests_path(member)
|
||||
click_link "View #{member}'s profile >>"
|
||||
expect(current_path).to eq member_path member
|
||||
end
|
||||
|
||||
scenario "Harvesting from crop page" do
|
||||
visit crop_path(maize)
|
||||
within '.crop-actions' do
|
||||
click_link "Harvest #{maize.name}"
|
||||
describe "Harvesting from crop page" do
|
||||
before do
|
||||
visit crop_path(maize)
|
||||
within '.crop-actions' do
|
||||
click_link "Harvest #{maize.name}"
|
||||
end
|
||||
within "form#new_harvest" do
|
||||
select plant_part.name, from: 'harvest[plant_part_id]'
|
||||
expect(page).to have_selector "input[value='maize']"
|
||||
click_button "Save"
|
||||
end
|
||||
end
|
||||
within "form#new_harvest" do
|
||||
|
||||
it { expect(page).to have_content "harvest was successfully created." }
|
||||
it { expect(page).to have_content "maize" }
|
||||
end
|
||||
|
||||
describe "Harvesting from planting page" do
|
||||
let!(:planting) { create :planting, crop: maize, owner: member, garden: member.gardens.first }
|
||||
before do
|
||||
visit planting_path(planting)
|
||||
within ".planting-actions" do
|
||||
click_link "Harvest"
|
||||
end
|
||||
|
||||
select plant_part.name, from: 'harvest[plant_part_id]'
|
||||
expect(page).to have_selector "input[value='maize']"
|
||||
click_button "Save"
|
||||
end
|
||||
|
||||
expect(page).to have_content "harvest was successfully created."
|
||||
expect(page).to have_content "maize"
|
||||
end
|
||||
|
||||
scenario "Harvesting from planting page" do
|
||||
planting = create :planting, crop: maize, owner: member, garden: member.gardens.first
|
||||
visit planting_path(planting)
|
||||
within ".planting-actions" do
|
||||
click_link "Harvest"
|
||||
end
|
||||
|
||||
select plant_part.name, from: 'harvest[plant_part_id]'
|
||||
click_button "Save"
|
||||
|
||||
expect(page).to have_content "harvest was successfully created."
|
||||
expect(page).to have_content planting.garden.name
|
||||
expect(page).to have_content "maize"
|
||||
it { expect(page).to have_content "harvest was successfully created." }
|
||||
it { expect(page).to have_content planting.garden.name }
|
||||
it { expect(page).to have_content "maize" }
|
||||
end
|
||||
|
||||
context "Editing a harvest" do
|
||||
let(:existing_harvest) { create :harvest, crop: maize, owner: member }
|
||||
let!(:other_plant_part) { create :plant_part, name: 'chocolate' }
|
||||
|
||||
background do
|
||||
before do
|
||||
visit harvest_path(existing_harvest)
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
scenario "Saving without edits" do
|
||||
it "Saving without edits" do
|
||||
# Check that the autosuggest helper properly fills inputs with
|
||||
# existing resource's data
|
||||
click_button "Save"
|
||||
@@ -109,7 +112,7 @@ feature "Harvesting a crop", :js, :elasticsearch do
|
||||
expect(page).to have_content "maize"
|
||||
end
|
||||
|
||||
scenario "change plant part" do
|
||||
it "change plant part" do
|
||||
select other_plant_part.name, from: 'harvest[plant_part_id]'
|
||||
click_button "Save"
|
||||
expect(page).to have_content "harvest was successfully updated."
|
||||
@@ -127,11 +130,11 @@ feature "Harvesting a crop", :js, :elasticsearch do
|
||||
planted_at: Time.zone.yesterday
|
||||
end
|
||||
|
||||
background do
|
||||
before do
|
||||
visit harvest_path(existing_harvest)
|
||||
end
|
||||
|
||||
scenario "linking to a planting" do
|
||||
it "linking to a planting" do
|
||||
expect(page).to have_content existing_planting.to_s
|
||||
choose("harvest_planting_id_#{existing_planting.id}")
|
||||
click_button "save"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "home page" do
|
||||
describe "home page" do
|
||||
subject { page }
|
||||
|
||||
let(:member) { FactoryBot.create :member }
|
||||
@@ -16,7 +16,7 @@ feature "home page" do
|
||||
let!(:finished_seed) { FactoryBot.create :tradable_seed, finished: true }
|
||||
let!(:untradable_seed) { FactoryBot.create :untradable_seed }
|
||||
|
||||
background do
|
||||
before do
|
||||
# Add photos, so they can appear on home page
|
||||
planting.photos << photo
|
||||
seed.photos << photo
|
||||
@@ -27,13 +27,13 @@ feature "home page" do
|
||||
|
||||
shared_examples 'shows seeds' do
|
||||
it "show tradeable seed" do
|
||||
is_expected.to have_link href: seed_path(tradable_seed)
|
||||
expect(subject).to have_link href: seed_path(tradable_seed)
|
||||
end
|
||||
it "does not show finished seeds" do
|
||||
is_expected.not_to have_link href: seed_path(finished_seed)
|
||||
expect(subject).not_to have_link href: seed_path(finished_seed)
|
||||
end
|
||||
it "does not show untradable seeds" do
|
||||
is_expected.not_to have_link href: seed_path(untradable_seed)
|
||||
expect(subject).not_to have_link href: seed_path(untradable_seed)
|
||||
end
|
||||
|
||||
it { is_expected.to have_text 'View all seeds' }
|
||||
@@ -41,14 +41,14 @@ feature "home page" do
|
||||
|
||||
shared_examples 'show plantings' do
|
||||
it 'shows plantings section' do
|
||||
is_expected.to have_text 'Recently Planted'
|
||||
is_expected.to have_link href: planting_path(planting)
|
||||
expect(subject).to have_text 'Recently Planted'
|
||||
expect(subject).to have_link href: planting_path(planting)
|
||||
end
|
||||
end
|
||||
shared_examples 'show harvests' do
|
||||
it 'shows harvests section' do
|
||||
is_expected.to have_text 'Recently Harvested'
|
||||
is_expected.to have_link href: harvest_path(harvest)
|
||||
expect(subject).to have_text 'Recently Harvested'
|
||||
expect(subject).to have_link href: harvest_path(harvest)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -61,12 +61,12 @@ feature "home page" do
|
||||
describe 'shows recently added crops' do
|
||||
it { is_expected.to have_text 'Recently Added' }
|
||||
it 'link to newest crops' do
|
||||
is_expected.to have_link crop.name, href: crop_path(crop)
|
||||
expect(subject).to have_link crop.name, href: crop_path(crop)
|
||||
end
|
||||
end
|
||||
|
||||
it 'includes a link to all crops' do
|
||||
is_expected.to have_link 'View all crops'
|
||||
expect(subject).to have_link 'View all crops'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -79,7 +79,8 @@ feature "home page" do
|
||||
end
|
||||
|
||||
context "when signed in" do
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
include_examples 'show crops'
|
||||
include_examples 'show plantings'
|
||||
include_examples 'show harvests'
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Likeable', js: true do
|
||||
describe 'Likeable', js: true do
|
||||
let(:member) { FactoryBot.create(:member) }
|
||||
let(:another_member) { FactoryBot.create(:london_member) }
|
||||
let(:post) { FactoryBot.create(:post) }
|
||||
|
||||
context 'logged in member' do
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit post_path(post)
|
||||
end
|
||||
|
||||
scenario 'can be liked' do
|
||||
it 'can be liked' do
|
||||
expect(page).to have_link 'Like'
|
||||
click_link 'Like'
|
||||
expect(page).to have_content '1 like'
|
||||
@@ -23,7 +23,7 @@ feature 'Likeable', js: true do
|
||||
expect(page).to have_content '0 likes'
|
||||
end
|
||||
|
||||
scenario 'displays correct number of likes' do
|
||||
it 'displays correct number of likes' do
|
||||
expect(page).to have_link 'Like'
|
||||
click_link 'Like'
|
||||
expect(page).to have_content '1 like'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Changing locales", js: true do
|
||||
describe "Changing locales", js: true do
|
||||
after { I18n.locale = :en }
|
||||
|
||||
scenario "Locale can be set with a query param" do
|
||||
it "Locale can be set with a query param" do
|
||||
visit root_path
|
||||
expect(page).to have_content("a community of food gardeners.")
|
||||
visit root_path(locale: 'ja')
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "member profile", js: true do
|
||||
describe "member profile", js: true do
|
||||
context "signed out member" do
|
||||
let(:member) { create :member }
|
||||
|
||||
scenario "basic details on member profile page" do
|
||||
it "basic details on member profile page" do
|
||||
visit member_path(member)
|
||||
expect(page).to have_css("h1", text: member.login_name)
|
||||
expect(page).to have_content member.bio
|
||||
@@ -12,20 +12,20 @@ feature "member profile", js: true do
|
||||
expect(page).to have_link "More about this garden...", href: garden_path(member.gardens.first)
|
||||
end
|
||||
|
||||
scenario "no bio" do
|
||||
it "no bio" do
|
||||
member.bio = nil
|
||||
member.save
|
||||
visit member_path(member)
|
||||
expect(page).to have_content "hasn't written a bio yet"
|
||||
end
|
||||
|
||||
scenario "gravatar" do
|
||||
it "gravatar" do
|
||||
visit member_path(member)
|
||||
expect(page).to have_css "img.avatar"
|
||||
end
|
||||
|
||||
context "location" do
|
||||
scenario "member has set location" do
|
||||
it "member has set location" do
|
||||
london_member = create :london_member
|
||||
visit member_path(london_member)
|
||||
expect(page).to have_css("h1>small", text: london_member.location)
|
||||
@@ -33,7 +33,7 @@ feature "member profile", js: true do
|
||||
expect(page).to have_content "See other members, plantings, seeds and more near #{london_member.location}"
|
||||
end
|
||||
|
||||
scenario "member has not set location" do
|
||||
it "member has not set location" do
|
||||
visit member_path(member)
|
||||
expect(page).not_to have_css("h1>small")
|
||||
expect(page).not_to have_css("#membermap")
|
||||
@@ -42,31 +42,31 @@ feature "member profile", js: true do
|
||||
end
|
||||
|
||||
context "email privacy" do
|
||||
scenario "public email address" do
|
||||
it "public email address" do
|
||||
public_member = create :public_member
|
||||
visit member_path(public_member)
|
||||
expect(page).to have_content public_member.email
|
||||
end
|
||||
scenario "private email address" do
|
||||
it "private email address" do
|
||||
visit member_path(member)
|
||||
expect(page).not_to have_content member.email
|
||||
end
|
||||
end
|
||||
|
||||
context "email privacy" do
|
||||
scenario "public email address" do
|
||||
it "public email address" do
|
||||
public_member = create :public_member
|
||||
visit member_path(public_member)
|
||||
expect(page).to have_content public_member.email
|
||||
end
|
||||
scenario "private email address" do
|
||||
it "private email address" do
|
||||
visit member_path(member)
|
||||
expect(page).not_to have_content member.email
|
||||
end
|
||||
end
|
||||
|
||||
context "activity stats" do
|
||||
scenario "with no activity" do
|
||||
it "with no activity" do
|
||||
visit member_path(member)
|
||||
expect(page).to have_content "Activity"
|
||||
expect(page).to have_content "0 plantings"
|
||||
@@ -75,7 +75,7 @@ feature "member profile", js: true do
|
||||
expect(page).to have_content "0 posts"
|
||||
end
|
||||
|
||||
scenario "with some activity" do
|
||||
it "with some activity" do
|
||||
create_list :planting, 2, owner: member
|
||||
create_list :harvest, 3, owner: member
|
||||
create_list :seed, 4, owner: member
|
||||
@@ -88,13 +88,13 @@ feature "member profile", js: true do
|
||||
end
|
||||
end
|
||||
|
||||
scenario "twitter link" do
|
||||
it "twitter link" do
|
||||
twitter_auth = create :authentication, member: member
|
||||
visit member_path(member)
|
||||
expect(page).to have_link twitter_auth.name, href: "http://twitter.com/#{twitter_auth.name}"
|
||||
end
|
||||
|
||||
scenario "flickr link" do
|
||||
it "flickr link" do
|
||||
flickr_auth = create :flickr_authentication, member: member
|
||||
visit member_path(member)
|
||||
expect(page).to have_link flickr_auth.name, href: "http://flickr.com/photos/#{flickr_auth.uid}"
|
||||
@@ -107,56 +107,56 @@ feature "member profile", js: true do
|
||||
let(:admin_member) { create :admin_member }
|
||||
let(:crop_wrangler) { create :crop_wrangling_member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as(member)
|
||||
end
|
||||
|
||||
scenario "admin user's page" do
|
||||
it "admin user's page" do
|
||||
visit member_path(admin_member)
|
||||
expect(page).to have_text "Admin"
|
||||
end
|
||||
|
||||
scenario "crop wrangler's page" do
|
||||
it "crop wrangler's page" do
|
||||
visit member_path(crop_wrangler)
|
||||
expect(page).to have_text "Crop Wrangler"
|
||||
end
|
||||
|
||||
scenario "ordinary user's page" do
|
||||
it "ordinary user's page" do
|
||||
visit member_path(other_member)
|
||||
expect(page).not_to have_text "Crop Wrangler"
|
||||
expect(page).not_to have_text "Admin"
|
||||
end
|
||||
|
||||
context "your own profile page" do
|
||||
background do
|
||||
before do
|
||||
visit member_path(member)
|
||||
end
|
||||
|
||||
scenario "has a link to create new garden" do
|
||||
it "has a link to create new garden" do
|
||||
expect(page).to have_link "New Garden", href: new_garden_path
|
||||
end
|
||||
|
||||
scenario "has a button to edit profile" do
|
||||
it "has a button to edit profile" do
|
||||
expect(page).to have_link "Edit profile", href: edit_member_registration_path
|
||||
end
|
||||
end
|
||||
|
||||
context "someone else's profile page" do
|
||||
background do
|
||||
before do
|
||||
visit member_path(other_member)
|
||||
end
|
||||
|
||||
scenario "has a private message button" do
|
||||
it "has a private message button" do
|
||||
expect(page).to have_link "Send message", href: new_notification_path(recipient_id: other_member.id)
|
||||
end
|
||||
end
|
||||
|
||||
context "home page" do
|
||||
background do
|
||||
before do
|
||||
visit root_path
|
||||
end
|
||||
|
||||
scenario "does not have a button to edit profile" do
|
||||
it "does not have a button to edit profile" do
|
||||
expect(page).not_to have_link "Edit profile", href: edit_member_registration_path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "member deletion" do
|
||||
describe "member deletion" do
|
||||
context "with activity and followers" do
|
||||
let(:member) { FactoryBot.create(:member) }
|
||||
let(:other_member) { FactoryBot.create(:member) }
|
||||
@@ -12,7 +12,7 @@ feature "member deletion" do
|
||||
let!(:secondgarden) { FactoryBot.create(:garden, owner: member) }
|
||||
let(:admin) { FactoryBot.create(:admin_member) }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as(member)
|
||||
visit member_path(other_member)
|
||||
click_link 'Follow'
|
||||
@@ -30,13 +30,13 @@ feature "member deletion" do
|
||||
FactoryBot.create(:member, login_name: "ex_member")
|
||||
end
|
||||
|
||||
scenario "has option to delete on member profile page" do
|
||||
it "has option to delete on member profile page" do
|
||||
visit member_path(member)
|
||||
click_link 'Edit profile'
|
||||
expect(page).to have_link "Delete Account"
|
||||
end
|
||||
|
||||
scenario "asks for password before deletion" do
|
||||
it "asks for password before deletion" do
|
||||
visit member_path(member)
|
||||
click_link 'Edit profile'
|
||||
click_link 'Delete Account'
|
||||
@@ -44,7 +44,7 @@ feature "member deletion" do
|
||||
expect(page).to have_content "Current password can't be blank"
|
||||
end
|
||||
|
||||
scenario "password must be correct" do
|
||||
it "password must be correct" do
|
||||
visit member_path(member)
|
||||
click_link 'Edit profile'
|
||||
click_link 'Delete Account'
|
||||
@@ -53,7 +53,7 @@ feature "member deletion" do
|
||||
expect(page).to have_content "Current password is invalid"
|
||||
end
|
||||
|
||||
scenario "deletes and removes bio" do
|
||||
it "deletes and removes bio" do
|
||||
visit member_path(member)
|
||||
click_link 'Edit profile'
|
||||
click_link 'Delete Account'
|
||||
@@ -64,7 +64,7 @@ feature "member deletion" do
|
||||
end
|
||||
|
||||
context "deletes and" do
|
||||
background do
|
||||
before do
|
||||
logout
|
||||
login_as(member)
|
||||
visit member_path(member)
|
||||
@@ -79,39 +79,39 @@ feature "member deletion" do
|
||||
it { expect(Member.with_deleted.find(member.id)).to eq member }
|
||||
end
|
||||
|
||||
scenario "removes plantings" do
|
||||
it "removes plantings" do
|
||||
visit planting_path(planting)
|
||||
expect(page.status_code).to eq(404)
|
||||
end
|
||||
|
||||
scenario "removes gardens" do
|
||||
it "removes gardens" do
|
||||
visit garden_path(secondgarden)
|
||||
expect(page.status_code).to eq(404)
|
||||
end
|
||||
|
||||
scenario "removes harvests and seeds" do
|
||||
it "removes harvests and seeds" do
|
||||
visit harvest_path(harvest)
|
||||
expect(page.status_code).to eq(404)
|
||||
end
|
||||
|
||||
scenario "removes seeds" do
|
||||
it "removes seeds" do
|
||||
visit seed_path(seed)
|
||||
expect(page.status_code).to eq(404)
|
||||
end
|
||||
|
||||
scenario "removes members from following" do
|
||||
it "removes members from following" do
|
||||
visit member_follows_path(other_member)
|
||||
expect(page).not_to have_content member.login_name.to_s
|
||||
visit member_followers_path(other_member)
|
||||
expect(page).not_to have_content member.login_name.to_s
|
||||
end
|
||||
|
||||
scenario "replaces posts with deletion note" do
|
||||
it "replaces posts with deletion note" do
|
||||
visit post_path(memberpost)
|
||||
expect(page.status_code).to eq(404)
|
||||
end
|
||||
|
||||
scenario "replaces comments on others' posts with deletion note, leaving post intact" do
|
||||
it "replaces comments on others' posts with deletion note, leaving post intact" do
|
||||
FactoryBot.create :comment, post: othermemberpost, author: member, body: 'i am deleting my account'
|
||||
|
||||
visit post_path(othermemberpost)
|
||||
@@ -120,7 +120,7 @@ feature "member deletion" do
|
||||
expect(page).to have_content "Member Deleted"
|
||||
end
|
||||
|
||||
scenario "can't be interesting" do
|
||||
it "can't be interesting" do
|
||||
expect(Member.interesting).not_to include(member)
|
||||
expect(Planting.interesting).not_to include(planting)
|
||||
expect(Seed.interesting).not_to include(seed)
|
||||
@@ -128,7 +128,7 @@ feature "member deletion" do
|
||||
|
||||
pending "doesn't show in nearby"
|
||||
|
||||
scenario "can no longer sign in" do
|
||||
it "can no longer sign in" do
|
||||
visit new_member_session_path
|
||||
fill_in 'Login', with: member.login_name
|
||||
fill_in 'Password', with: member.password
|
||||
@@ -145,7 +145,7 @@ feature "member deletion" do
|
||||
FactoryBot.create(:cropbot)
|
||||
let!(:ex_wrangler) { FactoryBot.create(:crop_wrangling_member, login_name: "ex_wrangler") }
|
||||
|
||||
scenario "leaves crops behind" do
|
||||
it "leaves crops behind" do
|
||||
login_as(otherwrangler)
|
||||
visit edit_crop_path(crop)
|
||||
expect(page).to have_content member.login_name
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "members list" do
|
||||
describe "members list" do
|
||||
context "list all members" do
|
||||
let!(:member1) { create :member, login_name: "Archaeopteryx", confirmed_at: Time.zone.parse('2013-02-10') }
|
||||
let!(:member2) { create :member, login_name: "Zephyrosaurus", confirmed_at: Time.zone.parse('2014-01-11') }
|
||||
let!(:member3) { create :member, login_name: "Testingname", confirmed_at: Time.zone.parse('2014-05-09') }
|
||||
|
||||
scenario "default alphabetical sort" do
|
||||
it "default alphabetical sort" do
|
||||
visit members_path
|
||||
expect(page).to have_css "#sort"
|
||||
expect(page).to have_selector "form"
|
||||
@@ -16,7 +16,7 @@ feature "members list" do
|
||||
expect(all_links.last).to have_text member2.login_name
|
||||
end
|
||||
|
||||
scenario "recently joined sort" do
|
||||
it "recently joined sort" do
|
||||
visit members_path
|
||||
expect(page).to have_css "#sort"
|
||||
expect(page).to have_selector "form"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Notifications", :js do
|
||||
describe "Notifications", :js do
|
||||
let(:sender) { create :member }
|
||||
let(:recipient) { create :member, login_name: 'beyonce' }
|
||||
|
||||
@@ -13,12 +13,12 @@ feature "Notifications", :js do
|
||||
post_id: nil
|
||||
end
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as recipient
|
||||
visit notification_path(notification)
|
||||
end
|
||||
|
||||
scenario "Replying to the notification" do
|
||||
it "Replying to the notification" do
|
||||
click_link "Reply"
|
||||
expect(page).to have_content "Notification body"
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "new photo page" do
|
||||
describe "new photo page" do
|
||||
let(:photo) { FactoryBot.create :photo }
|
||||
|
||||
context "signed in member" do
|
||||
let(:member) { FactoryBot.create :member }
|
||||
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
context "viewing a planting" do
|
||||
let(:planting) { FactoryBot.create :planting, owner: member }
|
||||
|
||||
scenario "add photo" do
|
||||
it "add photo" do
|
||||
visit planting_path(planting)
|
||||
within '.planting-actions' do
|
||||
click_link('Add photo')
|
||||
@@ -23,7 +23,7 @@ feature "new photo page" do
|
||||
context "viewing a harvest" do
|
||||
let(:harvest) { FactoryBot.create :harvest, owner: member }
|
||||
|
||||
scenario "add photo" do
|
||||
it "add photo" do
|
||||
visit harvest_path(harvest)
|
||||
within '.harvest-actions' do
|
||||
click_link "Add photo"
|
||||
@@ -35,7 +35,7 @@ feature "new photo page" do
|
||||
context "viewing a garden" do
|
||||
let(:garden) { FactoryBot.create :garden, owner: member }
|
||||
|
||||
scenario "add photo" do
|
||||
it "add photo" do
|
||||
visit garden_path(garden)
|
||||
within '.garden-actions' do
|
||||
click_link "Add photo"
|
||||
@@ -47,7 +47,7 @@ feature "new photo page" do
|
||||
describe "viewing a seed" do
|
||||
let(:seed) { FactoryBot.create :seed, owner: member }
|
||||
|
||||
scenario "add photo" do
|
||||
it "add photo" do
|
||||
visit seed_path(seed)
|
||||
first('.seed-actions').click_link('Add photo')
|
||||
expect(page).to have_text seed.to_s
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "show photo page" do
|
||||
describe "show photo page" do
|
||||
context "signed in member" do
|
||||
let(:member) { create :member }
|
||||
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
context "linked to planting" do
|
||||
let(:planting) { create :planting }
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
require "rails_helper"
|
||||
|
||||
feature "User searches" do
|
||||
describe "User searches" do
|
||||
let(:member) { create :member, location: "Philippines" }
|
||||
let!(:maize) { create :maize }
|
||||
let(:garden) { create :garden, owner: member }
|
||||
let!(:seed1) { create :seed, owner: member }
|
||||
let!(:planting) { create :planting, garden: garden, owner: member, planted_at: Date.parse("2013-3-10") }
|
||||
|
||||
scenario "with a valid place" do
|
||||
it "with a valid place" do
|
||||
visit places_path
|
||||
search_with "Philippines"
|
||||
expect(page).to have_content "community near Philippines"
|
||||
@@ -16,7 +16,7 @@ feature "User searches" do
|
||||
expect(page).not_to have_content "No results found"
|
||||
end
|
||||
|
||||
scenario "with a blank search string" do
|
||||
it "with a blank search string" do
|
||||
visit places_path
|
||||
search_with ""
|
||||
expect(page).to have_content "Please enter a valid location"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
require 'capybara/email/rspec'
|
||||
|
||||
feature "Planting reminder email", :js do
|
||||
describe "Planting reminder email", :js do
|
||||
let(:member) { create :member }
|
||||
let(:mail) { Notifier.planting_reminder(member) }
|
||||
|
||||
@@ -11,16 +11,16 @@ feature "Planting reminder email", :js do
|
||||
{ host: 'localhost', port: 8080 }
|
||||
end
|
||||
|
||||
scenario "has a greeting" do
|
||||
it "has a greeting" do
|
||||
expect(mail).to have_content "Hello"
|
||||
end
|
||||
|
||||
context "when member has no plantings" do
|
||||
scenario "tells you to track your plantings" do
|
||||
it "tells you to track your plantings" do
|
||||
expect(mail).to have_content "planting your first crop"
|
||||
end
|
||||
|
||||
scenario "doesn't list plantings" do
|
||||
it "doesn't list plantings" do
|
||||
expect(mail).not_to have_content "most recent plantings you've told us about"
|
||||
end
|
||||
end
|
||||
@@ -31,7 +31,7 @@ feature "Planting reminder email", :js do
|
||||
let!(:p1) { create :planting, garden: member.gardens.first, owner: member }
|
||||
let!(:p2) { create :planting, garden: member.gardens.first, owner: member }
|
||||
|
||||
scenario "lists plantings" do
|
||||
it "lists plantings" do
|
||||
expect(mail).to have_content "most recent plantings you've told us about"
|
||||
expect(mail).to have_link p1.to_s, href: planting_url(p1)
|
||||
expect(mail).to have_link p2.to_s, href: planting_url(p2)
|
||||
@@ -40,11 +40,11 @@ feature "Planting reminder email", :js do
|
||||
end
|
||||
|
||||
context "when member has no harvests" do
|
||||
scenario "tells you to tracking plantings" do
|
||||
it "tells you to tracking plantings" do
|
||||
expect(mail).to have_content "Get started now by tracking your first harvest"
|
||||
end
|
||||
|
||||
scenario "doesn't list plantings" do
|
||||
it "doesn't list plantings" do
|
||||
expect(mail).not_to have_content "the last few things you harvested were"
|
||||
end
|
||||
end
|
||||
@@ -55,7 +55,7 @@ feature "Planting reminder email", :js do
|
||||
let!(:h1) { create :harvest, owner: member }
|
||||
let!(:h2) { create :harvest, owner: member }
|
||||
|
||||
scenario "lists harvests" do
|
||||
it "lists harvests" do
|
||||
expect(mail).to have_content "the last few things you harvested were"
|
||||
expect(mail).to have_link h1.to_s, href: harvest_url(h1)
|
||||
expect(mail).to have_link h2.to_s, href: harvest_url(h2)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require "rails_helper"
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Planting a crop", :js, :elasticsearch do
|
||||
describe "Planting a crop", :js, :elasticsearch do
|
||||
let(:member) { FactoryBot.create :member }
|
||||
let!(:maize) { FactoryBot.create :maize }
|
||||
let(:garden) { FactoryBot.create :garden, owner: member }
|
||||
@@ -9,10 +9,9 @@ feature "Planting a crop", :js, :elasticsearch do
|
||||
FactoryBot.create :planting, garden: garden, owner: member, planted_at: Date.parse("2013-03-10")
|
||||
end
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_planting_path
|
||||
sync_elasticsearch [maize]
|
||||
end
|
||||
|
||||
it_behaves_like "crop suggest", "planting"
|
||||
@@ -32,26 +31,30 @@ feature "Planting a crop", :js, :elasticsearch do
|
||||
it { expect(page).to have_optional 'input#planting_finished_at' }
|
||||
end
|
||||
|
||||
scenario "Creating a new planting" do
|
||||
fill_autocomplete "crop", with: "mai"
|
||||
select_from_autocomplete "maize"
|
||||
within "form#new_planting" do
|
||||
fill_in "When", with: "2014-06-15"
|
||||
fill_in "How many?", with: 42
|
||||
select "cutting", from: "Planted from:"
|
||||
select "semi-shade", from: "Sun or shade?"
|
||||
fill_in "Tell us more about it", with: "It's rad."
|
||||
click_button "Save"
|
||||
describe "Creating a new planting" do
|
||||
before do
|
||||
fill_autocomplete "crop", with: "mai"
|
||||
select_from_autocomplete "maize"
|
||||
within "form#new_planting" do
|
||||
fill_in "When", with: "2014-06-15"
|
||||
fill_in "How many?", with: 42
|
||||
select "cutting", from: "Planted from:"
|
||||
select "semi-shade", from: "Sun or shade?"
|
||||
fill_in "Tell us more about it", with: "It's rad."
|
||||
click_button "Save"
|
||||
end
|
||||
end
|
||||
|
||||
expect(page).to have_content "planting was successfully created"
|
||||
expect(page).to have_content "Not enough data"
|
||||
it { expect(page).to have_content "planting was successfully created" }
|
||||
it { expect(page).to have_content "Not enough data" }
|
||||
end
|
||||
|
||||
scenario "Clicking link to owner's profile" do
|
||||
visit member_plantings_path(member)
|
||||
click_link "View #{member}'s profile >>"
|
||||
expect(current_path).to eq member_path(member)
|
||||
describe "Clicking link to owner's profile" do
|
||||
before do
|
||||
visit member_plantings_path(member)
|
||||
click_link "View #{member}'s profile >>"
|
||||
end
|
||||
it { expect(current_path).to eq member_path(member) }
|
||||
end
|
||||
|
||||
describe "Progress bar status on planting creation" do
|
||||
@@ -151,7 +154,7 @@ feature "Planting a crop", :js, :elasticsearch do
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Planting from crop page" do
|
||||
it "Planting from crop page" do
|
||||
visit crop_path(maize)
|
||||
within '.crop-actions' do
|
||||
click_link "Plant maize"
|
||||
@@ -165,7 +168,7 @@ feature "Planting a crop", :js, :elasticsearch do
|
||||
expect(page).to have_content "maize"
|
||||
end
|
||||
|
||||
scenario "Editing a planting to add details" do
|
||||
it "Editing a planting to add details" do
|
||||
visit planting_path(planting)
|
||||
click_link "Edit"
|
||||
fill_in "Tell us more about it", with: "Some extra notes"
|
||||
@@ -173,7 +176,7 @@ feature "Planting a crop", :js, :elasticsearch do
|
||||
expect(page).to have_content "planting was successfully updated"
|
||||
end
|
||||
|
||||
scenario "Editing a planting to fill in the finished date" do
|
||||
it "Editing a planting to fill in the finished date" do
|
||||
visit planting_path(planting)
|
||||
expect(page).to have_content "Not enough data"
|
||||
click_link "Edit"
|
||||
@@ -184,7 +187,7 @@ feature "Planting a crop", :js, :elasticsearch do
|
||||
expect(page).not_to have_content "Not enough data"
|
||||
end
|
||||
|
||||
scenario "Marking a planting as finished" do
|
||||
it "Marking a planting as finished" do
|
||||
fill_autocomplete "crop", with: "mai"
|
||||
select_from_autocomplete "maize"
|
||||
within "form#new_planting" do
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Post a post' do
|
||||
describe 'Post a post' do
|
||||
let(:member) { create :member }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_post_path
|
||||
end
|
||||
|
||||
scenario "creating a post" do
|
||||
it "creating a post" do
|
||||
fill_in "post_subject", with: "Testing"
|
||||
fill_in "post_body", with: "This is a sample test"
|
||||
click_button "Post"
|
||||
@@ -19,11 +19,11 @@ feature 'Post a post' do
|
||||
context "editing a post" do
|
||||
let(:existing_post) { create :post, author: member }
|
||||
|
||||
background do
|
||||
before do
|
||||
visit edit_post_path(existing_post)
|
||||
end
|
||||
|
||||
scenario "saving edit" do
|
||||
it "saving edit" do
|
||||
fill_in "post_subject", with: "Testing Edit"
|
||||
click_button "Post"
|
||||
expect(page).to have_content "Post was successfully updated"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Comments RSS feed' do
|
||||
scenario 'The index feed exists' do
|
||||
describe 'Comments RSS feed' do
|
||||
it 'The index feed exists' do
|
||||
visit comments_path(format: 'rss')
|
||||
expect(page.status_code).to equal 200
|
||||
end
|
||||
|
||||
scenario 'The index title is what we expect' do
|
||||
it 'The index title is what we expect' do
|
||||
visit comments_path(format: 'rss')
|
||||
expect(page).to have_content "Recent comments on all posts (#{ENV['GROWSTUFF_SITE_NAME']})"
|
||||
end
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Crops RSS feed' do
|
||||
scenario 'The index feed exists' do
|
||||
describe 'Crops RSS feed' do
|
||||
it 'The index feed exists' do
|
||||
visit crops_path(format: 'rss')
|
||||
expect(page.status_code).to equal 200
|
||||
end
|
||||
|
||||
scenario 'The index title is what we expect' do
|
||||
it 'The index title is what we expect' do
|
||||
visit crops_path(format: 'rss')
|
||||
expect(page).to have_content "Recently added crops (#{ENV['GROWSTUFF_SITE_NAME']})"
|
||||
end
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Members RSS feed' do
|
||||
describe 'Members RSS feed' do
|
||||
let(:member) { create :member }
|
||||
|
||||
scenario 'The show action exists' do
|
||||
it 'The show action exists' do
|
||||
visit member_path(member, format: 'rss')
|
||||
expect(page.status_code).to equal 200
|
||||
end
|
||||
|
||||
scenario 'The show action title is what we expect' do
|
||||
it 'The show action title is what we expect' do
|
||||
visit member_path(member, format: 'rss')
|
||||
expect(page).to have_content "#{member.login_name}'s recent posts (#{ENV['GROWSTUFF_SITE_NAME']})"
|
||||
end
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Plantings RSS feed' do
|
||||
scenario 'The index feed exists' do
|
||||
describe 'Plantings RSS feed' do
|
||||
it 'The index feed exists' do
|
||||
visit plantings_path(format: 'rss')
|
||||
expect(page.status_code).to equal 200
|
||||
end
|
||||
|
||||
scenario 'The index title is what we expect' do
|
||||
it 'The index title is what we expect' do
|
||||
visit plantings_path(format: 'rss')
|
||||
expect(page).to have_content "Recent plantings from "\
|
||||
"#{@owner || 'all members'} (#{ENV['GROWSTUFF_SITE_NAME']})"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Posts RSS feed' do
|
||||
scenario 'The index feed exists' do
|
||||
describe 'Posts RSS feed' do
|
||||
it 'The index feed exists' do
|
||||
visit posts_path(format: 'rss')
|
||||
expect(page.status_code).to equal 200
|
||||
end
|
||||
|
||||
scenario 'The index title is what we expect' do
|
||||
it 'The index title is what we expect' do
|
||||
visit posts_path(format: 'rss')
|
||||
expect(page).to have_content "Recent posts from "\
|
||||
"#{@author || 'all members'} (#{ENV['GROWSTUFF_SITE_NAME']})"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature 'Seeds RSS feed' do
|
||||
scenario 'The index feed exists' do
|
||||
describe 'Seeds RSS feed' do
|
||||
it 'The index feed exists' do
|
||||
visit seeds_path(format: 'rss')
|
||||
expect(page.status_code).to equal 200
|
||||
end
|
||||
|
||||
scenario 'The index title is what we expect' do
|
||||
it 'The index title is what we expect' do
|
||||
visit seeds_path(format: 'rss')
|
||||
expect(page).to have_content "Recent seeds from "\
|
||||
"#{@owner || 'all members'} (#{ENV['GROWSTUFF_SITE_NAME']})"
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "Scientific names", js: true do
|
||||
describe "Scientific names", js: true do
|
||||
let!(:zea_mays) { create :zea_mays }
|
||||
let(:crop) { zea_mays.crop }
|
||||
|
||||
scenario "Display scientific names on crop page" do
|
||||
it "Display scientific names on crop page" do
|
||||
visit crop_path(zea_mays.crop)
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_content zea_mays.name
|
||||
end
|
||||
|
||||
scenario "Index page for scientific names" do
|
||||
it "Index page for scientific names" do
|
||||
visit scientific_names_path
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_content zea_mays.name
|
||||
@@ -20,11 +20,11 @@ feature "Scientific names", js: true do
|
||||
let!(:crop_wranglers) { create_list :crop_wrangling_member, 3 }
|
||||
let(:member) { crop_wranglers.first }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as(member)
|
||||
end
|
||||
|
||||
scenario "Crop wranglers can edit scientific names" do
|
||||
it "Crop wranglers can edit scientific names" do
|
||||
visit crop_path(crop)
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_content "CROP WRANGLER"
|
||||
@@ -39,7 +39,7 @@ feature "Scientific names", js: true do
|
||||
expect(page).to have_content 'crop was successfully updated'
|
||||
end
|
||||
|
||||
scenario "Crop wranglers can delete scientific names" do
|
||||
it "Crop wranglers can delete scientific names" do
|
||||
visit crop_path(zea_mays.crop)
|
||||
expect(page).to have_link "Delete",
|
||||
href: scientific_name_path(zea_mays)
|
||||
@@ -49,7 +49,7 @@ feature "Scientific names", js: true do
|
||||
expect(page).to have_content 'Scientific name was successfully deleted.'
|
||||
end
|
||||
|
||||
scenario "Crop wranglers can add scientific names" do
|
||||
it "Crop wranglers can add scientific names" do
|
||||
visit crop_path(crop)
|
||||
expect(page).to have_link "Add",
|
||||
href: new_scientific_name_path(crop_id: crop.id)
|
||||
@@ -63,7 +63,7 @@ feature "Scientific names", js: true do
|
||||
expect(page).to have_content 'crop was successfully created.'
|
||||
end
|
||||
|
||||
scenario "The show-scientific-name page works" do
|
||||
it "The show-scientific-name page works" do
|
||||
visit scientific_name_path(zea_mays)
|
||||
expect(page.status_code).to equal 200
|
||||
expect(page).to have_link zea_mays.crop.name,
|
||||
@@ -74,7 +74,7 @@ feature "Scientific names", js: true do
|
||||
let(:pending_crop) { create :crop_request }
|
||||
let(:pending_sci_name) { create :scientific_name, crop: pending_crop }
|
||||
|
||||
scenario "Displays crop pending message" do
|
||||
it "Displays crop pending message" do
|
||||
visit scientific_name_path(pending_sci_name)
|
||||
expect(page).to have_content "This crop is currently pending approval"
|
||||
end
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
require 'rails_helper'
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Seeds", :js, :elasticsearch do
|
||||
describe "Seeds", :js, :elasticsearch do
|
||||
let(:member) { create :member }
|
||||
let!(:maize) { create :maize }
|
||||
|
||||
background do
|
||||
before do
|
||||
login_as member
|
||||
visit new_seed_path
|
||||
sync_elasticsearch [maize]
|
||||
end
|
||||
|
||||
it_behaves_like "crop suggest", "seed", "crop"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "seeds", js: true do
|
||||
describe "seeds", js: true do
|
||||
let(:member) { create :member }
|
||||
|
||||
context "signed in user" do
|
||||
let(:crop) { create :crop }
|
||||
|
||||
background { login_as member }
|
||||
before { login_as member }
|
||||
|
||||
describe "button on index to edit seed" do
|
||||
let!(:seed) { create :seed, owner: member }
|
||||
@@ -41,7 +41,7 @@ feature "seeds", js: true do
|
||||
|
||||
# actually adding seeds is in spec/features/seeds_new_spec.rb
|
||||
|
||||
scenario "edit seeds" do
|
||||
it "edit seeds" do
|
||||
seed = create :seed, owner: member
|
||||
visit seed_path(seed)
|
||||
click_link 'Edit'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
require 'custom_matchers'
|
||||
|
||||
feature "Seeds", :js do
|
||||
describe "Seeds", :js do
|
||||
subject do
|
||||
login_as member
|
||||
visit seed_path(seed)
|
||||
@@ -31,16 +31,16 @@ feature "Seeds", :js do
|
||||
let!(:photos) { FactoryBot.create_list :photo, 50 }
|
||||
|
||||
it "shows newest photo" do
|
||||
is_expected.to have_xpath("//img[contains(@src,'#{photos.last.thumbnail_url}')]")
|
||||
expect(subject).to have_xpath("//img[contains(@src,'#{photos.last.thumbnail_url}')]")
|
||||
end
|
||||
it "links to newest photo" do
|
||||
is_expected.to have_xpath("//a[contains(@href,'#{photo_path(photos.last)}')]")
|
||||
expect(subject).to have_xpath("//a[contains(@href,'#{photo_path(photos.last)}')]")
|
||||
end
|
||||
it "does not show oldest photo" do
|
||||
is_expected.not_to have_xpath("//img[contains(@src,'#{photos.first.thumbnail_url}')]")
|
||||
expect(subject).not_to have_xpath("//img[contains(@src,'#{photos.first.thumbnail_url}')]")
|
||||
end
|
||||
it "does not link to oldest photo" do
|
||||
is_expected.not_to have_xpath("//a[contains(@href,'#{photo_path(photos.first)}')]")
|
||||
expect(subject).not_to have_xpath("//a[contains(@href,'#{photo_path(photos.first)}')]")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@ shared_examples "append date" do
|
||||
let(:this_month) { Time.zone.today.strftime("%B") }
|
||||
let(:this_year) { Time.zone.today.strftime("%Y") }
|
||||
|
||||
background { visit path }
|
||||
before { visit path }
|
||||
|
||||
scenario "Selecting a date with datepicker" do
|
||||
click_link link_text
|
||||
|
||||
@@ -6,8 +6,6 @@ shared_examples "crop suggest" do |resource|
|
||||
let!(:tomato) { create :tomato }
|
||||
let!(:roma) { create :roma }
|
||||
|
||||
background { sync_elasticsearch [pea, pear, maize, tomato] }
|
||||
|
||||
scenario "placeholder text in crop auto suggest field" do
|
||||
expect(page).to have_selector("input[placeholder='e.g. lettuce']")
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "signin", js: true do
|
||||
describe "signin", js: true do
|
||||
let(:member) { FactoryBot.create :member }
|
||||
let(:recipient) { FactoryBot.create :member }
|
||||
let(:wrangler) { FactoryBot.create :crop_wrangling_member }
|
||||
@@ -12,34 +12,34 @@ feature "signin", js: true do
|
||||
click_button 'Sign in'
|
||||
end
|
||||
|
||||
scenario "via email address" do
|
||||
it "via email address" do
|
||||
visit crops_path # some random page
|
||||
click_link 'Sign in'
|
||||
login
|
||||
expect(page).to have_content("Sign out")
|
||||
end
|
||||
|
||||
scenario "redirect to previous page after signin" do
|
||||
it "redirect to previous page after signin" do
|
||||
visit crops_path # some random page
|
||||
click_link 'Sign in'
|
||||
login
|
||||
expect(current_path).to eq crops_path
|
||||
end
|
||||
|
||||
scenario "don't redirect to devise pages after signin" do
|
||||
it "don't redirect to devise pages after signin" do
|
||||
visit new_member_registration_path # devise signup page
|
||||
click_link 'Sign in'
|
||||
login
|
||||
expect(current_path).to eq root_path
|
||||
end
|
||||
|
||||
scenario "redirect to signin page for if not authenticated to view notification" do
|
||||
it "redirect to signin page for if not authenticated to view notification" do
|
||||
visit notification_path(notification)
|
||||
expect(current_path).to eq new_member_session_path
|
||||
end
|
||||
|
||||
shared_examples "redirects to what you were trying to do" do
|
||||
scenario do
|
||||
it do
|
||||
visit "/#{model_name}/new"
|
||||
expect(current_path).to eq new_member_session_path
|
||||
login
|
||||
@@ -55,14 +55,14 @@ feature "signin", js: true do
|
||||
end
|
||||
end
|
||||
|
||||
scenario "after signin, redirect to new notifications page" do
|
||||
it "after signin, redirect to new notifications page" do
|
||||
visit new_notification_path(recipient_id: recipient.id)
|
||||
expect(current_path).to eq new_member_session_path
|
||||
login
|
||||
expect(current_path).to eq new_notification_path
|
||||
end
|
||||
|
||||
scenario "after crop wrangler signs in and crops await wrangling, show alert" do
|
||||
it "after crop wrangler signs in and crops await wrangling, show alert" do
|
||||
create :crop_request
|
||||
visit crops_path # some random page
|
||||
click_link 'Sign in'
|
||||
@@ -73,7 +73,7 @@ feature "signin", js: true do
|
||||
end
|
||||
|
||||
context "with facebook" do
|
||||
scenario "sign in" do
|
||||
it "sign in" do
|
||||
# Ordinarily done by database_cleaner
|
||||
Member.where(login_name: 'tdawg').delete_all
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "signout" do
|
||||
describe "signout" do
|
||||
let(:member) { create :member }
|
||||
|
||||
let(:path) {}
|
||||
|
||||
scenario "redirect to previous page after signout" do
|
||||
it "redirect to previous page after signout" do
|
||||
visit crops_path # some random page
|
||||
click_link 'Sign in'
|
||||
fill_in 'Login', with: member.login_name
|
||||
@@ -16,7 +16,7 @@ feature "signout" do
|
||||
end
|
||||
|
||||
shared_examples "sign-in redirects" do |path|
|
||||
scenario "after signout, redirect to signin page if page needs authentication" do
|
||||
it "after signout, redirect to signin page if page needs authentication" do
|
||||
visit path
|
||||
expect(current_path).to eq new_member_session_path
|
||||
expect(page).to have_http_status(200)
|
||||
@@ -39,7 +39,7 @@ feature "signout" do
|
||||
include_examples "sign-in redirects", "/seeds/new"
|
||||
end
|
||||
|
||||
scenario 'photos' do
|
||||
it 'photos' do
|
||||
garden = FactoryBot.create :garden, owner: member
|
||||
visit "/photos/new?id=#{garden.id}&type=garden"
|
||||
expect(current_path).to eq new_member_session_path
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "signup", js: true do
|
||||
scenario "sign up for new account from top menubar" do
|
||||
describe "signup", js: true do
|
||||
it "sign up for new account from top menubar" do
|
||||
visit crops_path # something other than front page, which has multiple signup links
|
||||
click_link 'Sign up'
|
||||
fill_in 'Login name', with: 'person123'
|
||||
@@ -13,7 +13,7 @@ feature "signup", js: true do
|
||||
expect(current_path).to eq root_path
|
||||
end
|
||||
|
||||
scenario "sign up for new account with existing username" do
|
||||
it "sign up for new account with existing username" do
|
||||
visit crops_path # something other than front page, which has multiple signup links
|
||||
click_link 'Sign up'
|
||||
fill_in 'Login name', with: 'person123'
|
||||
@@ -32,7 +32,7 @@ feature "signup", js: true do
|
||||
click_button 'Sign up'
|
||||
end
|
||||
|
||||
scenario "sign up for new account without accepting TOS" do
|
||||
it "sign up for new account without accepting TOS" do
|
||||
visit root_path
|
||||
first('.signup a').click # click the 'Sign up' button in the middle of the page
|
||||
fill_in 'Login name', with: 'person123'
|
||||
@@ -45,7 +45,7 @@ feature "signup", js: true do
|
||||
end
|
||||
|
||||
context "with facebook" do
|
||||
scenario "sign up" do
|
||||
it "sign up" do
|
||||
# Ordinarily done by database_cleaner
|
||||
Member.where(login_name: 'tdawg').delete_all
|
||||
Member.where(email: 'tdawg@hotmail.com').delete_all
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
require 'rails_helper'
|
||||
require 'capybara/email/rspec'
|
||||
|
||||
feature "unsubscribe" do
|
||||
describe "unsubscribe" do
|
||||
let(:member) { create :member }
|
||||
let(:notification) { create :notification }
|
||||
|
||||
background do
|
||||
before do
|
||||
clear_emails
|
||||
end
|
||||
|
||||
scenario "from planting reminder mailing list" do
|
||||
it "from planting reminder mailing list" do
|
||||
# verifying the initial subscription status of the member
|
||||
expect(member.send_planting_reminder).to eq(true)
|
||||
expect(member.send_notification_email).to eq(true)
|
||||
@@ -26,7 +26,7 @@ feature "unsubscribe" do
|
||||
expect(updated_member.send_notification_email).to eq(true)
|
||||
end
|
||||
|
||||
scenario "from inbox notification mailing list" do
|
||||
it "from inbox notification mailing list" do
|
||||
# verifying the initial subscription status of the member
|
||||
expect(member.send_planting_reminder).to eq(true)
|
||||
expect(member.send_notification_email).to eq(true)
|
||||
@@ -44,7 +44,7 @@ feature "unsubscribe" do
|
||||
expect(updated_member.send_notification_email).to eq(false)
|
||||
end
|
||||
|
||||
scenario "visit unsubscribe page with a non-encrypted parameter" do
|
||||
it "visit unsubscribe page with a non-encrypted parameter" do
|
||||
# verifying the initial subscription status of the member
|
||||
expect(member.send_planting_reminder).to eq(true)
|
||||
expect(member.send_notification_email).to eq(true)
|
||||
|
||||
@@ -22,7 +22,7 @@ describe PhotosHelper do
|
||||
before { planting.photos << planting_photo }
|
||||
|
||||
it "uses planting photos" do
|
||||
is_expected.to eq planting_photo.thumbnail_url
|
||||
expect(subject).to eq planting_photo.thumbnail_url
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ describe PhotosHelper do
|
||||
before { harvest.photos << harvest_photo }
|
||||
|
||||
it "uses harvest photos" do
|
||||
is_expected.to eq harvest_photo.thumbnail_url
|
||||
expect(subject).to eq harvest_photo.thumbnail_url
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,7 +38,7 @@ describe PhotosHelper do
|
||||
before { seed.photos << seed_photo }
|
||||
|
||||
it "uses seed photos" do
|
||||
is_expected.to eq seed_photo.thumbnail_url
|
||||
expect(subject).to eq seed_photo.thumbnail_url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,6 @@ describe Crop do
|
||||
let(:pp2) { FactoryBot.create(:plant_part) }
|
||||
let(:pp1) { FactoryBot.create(:plant_part) }
|
||||
let(:maize) { FactoryBot.create(:maize) }
|
||||
|
||||
context 'all fields present' do
|
||||
let(:crop) { FactoryBot.create(:tomato) }
|
||||
|
||||
@@ -143,57 +142,66 @@ describe Crop do
|
||||
end
|
||||
|
||||
context 'photos' do
|
||||
before do
|
||||
@crop = FactoryBot.create(:tomato)
|
||||
shared_examples 'has default photo' do
|
||||
it { expect(Crop.has_photos).to include(crop) }
|
||||
end
|
||||
let!(:crop) { FactoryBot.create :tomato }
|
||||
let(:member) { FactoryBot.create :member }
|
||||
|
||||
context 'with a planting photo' do
|
||||
before do
|
||||
@planting = FactoryBot.create(:planting, crop: @crop)
|
||||
@photo = FactoryBot.create(:photo, owner: @planting.owner)
|
||||
@planting.photos << @photo
|
||||
end
|
||||
let!(:photo) { FactoryBot.create(:photo, owner: planting.owner) }
|
||||
let!(:planting) { FactoryBot.create(:planting, crop: crop) }
|
||||
|
||||
it 'has a default photo' do
|
||||
@crop.default_photo.should be_an_instance_of Photo
|
||||
expect(@crop.default_photo.id).to eq @photo.id
|
||||
end
|
||||
before { planting.photos << photo }
|
||||
|
||||
it 'is found in has_photos scope' do
|
||||
Crop.has_photos.should include(@crop)
|
||||
end
|
||||
it { expect(crop.default_photo).to eq photo }
|
||||
include_examples 'has default photo'
|
||||
end
|
||||
|
||||
context 'with a harvest photo' do
|
||||
before do
|
||||
@harvest = FactoryBot.create(:harvest, crop: @crop)
|
||||
@photo = FactoryBot.create(:photo, owner: @harvest.owner)
|
||||
@harvest.photos << @photo
|
||||
end
|
||||
let!(:harvest) { FactoryBot.create(:harvest, crop: crop) }
|
||||
let!(:photo) { FactoryBot.create(:photo, owner: harvest.owner) }
|
||||
|
||||
it 'has a default photo' do
|
||||
@crop.default_photo.should be_an_instance_of Photo
|
||||
expect(@crop.default_photo.id).to eq @photo.id
|
||||
end
|
||||
before { harvest.photos << photo }
|
||||
|
||||
it { expect(crop.default_photo).to eq photo }
|
||||
include_examples 'has default photo'
|
||||
|
||||
context 'and planting photo' do
|
||||
before do
|
||||
@planting = FactoryBot.create(:planting, crop: @crop)
|
||||
@planting_photo = FactoryBot.create(:photo, owner: @planting.owner)
|
||||
@planting.photos << @planting_photo
|
||||
end
|
||||
let(:planting) { FactoryBot.create(:planting, crop: crop) }
|
||||
let!(:planting_photo) { FactoryBot.create(:photo, owner: planting.owner) }
|
||||
|
||||
before { planting.photos << planting_photo }
|
||||
|
||||
it 'prefers the planting photo' do
|
||||
expect(@crop.default_photo.id).to eq @planting_photo.id
|
||||
expect(crop.default_photo.id).to eq planting_photo.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no plantings or harvests' do
|
||||
it 'has no default photo' do
|
||||
expect(@crop.default_photo).to eq nil
|
||||
expect(crop.default_photo).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'finding all photos' do
|
||||
let(:planting) { FactoryBot.create :planting, crop: crop }
|
||||
let(:harvest) { FactoryBot.create :harvest, crop: crop }
|
||||
let(:seed) { FactoryBot.create :seed, crop: crop }
|
||||
|
||||
before do
|
||||
# Add photos to all
|
||||
planting.photos << FactoryBot.create(:photo, owner: planting.owner)
|
||||
harvest.photos << FactoryBot.create(:photo, owner: harvest.owner)
|
||||
seed.photos << FactoryBot.create(:photo, owner: seed.owner)
|
||||
end
|
||||
|
||||
it { expect(crop.photos.size).to eq 3 }
|
||||
it { expect(crop.planting_photos.size).to eq 1 }
|
||||
it { expect(crop.harvest_photos.size).to eq 1 }
|
||||
it { expect(crop.seed_photos.size).to eq 1 }
|
||||
end
|
||||
end
|
||||
|
||||
context 'sunniness' do
|
||||
@@ -356,35 +364,6 @@ describe Crop do
|
||||
expect(@maize.plant_parts).to eq [@pp1]
|
||||
end
|
||||
|
||||
context "search", :elasticsearch do
|
||||
let(:mushroom) { FactoryBot.create(:crop, name: 'mushroom') }
|
||||
|
||||
before { sync_elasticsearch([mushroom]) }
|
||||
|
||||
it "finds exact matches" do
|
||||
expect(Crop.search('mushroom')).to eq [mushroom]
|
||||
end
|
||||
it "finds approximate matches" do
|
||||
expect(Crop.search('mush')).to eq [mushroom]
|
||||
end
|
||||
it "doesn't find non-matches" do
|
||||
Crop.search('mush').should_not include @crop
|
||||
end
|
||||
it "searches case insensitively" do
|
||||
Crop.search('mUsH').should include mushroom
|
||||
end
|
||||
it "doesn't find 'rejected' crop" do
|
||||
@rejected_crop = FactoryBot.create(:rejected_crop, name: 'tomato')
|
||||
sync_elasticsearch([@rejected_crop])
|
||||
Crop.search('tomato').should_not include @rejected_crop
|
||||
end
|
||||
it "doesn't find 'pending' crop" do
|
||||
@crop_request = FactoryBot.create(:crop_request, name: 'tomato')
|
||||
sync_elasticsearch([@crop_request])
|
||||
Crop.search('tomato').should_not include @crop_request
|
||||
end
|
||||
end
|
||||
|
||||
context "csv loading" do
|
||||
before do
|
||||
# don't use 'let' for this -- we need to actually create it,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Garden do
|
||||
let(:owner) { FactoryBot.create(:member, login_name: 'hatupatu') }
|
||||
let(:garden) { FactoryBot.create(:garden, owner: owner, name: 'Springfield Community Garden') }
|
||||
let(:owner) { FactoryBot.create(:member, login_name: 'hatupatu') }
|
||||
let(:garden) { FactoryBot.create(:garden, owner: owner, name: 'Springfield Community Garden') }
|
||||
let(:garden_type) { FactoryBot.create(:garden_type, name: "aquaponic") }
|
||||
|
||||
it "has a slug" do
|
||||
garden.slug.should match(/hatupatu-springfield-community-garden/)
|
||||
|
||||
38
spec/models/garden_type.rb
Normal file
38
spec/models/garden_type.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe GardenType do
|
||||
let(:garden) { FactoryBot.create(:garden, 'Free Carrots') }
|
||||
|
||||
describe "should have a name" do
|
||||
let(:garden_type) { FactoryBot.build(:garden_type, name: "organic") }
|
||||
|
||||
it { expect(garden_type).to be_valid }
|
||||
end
|
||||
|
||||
describe "doesn't allow a nil name" do
|
||||
let(:garden_type) { FactoryBot.build(:garden_type, name: nil) }
|
||||
|
||||
it { expect(garden_type).not_to be_valid }
|
||||
end
|
||||
|
||||
describe "doesn't allow a blank name" do
|
||||
let(:garden_type) { FactoryBot.build(:garden_type, name: "") }
|
||||
|
||||
it { expect(garden_type).not_to be_valid }
|
||||
end
|
||||
|
||||
describe "doesn't allow a name with only spaces" do
|
||||
let(:garden_type) { FactoryBot.build(:garden_type, name: " ") }
|
||||
|
||||
it { expect(garden_type).not_to be_valid }
|
||||
end
|
||||
|
||||
describe "does not delete gardens when deleted" do
|
||||
before { FactoryBot.create :garden, garden_type: garden_type }
|
||||
|
||||
let(:garden_type) { FactoryBot.create(:garden_type, name: "Massive Flower Pot") }
|
||||
|
||||
it { expect(garden_type.gardens.size).to eq(1) }
|
||||
it { expect { garden_type.destroy }.not_to change(Garden, :count) }
|
||||
end
|
||||
end
|
||||
@@ -38,12 +38,12 @@ RSpec.describe 'Gardens', type: :request do
|
||||
"related" => "#{resource_url}/photos" } }
|
||||
end
|
||||
|
||||
scenario '#index' do
|
||||
it '#index' do
|
||||
get '/api/v1/gardens', params: {}, headers: headers
|
||||
expect(subject['data']).to include(garden_encoded_as_json_api)
|
||||
end
|
||||
|
||||
scenario '#show' do
|
||||
it '#show' do
|
||||
get "/api/v1/gardens/#{garden.id}", params: {}, headers: headers
|
||||
expect(subject['data']).to include(garden_encoded_as_json_api)
|
||||
end
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user