diff --git a/app/views/controllers/sequences/new.html.erb b/app/views/controllers/sequences/new.html.erb
index e141e41575..d4a3159619 100644
--- a/app/views/controllers/sequences/new.html.erb
+++ b/app/views/controllers/sequences/new.html.erb
@@ -8,8 +8,7 @@ add_tab_set(sequence_form_tabs(obj: @observation))
<%= render(partial: "sequences/observation_title",
locals: { observation: @observation }) %>
- <%= render(partial: "sequences/form",
- locals: { action: :create, local: true }) %>
+ <%= render(partial: "sequences/form", locals: { local: true }) %>
diff --git a/app/views/controllers/shared/_notes_fields.html.erb b/app/views/controllers/shared/_notes_fields.html.erb
new file mode 100644
index 0000000000..baeeb2d1df
--- /dev/null
+++ b/app/views/controllers/shared/_notes_fields.html.erb
@@ -0,0 +1,48 @@
+<%# Notes section of any form %>
+
+<%
+# Users may have custom notes "parts". This prints a single large textarea and
+# textile help block if there's only one notes part. Otherwise, it prints
+# smaller textareas and a general textile help link.
+
+help = general_help = other = nil
+if fields == [Observation.other_notes_part]
+ help = [tag.p(:form_observations_notes_help.t),
+ tag.p(:shared_textile_help.l)].safe_join
+ other = true
+ rows = 10
+else
+ general_help = tag.p do
+ [
+ tag.strong("#{:NOTES.t}:", class: "mr-3"),
+ collapse_info_trigger("notes_help"),
+ collapse_help_block(nil, :shared_textile_help.l, id: "notes_help")
+ ].safe_join
+ end
+ rows = 1
+end
+indent = form.object_name == "observation" ? "" : "ml-5"
+%>
+
+<%= tag.div(id: "#{form.object_name}_notes") do %>
+ <%= general_help %>
+ <%= tag.div(class: indent) do %>
+ <%= form.fields_for(:notes) do |f_n| %>
+ <% fields.each do |part| %>
+ <% if form.object_name == "observation"
+ field = @observation.notes_normalized_key(part)
+ value = @observation.notes_part_value(part)
+ label = other ? "#{:NOTES.t}:" : "#{part.to_s.humanize}:"
+ else
+ field = part.name
+ value = part.value
+ label = part.label + ":"
+ end %>
+ <%= text_area_with_label(
+ form: f_n, rows:, help:, field:, value:, label:
+ ) %>
+ <% end %>
+ <% end %>
+ <% end %>
+<% end %>
+
diff --git a/app/views/controllers/shared/_notes_form.html.erb b/app/views/controllers/shared/_notes_form.html.erb
deleted file mode 100644
index 1247302353..0000000000
--- a/app/views/controllers/shared/_notes_form.html.erb
+++ /dev/null
@@ -1,21 +0,0 @@
-<%# Notes section of a form %>
-
-
-
-
-
- <%= :NOTES.t %>:
-
-
- <% fields.each do |field| %>
- <%= form.fields_for(:notes) do |f_n| %>
- <%= text_area_with_label(
- form: f_n, rows: 1, label: field.label + ": ",
- field: field.name,
- value: field.value) %>
- <% end # form.fields_for(:notes) %>
- <% end # each do field %>
-
-
-
-
diff --git a/app/views/controllers/shared/_textilize_help.erb b/app/views/controllers/shared/_textilize_help.erb
deleted file mode 100644
index 2903da47c1..0000000000
--- a/app/views/controllers/shared/_textilize_help.erb
+++ /dev/null
@@ -1,6 +0,0 @@
-<%= tag.div(id: "textilize_note", class: "help-block") do
- link = link_to(:shared_textile_link.t, info_textile_sandbox_path,
- target: "_new")
- str = :shared_textile_help.l % link
- str.html_safe
-end %>
diff --git a/app/views/controllers/species_lists/_form.html.erb b/app/views/controllers/species_lists/_form.html.erb
index b86b03f4c8..dcc5211a27 100644
--- a/app/views/controllers/species_lists/_form.html.erb
+++ b/app/views/controllers/species_lists/_form.html.erb
@@ -36,7 +36,7 @@
<%= text_area_with_label(form: f, field: :notes, rows: 12,
label: "#{:form_species_lists_list_notes.l}:",
- append: render(partial: "shared/textilize_help")) %>
+ help: :shared_textile_help.l) %>
<%= date_select_with_label(form: f, field: :when,
inline: true, label: "#{:WHEN.l}:") %>
diff --git a/config/locales/en.txt b/config/locales/en.txt
index 52f57df0bc..6fd52d3dd6 100644
--- a/config/locales/en.txt
+++ b/config/locales/en.txt
@@ -270,6 +270,8 @@
field_slip: field slip
FIELD_SLIPS: Field Slips
field_slips: field slips
+ IDENTIFICATION: Identification
+ identification: identification
IMAGE: Image
image: image
IMAGES: Images
@@ -305,6 +307,10 @@
lichen: lichen
LINKS: Links
links: links
+ LOCALITY: Locality
+ locality: locality
+ LOCALITIES: Localities
+ localities: localities
LOCATION: Location
location: location
LOCATIONS: Locations
@@ -652,8 +658,8 @@
prev: prev
NEXT: Next
next: next
- BACK: Prev
- back: prev
+ BACK: Back
+ back: back
FORWARD: Next
forward: next
EAST: East
@@ -758,6 +764,11 @@
# upload an image or checklist
UPLOAD: Upload
upload: upload
+ USE: Use
+ use: use
+ RECORD: Record
+ IDENTIFY: Identify
+ ADD_TO: Add to
# Common adjectives.
ANONYMOUS: Anonymous
@@ -1425,7 +1436,8 @@
ask_webmaster_title: Email Question or Comment
ask_webmaster_your_email: Your email address
ask_webmaster_question: Question or Comment
- ask_webmaster_note: "Thanks for your interest in the Mushroom Observer website. This website was first launched in mid-2006. The site is owned by the non-profit \"Mushroom Observer, Inc.\":/support/governance and administered by a group of volunteer developers and maintainers. We welcome any questions you might have about using the site or comments on how the site might be improved. You can vote and comment on all the various suggestions for future development there. However, they are only rough guides, subject to bugs or others issues that may come up and, of course, the availability of our own time to work on the site.\n\nThe Mushroom Observer Team"
+ ask_webmaster_note: "Thanks for your interest in the Mushroom Observer website. This website was first launched in mid-2006. The site is owned by the non-profit \"Mushroom Observer, Inc.\":/support/governance and administered by a group of volunteer developers and maintainers. We welcome any questions about using the site or comments on how the site might be improved. \n\n [:ask_webmaster_bug] \n\nThe Mushroom Observer Team"
+ ask_webmaster_bug: "**Bug Reports**\n If you are reporting a bug, please let us know what hardware, operating system, and browser you use, and exactly what you were doing. (Which page(s) you were viewing, what you typed, which lin(s) you clicked.)"
# comments/new
comment_add_title: Add Comment to [name]
@@ -1580,7 +1592,7 @@
form_glossary_description_help: "A concise definition matching the part of speech of the Term, without repeating another Term's definition. (Instead link to the other Term.) Details:"
# location/_form_location
- form_locations_hidden: Hide location
+ form_locations_hidden: Hide observations at this location
form_locations_hidden_doc: Hidden locations will hide the GPS coordinates of associated observations. They also cannot be more precise than 0.1 degrees. This value cannot be changed when there are any associated observations.
form_locations_locked: Lock this location so users cannot change the name or coordinates?
form_locations_gen_desc: General Description
@@ -1589,9 +1601,9 @@
form_locations_notes: "[:Notes]"
form_locations_refs: "[:form_names_refs]"
form_locations_refs_help: "[:form_names_refs_help]"
- form_locations_help: "
Help"
- form_locations_find_on_map: Find on Map >
- form_locations_get_elevation: Get Elevation
+ form_locations_help: "Here you can define the place where you observed mushrooms, if a matching place doesn't exist in Mushroom Observer already. Please try to define locations that will be reusable by yourself or others. If you have an idea of the location's name, you can start typing and Google will return its best guess of the place you typed, and draw a box of the approximate boundaries on the map. At this point, you can manually edit both the boundaries and the name of the place.
More about Locations on MO."
+ form_locations_find_on_map: Find on Map
+ form_locations_get_elevation: Get Elevations
form_locations_lat_long_help: All values should be in decimal degrees.
form_locations_license_help: Select "license":/info/how_to_use#license you want to give for the above text.
form_locations_gen_desc_help: Describe the geographical location of this location.
@@ -1659,20 +1671,23 @@
form_observations_specimen_available: Specimen Available
form_observations_is_collection_location: Is this location where it was collected?
form_observations_gps_hidden: Hide exact coordinates?
- form_observations_upload_images: Upload Images
- form_observations_uploading_images: Uploading Images
- form_observations_upload_another: Upload Another...
- form_observations_creating_observation: Creating Observation
- form_observations_edit_image: Edit Image
- form_observations_remove_image: Remove Image
+ form_observations_upload_images: "Upload [:images]"
+ form_observations_uploading_images: "Uploading [:images]"
+ form_observations_upload_another: Upload another...
+ form_observations_creating_observation: "Creating [:observation]"
+ form_observations_edit_image: "[:EDIT] [:image]"
+ form_observations_remove_image: "[:REMOVE] [:image]"
form_observations_lat_long_help: "Optional GPS location within **[:WHERE]**. Latitude must be -90.0 to 90.0; longitude must be -180.0 to 180.0. Elevation will be converted to meters. If you choose to provide this data please make it as accurate as possible. Examples: \"34.1164\" = \"34°6'59"N\", \"-118.1459\" = \"118 8.754 W\", \"239 m\" = \"784 ft.\""
form_observations_log_change: Log Change
form_observations_is_collection_location_help: Check when the location is where the mushroom was growing. Uncheck when it is only where the mushroom was seen (e.g., mushroom fairs, grocery, foray id table where collection location is unknown etc.).
form_observations_open_map: "[:SHOW] [:map]"
form_observations_hide_map: "[:HIDE] [:map]"
- form_observations_clear_map: Clear location
- form_observations_click_point: Click a point on the map to set a location
- form_observations_locality_contains: Localities containing this point
+ form_observations_clear_map: "[:CLEAR] [:location]"
+ form_observations_click_point: "Tip: select a locality to center the map, then click a point on the map to set a location."
+ form_observations_locality_contains: "[:LOCALITIES] containing this point"
+ form_observations_create_locality: "[:CREATE] [:locality]"
+ form_observations_use_locality: "[:USE] this [:locality]"
+ form_observations_edit_locality: "[:EDIT] this [:locality]"
form_observations_notes_help: Please include any additional information you can think of about this observation that isn't clear from the photographs, e.g., habitat, substrate or nearby trees; distinctive texture, scent, taste, staining or bruising; results of chemical or microscopic analyses, etc.
form_observations_remove_image_confirm: Are you sure you want to remove this image? This will only remove this image from this observation. If it is attached to other observations, it will remain attached to them.
form_observations_specimen_available_help: Check when there is a preserved specimen available for further study.
@@ -3597,7 +3612,7 @@
# Location help
location_help_title: Locations in Mushroom Observer
- location_help_intro: "The Mushroom Observer provides two ways to represent the geographic location of an observation. The simplest are latitude and longitude positions associated with the observation. Please keep these accurate to within at least 300 meters (or about 1000 feet). However, the more widely used method is a simple phrase describing the location. For example, \"Beebe Woods, Falmouth, Massachusetts, USA\". The goal of these location names is to provide a consistent, reusable way of talking about where an observation was made without necessarily revealing a precise \"spot\". If you are comfortable provide more precise lat/longs for an observation, the location names are still useful for searches so you are encouraged to provide them as well. The location names should, by default, go from the smallest contained area to the country name. If you prefer to describe your locations as going from the largest (country) down to the smallest contained area, you can change your preference from the default, \"Postal\", to \"Scientific\" on your preference page. There are cases such as \"Great Smoky Mountains National Park, Blount Co., Tennessee, USA\", where the area you are describing overlaps a number of counties, states or even countries. In these cases, the country and other official political boundaries should come at the end as shown in the example.\n\nOriginally, the Mushroom Observer was very loose about these location names, hoping that the users would create a reasonably consistent set of rules and correct each other. After about four years and thousands of location names, we found that there were rules emerging, but they were not applied at all consistently and people were not tending to directly correct each other. Consequently, we have tried to codify these rules and when reasonable to provide warnings if you attempt to create a new location that violates these rules. It is not always possible to correct identify \"bad\" locations, so if you get some warnings, but after reviewing the location decide it should be \"good\", then simply resubmitting the form will force the name into the database. However, all new location names will get reviewed regularly and may get changed to better fit the consensus rules. Below are some examples of \"bad\" and \"good\" location names followed by a more detailed explanation of the current rules. Each example is labeled with the following section that explains the example in more detail. These rules are by no means set it stone and we encourage the discussion and revision of them."
+ location_help_intro: "The Mushroom Observer provides two ways to represent the geographic location of an observation. The simplest are latitude and longitude positions associated with the observation. Please keep these accurate to within at least 300 meters (or about 1000 feet). However, the more widely used method is a simple phrase describing the location. For example, \"Beebe Woods, Falmouth, Massachusetts, USA\". The goal of these location names is to provide a consistent, reusable way of talking about where an observation was made without necessarily revealing a precise \"spot\". If you are comfortable providing more precise lat/longs for an observation, the location names are still useful for searches so you are encouraged to provide them as well. The location names should, by default, go from the smallest contained area to the country name. If you prefer to describe your locations as going from the largest (country) down to the smallest contained area, you can change your preference from the default, \"Postal\", to \"Scientific\" on your preference page. There are cases such as \"Great Smoky Mountains National Park, Blount Co., Tennessee, USA\", where the area you are describing overlaps a number of counties, states or even countries. In these cases, the country and other official political boundaries should come at the end as shown in the example.\n\nOriginally, the Mushroom Observer was very loose about these location names, hoping that the users would create a reasonably consistent set of rules and correct each other. After about four years and thousands of location names, we found that there were rules emerging, but they were not applied at all consistently and people were not tending to directly correct each other. Consequently, we have tried to codify these rules and when reasonable to provide warnings if you attempt to create a new location that violates these rules. It is not always possible to correct identify \"bad\" locations, so if you get some warnings, but after reviewing the location decide it should be \"good\", then simply resubmitting the form will force the name into the database. However, all new location names will get reviewed regularly and may get changed to better fit the consensus rules. Below are some examples of \"bad\" and \"good\" location names followed by a more detailed explanation of the current rules. Each example is labeled with the following section that explains the example in more detail. These rules are by no means set it stone and we encourage the discussion and revision of them."
location_help_example_help: These are cases that are not detected automatically, so no warning would be given.
location_help_example_title: Some examples
location_help_bad: Bad
diff --git a/script/deploy.sh b/script/deploy.sh
index dbacb67893..a9c71f1c42 100755
--- a/script/deploy.sh
+++ b/script/deploy.sh
@@ -42,7 +42,7 @@ if [ $? -ne 0 ]; then
exit 1
fi
-if [ $STASH_RESULT -ne 'No local changes to save' ]; then
+if [ $STASH_RESULT != 'No local changes to save' ]; then
echo Reapply local changes... && git stash pop
if [ $? -ne 0 ]; then
echo Applying the stashed changes failed.
diff --git a/test/controllers/locations_controller_test.rb b/test/controllers/locations_controller_test.rb
index f383c0e126..0b96117cdf 100644
--- a/test/controllers/locations_controller_test.rb
+++ b/test/controllers/locations_controller_test.rb
@@ -81,7 +81,6 @@ def location_error(page, params)
assert_template("edit")
end
assert_template("locations/_form")
- assert_template("shared/_textilize_help")
assert_equal(loc_count, Location.count)
assert_equal(past_loc_count, Location::Version.count)
assert_equal(desc_count, LocationDescription.count)
diff --git a/test/controllers/names/descriptions_controller_test.rb b/test/controllers/names/descriptions_controller_test.rb
index fa6f29f574..fdcedd21a3 100644
--- a/test/controllers/names/descriptions_controller_test.rb
+++ b/test/controllers/names/descriptions_controller_test.rb
@@ -14,7 +14,6 @@ def empty_notes
CREATE_NAME_DESCRIPTION_PARTIALS = %w[
_fields_for_description
- _textilize_help
_form
].freeze
diff --git a/test/controllers/observations_controller/observations_controller_create_test.rb b/test/controllers/observations_controller/observations_controller_create_test.rb
index 58f24101d7..6e5c833091 100644
--- a/test/controllers/observations_controller/observations_controller_create_test.rb
+++ b/test/controllers/observations_controller/observations_controller_create_test.rb
@@ -36,26 +36,26 @@ def default_herbarium_record_fields
{ herbarium_name: "", accession_number: "" }
end
- def location_exists_or_place_name_blank(params)
- Location.find_by(name: params[:observation][:place_name]) ||
- Location.is_unknown?(params[:observation][:place_name]) ||
- params[:observation][:place_name].blank?
+ def location_exists_or_place_name_blank(params, user)
+ name = Location.user_format(user, params[:observation][:place_name])
+ Location.find_by(name:) || Location.is_unknown?(name) || name.blank?
end
# Test constructing observations in various ways (with minimal namings)
- def generic_construct_observation(params, o_num, g_num, n_num, user = rolf)
+ def generic_construct_observation(params, o_num, g_num, n_num, l_num,
+ user = rolf)
o_count = Observation.count
g_count = Naming.count
n_count = Name.count
+ l_count = Location.count
score = user.reload.contribution
params = modified_generic_params(params, user)
-
post_requires_login(:create, params)
begin
if o_num.zero?
assert_response(:success)
- elsif location_exists_or_place_name_blank(params)
+ elsif location_exists_or_place_name_blank(params, user)
# assert_redirected_to(action: :show)
assert_response(:redirect)
assert_match(%r{/test.host/\d+\Z}, @response.redirect_url)
@@ -73,7 +73,8 @@ def generic_construct_observation(params, o_num, g_num, n_num, user = rolf)
assert_equal(o_count + o_num, Observation.count, "Wrong Observation count")
assert_equal(g_count + g_num, Naming.count, "Wrong Naming count")
assert_equal(n_count + n_num, Name.count, "Wrong Name count")
- assert_equal(score + o_num + g_num * 2 + n_num * 10,
+ assert_equal(l_count + l_num, Location.count, "Wrong Location count")
+ assert_equal(score + o_num + g_num * 2 + n_num * 10 + l_num * 10,
user.reload.contribution,
"Wrong User score")
return unless o_num == 1
@@ -111,7 +112,7 @@ def test_create_log_updated_at
params = {
naming: { name: "", vote: { value: "" } },
user: rolf,
- where: locations.first.name
+ observation: { place_name: locations.first.name }
}
users(:rolf).login
@@ -123,7 +124,7 @@ def test_create_log_updated_at
def test_create_observation_without_scientific_name
params = { user: rolf,
- where: locations.first.name }
+ observation: { place_name: locations.first.name } }
fungi = names(:fungi)
post_requires_login(:create, params)
@@ -141,7 +142,7 @@ def test_create_observation_with_unrecognized_name
text_name = "Elfin saddle"
params = { naming: { name: text_name },
user: rolf,
- where: locations.first.name }
+ observation: { place_name: locations.first.name } }
post_requires_login(:create, params)
assert_select("div[id='name_messages']",
@@ -154,7 +155,7 @@ def test_construct_observation_approved_place_name
{ observation: { place_name: where },
naming: { name: "Coprinus comatus" },
approved_place_name: "" },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert_equal(where, obs.place_name)
@@ -166,7 +167,7 @@ def test_create_observation_with_field_slip
{ observation: { specimen: "1" },
field_code: field_slips(:field_slip_no_obs).code,
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -178,7 +179,7 @@ def test_create_observation_with_collection_number
{ observation: { specimen: "1" },
collection_number: { name: "Billy Bob", number: "17-034" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -190,7 +191,7 @@ def test_create_observation_with_used_collection_number
{ observation: { specimen: "1" },
collection_number: { name: "Rolf Singer", number: "1" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -203,7 +204,7 @@ def test_create_observation_with_specimen_and_collector_but_no_number
{ observation: { specimen: "1" },
collection_number: { name: "Rolf Singer", number: "" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -214,7 +215,7 @@ def test_create_observation_with_collection_number_but_no_specimen
generic_construct_observation(
{ collection_number: { name: "Rolf Singer", number: "3141" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert_not(obs.specimen)
@@ -226,7 +227,7 @@ def test_create_observation_with_collection_number_but_no_collector
{ observation: { specimen: "1" },
collection_number: { name: "", number: "27-18A.2" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -244,7 +245,7 @@ def test_create_observation_with_herbarium_record
accession_number: "1234"
},
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -259,7 +260,7 @@ def test_create_observation_with_herbarium_duplicate_label
accession_number: "1234"
},
naming: { name: "Cortinarius sp." } },
- 0, 0, 0
+ 0, 0, 0, 0
)
assert_input_value(:herbarium_record_herbarium_name,
"NY - The New York Botanical Garden")
@@ -275,7 +276,7 @@ def test_create_observation_with_herbarium_no_id
accession_number: ""
},
naming: { name: name } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert_true(obs.specimen)
@@ -289,7 +290,7 @@ def test_create_observation_with_herbarium_but_no_specimen
accession_number: "1234"
},
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert_not(obs.specimen)
@@ -302,7 +303,7 @@ def test_create_observation_with_new_nonpersonal_herbarium
herbarium_record: { herbarium_name: "A Brand New Herbarium",
accession_number: "" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -315,7 +316,7 @@ def test_create_observation_with_new_personal_herbarium
herbarium_record: { herbarium_name: katrina.personal_herbarium_name,
accession_number: "12345" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0, katrina
+ 1, 1, 0, 0, katrina
)
obs = assigns(:observation)
assert(obs.specimen)
@@ -332,7 +333,7 @@ def test_create_simple_observation_with_approved_unique_name
generic_construct_observation(
{ observation: { place_name: where, thumb_image_id: "0" },
naming: { name: "Coprinus comatus" } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
nam = assigns(:naming)
@@ -350,7 +351,7 @@ def test_create_simple_observation_of_unknown_taxon
where = "Unknown, Massachusetts, USA"
generic_construct_observation(
{ observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0
+ 1, 0, 0, 0
)
obs = assigns(:observation)
assert_equal(where, obs.where) # Make sure it's the right observation
@@ -359,7 +360,7 @@ def test_create_simple_observation_of_unknown_taxon
def test_create_observation_with_new_name
generic_construct_observation(
- { naming: { name: "New name" } }, 0, 0, 0
+ { naming: { name: "New name" } }, 0, 0, 0, 0
)
end
@@ -367,7 +368,7 @@ def test_create_observation_with_approved_new_name
# Test an observation creation with an approved new name
generic_construct_observation(
{ naming: { name: "Argus arg-arg" }, approved_name: "Argus arg-arg" },
- 1, 1, 2
+ 1, 1, 2, 0
)
end
@@ -375,7 +376,7 @@ def test_create_observation_with_approved_name_and_extra_space
generic_construct_observation(
{ naming: { name: "Another new-name " },
approved_name: "Another new-name " },
- 1, 1, 2
+ 1, 1, 2, 0
)
end
@@ -386,7 +387,7 @@ def test_create_observation_with_approved_section
generic_construct_observation(
{ naming: { name: "Macrocybe section Fakesection" },
approved_name: "Macrocybe section Fakesection" },
- 1, 1, 1
+ 1, 1, 1, 0
)
end
@@ -394,13 +395,14 @@ def test_create_observation_with_approved_junk_name
generic_construct_observation(
{ naming: { name: "This is a bunch of junk" },
approved_name: "This is a bunch of junk" },
- 0, 0, 0
+ 0, 0, 0, 0
)
end
def test_create_observation_with_multiple_name_matches
generic_construct_observation(
- { naming: { name: "Amanita baccata" } }, 0, 0, 0
+ { naming: { name: "Amanita baccata" } },
+ 0, 0, 0, 0
)
end
@@ -408,14 +410,14 @@ def test_create_observation_choosing_one_of_multiple_name_matches
generic_construct_observation(
{ naming: { name: "Amanita baccata" },
chosen_name: { name_id: names(:amanita_baccata_arora).id } },
- 1, 1, 0
+ 1, 1, 0, 0
)
end
def test_create_observation_choosing_deprecated_one_of_multiple_name_matches
generic_construct_observation(
{ naming: { name: names(:pluteus_petasatus_deprecated).text_name } },
- 1, 1, 0
+ 1, 1, 0, 0
)
nam = assigns(:naming)
assert_equal(names(:pluteus_petasatus_approved).id, nam.name_id)
@@ -423,7 +425,8 @@ def test_create_observation_choosing_deprecated_one_of_multiple_name_matches
def test_create_observation_with_deprecated_name
generic_construct_observation(
- { naming: { name: "Lactarius subalpinus" } }, 0, 0, 0
+ { naming: { name: "Lactarius subalpinus" } },
+ 0, 0, 0, 0
)
end
@@ -432,7 +435,7 @@ def test_create_observation_with_chosen_approved_synonym_of_deprecated_name
{ naming: { name: "Lactarius subalpinus" },
approved_name: "Lactarius subalpinus",
chosen_name: { name_id: names(:lactarius_alpinus).id } },
- 1, 1, 0
+ 1, 1, 0, 0
)
nam = assigns(:naming)
assert_equal(nam.name, names(:lactarius_alpinus))
@@ -443,7 +446,7 @@ def test_create_observation_with_approved_deprecated_name
{ naming: { name: "Lactarius subalpinus" },
approved_name: "Lactarius subalpinus",
chosen_name: {} },
- 1, 1, 0
+ 1, 1, 0, 0
)
nam = assigns(:naming)
assert_equal(nam.name, names(:lactarius_subalpinus))
@@ -455,7 +458,7 @@ def test_create_observation_with_approved_new_species
generic_construct_observation(
{ naming: { name: "Agaricus novus" },
approved_name: "Agaricus novus" },
- 1, 1, 2
+ 1, 1, 2, 0
)
name = Name.find_by(text_name: "Agaricus novus")
assert(name)
@@ -475,7 +478,7 @@ def test_create_observation_that_generates_email
where = "Simple, Massachusetts, USA"
generic_construct_observation(
{ observation: { place_name: where }, naming: { name: name.text_name } },
- 1, 1, 0
+ 1, 1, 0, 0
)
obs = assigns(:observation)
nam = assigns(:naming)
@@ -493,7 +496,7 @@ def test_create_observation_with_decimal_geolocation_and_unknown_name
generic_construct_observation(
{ observation: { place_name: "", lat: lat, lng: lng },
naming: { name: "Unknown" } },
- 1, 0, 0
+ 1, 0, 0, 0
)
obs = assigns(:observation)
@@ -509,7 +512,7 @@ def test_create_observation_with_dms_geolocation_and_unknown_name
generic_construct_observation(
{ observation: { place_name: "", lat: lat2, lng: lng2 },
naming: { name: "Unknown" } },
- 1, 0, 0
+ 1, 0, 0, 0
)
obs = assigns(:observation)
@@ -524,7 +527,7 @@ def test_create_observation_with_empty_geolocation_and_location
generic_construct_observation(
{ observation: { place_name: "", lat: "", lng: "" },
naming: { name: "Unknown" } },
- 0, 0, 0
+ 0, 0, 0, 0
)
end
@@ -533,7 +536,7 @@ def test_create_observations_with_unknown_location_and_empty_geolocation
generic_construct_observation(
{ observation: { place_name: "Earth", lat: "", lng: "" },
naming: { name: "Unknown" } },
- 1, 0, 0
+ 1, 0, 0, 0
)
end
@@ -549,7 +552,7 @@ def test_create_observation_with_various_altitude_formats
generic_construct_observation(
{ observation: { place_name: where, alt: input },
naming: { name: "Unknown" } },
- 1, 0, 0
+ 1, 0, 0, 0
)
obs = assigns(:observation)
@@ -564,7 +567,7 @@ def test_create_observation_creating_class
{ observation: { place_name: "Earth", lat: "", lng: "" },
naming: { name: "Lecanoromycetes L." },
approved_name: "Lecanoromycetes L." },
- 1, 1, 1
+ 1, 1, 1, 0
)
name = Name.last
assert_equal("Lecanoromycetes", name.text_name)
@@ -614,7 +617,7 @@ def test_create_observation_creating_group
{ observation: { place_name: "Earth", lat: "", lng: "" },
naming: { name: "Morchella elata group" },
approved_name: "Morchella elata group" },
- 1, 1, 2
+ 1, 1, 2, 0
)
name = Name.last
assert_equal("Morchella elata group", name.text_name)
@@ -636,7 +639,7 @@ def test_prevent_creation_of_species_under_deprecated_genus
generic_construct_observation(
{ observation: { place_name: "Earth" },
naming: { name: "Cladina pictum" } },
- 0, 0, 0, roy
+ 0, 0, 0, 0, roy
)
assert_names_equal(cladina, assigns(:parent_deprecated))
assert_obj_arrays_equal([cladonia_picta], assigns(:valid_names))
@@ -645,7 +648,7 @@ def test_prevent_creation_of_species_under_deprecated_genus
{ observation: { place_name: "Earth" },
naming: { name: "Cladina pictum" },
approved_name: "Cladina pictum" },
- 1, 1, 1, roy
+ 1, 1, 1, 0, roy
)
name = Name.last
@@ -653,97 +656,106 @@ def test_prevent_creation_of_species_under_deprecated_genus
assert_true(name.deprecated)
end
+ # The ones that should pass here now need to match fixtures, in order to
+ # generate a location_id, or they will be rejected.
def test_construct_observation_dubious_place_names
+ # Location box necessary for new locations (these are all non-fixtures).
+ params = {
+ naming: { name: "Unknown" },
+ location: { north: 35, south: 34, east: -117, west: -118 }
+ }
# Test a reversed name with a scientific user
where = "USA, Massachusetts, Reversed"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0, roy
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 1, roy
)
# Test missing space.
where = "Reversible, Massachusetts,USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0
)
# (This is accepted now for some reason.)
where = "USA,Massachusetts, Reversible"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0, roy
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 1, roy
)
# Test a bogus country name
where = "Bogus, Massachusetts, UAS"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0
)
where = "UAS, Massachusetts, Bogus"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0, roy
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0, roy
)
# Test a bad state name
where = "Bad State Name, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0
)
where = "USA, Bad State Name"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0, roy
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0, roy
)
# Test mix of city and county
where = "Burbank, Los Angeles Co., California, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 1
)
+ # Location should now already exist (because of the above).
where = "USA, California, Los Angeles Co., Burbank"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0, roy
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 0, roy
)
# Test mix of city and county
where = "Falmouth, Barnstable Co., Massachusetts, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 1
)
+ # Location should now already exist (because of the above).
where = "USA, Massachusetts, Barnstable Co., Falmouth"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0, roy
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 0, roy
)
# Test some bad terms
where = "Some County, Ohio, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0
)
where = "Old Rd, Ohio, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 0, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, 0, 0, 0
)
where = "Old Rd., Ohio, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 1
)
# Test some acceptable additions
where = "near Burbank, Southern California, USA"
generic_construct_observation(
- { observation: { place_name: where }, naming: { name: "Unknown" } },
- 1, 0, 0
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, 0, 0, 1
)
end
diff --git a/test/controllers/observations_controller/observations_controller_update_test.rb b/test/controllers/observations_controller/observations_controller_update_test.rb
index 61001d9485..45aa430e17 100644
--- a/test/controllers/observations_controller/observations_controller_update_test.rb
+++ b/test/controllers/observations_controller/observations_controller_update_test.rb
@@ -5,14 +5,10 @@
class ObservationsControllerUpdateTest < FunctionalTestCase
tests ObservationsController
- ##############################################################################
-
# ----------------------------------------------------------------
# Test :edit and :update (note :update uses method: :put)
# ----------------------------------------------------------------
- # (Sorry, these used to all be edit/update_observation, now they're
- # confused because of the naming stuff.)
def test_edit_observation_form
obs = observations(:coprinus_comatus_obs)
assert_equal("rolf", obs.user.login)
@@ -274,6 +270,162 @@ def test_update_observation_strip_images
assert_false(old_img2.reload.gps_stripped)
end
+ ##############################################################################
+ # Location name validation
+ def obs_for_user(user)
+ # We need an obs owned by each user to test editing (adding) locations.
+ # Roy doesn't have a simple one, but we need him for scientific_format.
+ case user.login
+ when "rolf"
+ observations(:agaricus_campestros_obs)
+ when "roy"
+ obs = observations(:agaricus_campestras_obs)
+ obs.user_id = user.id
+ obs.save
+ obs
+ end
+ end
+
+ def modified_obs_params(params, user)
+ obs = obs_for_user(user)
+ # params[:observation] = obs.attributes.merge(params[:observation] || {})
+ params[:username] = user.login
+ params[:id] = obs.id
+ params
+ end
+
+ def location_name_exists(params, user)
+ name = Location.user_format(user, params[:observation][:place_name])
+ Location.find_by(name:) || Location.is_unknown?(name)
+ end
+
+ # Test constructing observations in various ways (with minimal namings)
+ def generic_update_observation(params, l_num, user = rolf)
+ l_count = Location.count
+ params = modified_obs_params(params, user)
+ put_requires_user(
+ :update,
+ [{ controller: "/observations", action: :show }],
+ params,
+ user.login
+ )
+
+ begin
+ if l_num.positive? || (location_name_exists(params, user) && l_num.zero?)
+ assert_redirected_to(action: :show)
+ else
+ assert_select("#dubious_location_messages")
+ end
+ rescue Minitest::Assertion => e
+ flash = get_last_flash.to_s.dup.sub!(/^(\d)/, "")
+ message = "#{e}\n" \
+ "Flash messages: (level #{Regexp.last_match(1)})\n" \
+ "< #{flash} >\n"
+ flunk(message)
+ end
+
+ assert_equal(l_count + l_num, Location.count, "Wrong Location count")
+ end
+
+ # The ones that should pass here now need to match fixtures, in order to
+ # generate a location_id, or they will be rejected.
+ def test_update_observation_dubious_place_names
+ # Location box necessary for new locations (these are all non-fixtures).
+ params = {
+ location: { north: 35, south: 34, east: -117, west: -118 }
+ }
+ # Test a reversed name with a scientific user
+ where = "USA, Massachusetts, Reversed"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, roy
+ )
+
+ # Test an existing name - should allow, but use existing location
+ where = locations(:salt_point).name
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0
+ )
+ assert_equal(locations(:salt_point).id,
+ obs_for_user(rolf).reload.location_id)
+
+ # Test missing space.
+ where = "Reversible, Massachusetts,USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0
+ )
+
+ # Test a bogus country name
+ where = "Bogus, Massachusetts, UAS"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0
+ )
+ where = "UAS, Massachusetts, Bogus"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, roy
+ )
+
+ # Test a bad state name
+ where = "Bad State Name, USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0
+ )
+ where = "USA, Bad State Name"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, roy
+ )
+
+ # Test mix of city and county
+ where = "Burbank, Los Angeles Co., California, USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1
+ )
+ # Location should now already exist (because of the above).
+ where = "USA, California, Los Angeles Co., Burbank"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0, roy
+ )
+
+ # Test mix of city and county
+ where = "USA, Massachusetts, Barnstable Co., Falmouth"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1, roy
+ )
+
+ # Test some bad terms
+ where = "Some County, Ohio, USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0
+ )
+ where = "Old Rd, Ohio, USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 0
+ )
+ where = "Old Rd., Ohio, USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1
+ )
+
+ # Test some acceptable additions
+ where = "near Burbank, Southern California, USA"
+ generic_update_observation(
+ params.merge({ observation: { place_name: where, location_id: -1 } }),
+ 1
+ )
+ end
+
# --------------------------------------------------------------------
# Test notes with template
# --------------------------------------------------------------------
diff --git a/test/controllers/species_lists/name_lists_controller_test.rb b/test/controllers/species_lists/name_lists_controller_test.rb
index f6fbe971c7..4a2d6a16d2 100644
--- a/test/controllers/species_lists/name_lists_controller_test.rb
+++ b/test/controllers/species_lists/name_lists_controller_test.rb
@@ -57,7 +57,6 @@ def test_name_lister
def assert_create_species_list
assert_template("species_lists/new")
assert_template("shared/_form_list_feedback")
- assert_template("shared/_textilize_help")
assert_template("species_lists/_form")
end
end
diff --git a/test/controllers/species_lists/uploads_controller_test.rb b/test/controllers/species_lists/uploads_controller_test.rb
index ecf8e39306..1cc201ec71 100644
--- a/test/controllers/species_lists/uploads_controller_test.rb
+++ b/test/controllers/species_lists/uploads_controller_test.rb
@@ -67,7 +67,6 @@ def test_read_species_list_two
def assert_edit_species_list
assert_template("species_lists/edit")
assert_template("shared/_form_list_feedback")
- assert_template("shared/_textilize_help")
assert_template("species_lists/_form")
end
end
diff --git a/test/controllers/species_lists_controller_test.rb b/test/controllers/species_lists_controller_test.rb
index f66b61eda7..56d08e1527 100644
--- a/test/controllers/species_lists_controller_test.rb
+++ b/test/controllers/species_lists_controller_test.rb
@@ -50,14 +50,12 @@ def spl_params(spl)
def assert_create_species_list
assert_template("new")
assert_template("shared/_form_list_feedback")
- assert_template("shared/_textilize_help")
assert_template("species_lists/_form")
end
def assert_edit_species_list
assert_template("edit")
assert_template("shared/_form_list_feedback")
- assert_template("shared/_textilize_help")
assert_template("species_lists/_form")
end
diff --git a/test/images/geotagged_s_pasadena.jpg b/test/images/geotagged_s_pasadena.jpg
new file mode 100644
index 0000000000..80542625b8
Binary files /dev/null and b/test/images/geotagged_s_pasadena.jpg differ
diff --git a/test/integration/capybara/field_slips_integration_test.rb b/test/integration/capybara/field_slips_integration_test.rb
index e125c2204e..5b278b6a05 100644
--- a/test/integration/capybara/field_slips_integration_test.rb
+++ b/test/integration/capybara/field_slips_integration_test.rb
@@ -44,6 +44,7 @@ def test_destroying_a_field_slip
def test_new_observation_violates_project_constraints
project = projects(:falmouth_2023_09_project)
+ wrong_location = locations(:albion)
user = users(:roy)
assert(project.member?(user),
"Test needs user who is member of #{project.title} Project")
@@ -52,7 +53,14 @@ def test_new_observation_violates_project_constraints
visit("/qr/NFAL-0001")
click_on(:field_slip_create_obs.l)
- fill_in(:WHERE.l, with: locations(:albion).name, visible: :any)
+ project_checkbox = "project_id_#{project.id}"
+ check(project_checkbox)
+ assert_selector("##{project_checkbox}[checked='checked']")
+ fill_in(:WHERE.l, with: wrong_location.name, visible: :any)
+ # this is what counts, would be handled by js
+ find_field(id: "observation_location_id",
+ type: :hidden).set(wrong_location.id)
+
assert_no_difference(
"Observation.count",
"Observation shouldn't be created before confirming constraint violation"
diff --git a/test/integration/capybara/observations_integration_test.rb b/test/integration/capybara/observations_integration_test.rb
index 7326ebb04b..2a813f5698 100644
--- a/test/integration/capybara/observations_integration_test.rb
+++ b/test/integration/capybara/observations_integration_test.rb
@@ -239,6 +239,7 @@ def test_observation_project_checkbox_state_persistence
# Test user's options when an out-of-date-range project is checked
# when creating an Observation
+ # proj.location == albion, proj.start_date 2010/9/26, end_date 2010/10/26
def test_add_out_of_range_observation_to_project
proj = projects(:past_project)
user = users(:roy)
@@ -246,17 +247,22 @@ def test_add_out_of_range_observation_to_project
assert(proj.member?(user),
"Need fixtures such that `user` is a member of `proj`")
proj_checkbox = "project_id_#{proj.id}"
+ last_obs = Observation.recent_by_user(user).last
+ last_location = last_obs.location # nybg_location
obs_location = locations(:burbank)
+ assert_not_equal(proj.location, last_location)
+ assert_not_equal(proj.location, obs_location)
login(user)
- # Try adding out-of-range Observation to Project
+ # Try adding out-of-range Observation (by both date and location) to Project
# It should reload the form with warnings and a hidden field
visit(new_observation_path)
assert_selector("#observation_place_name", visible: :any)
assert(has_unchecked_field?(proj_checkbox),
"Missing an unchecked box for Project which has ended")
- fill_in(id: "observation_place_name", visible: :any,
- with: obs_location.name)
+ assert_field("observation_location_id",
+ type: :hidden, with: last_location.id)
+ assert_field("observation_place_name", with: last_location.display_name)
check(proj_checkbox)
assert_selector("##{proj_checkbox}[checked='checked']")
assert_no_difference("Observation.count",
@@ -268,14 +274,12 @@ def test_add_out_of_range_observation_to_project
"#flash_notices",
text: :form_observations_there_is_a_problem_with_projects.t.strip_html
)
- default_obs = Observation.where(user_id: user.id).order(:created_at).last
within("#project_messages") do # out-of-range warning message
assert(has_text?(:form_observations_projects_out_of_range.l(
- date: default_obs.when,
- place_name: obs_location.name
+ date: last_obs.when,
+ place_name: last_location.display_name
)),
"Missing out-of-range warning with observation date")
-
assert(has_text?(proj.title) && has_text?(proj.constraints),
"Warning is missing out-of-range project's title or constraints")
end
@@ -299,20 +303,27 @@ def test_add_out_of_range_observation_to_project
# 2. Prove that Observation is created if user fixes dates and
# location to be in-range
+ # First, change the location to be in range, but not the date.
visit(new_observation_path)
assert_selector("#observation_place_name", visible: :any)
fill_in(id: "observation_place_name", visible: :any,
with: proj.location.display_name)
+ # this is what counts, would be handled by js
+ find_field(id: "observation_location_id",
+ type: :hidden).set(proj.location.id)
check(proj_checkbox)
first(:button, "Create").click
assert_selector(
"#flash_notices",
text: :form_observations_there_is_a_problem_with_projects.t.strip_html
)
- # Change the Obs date to be in range
+ # Change the Obs date to be in range - this should do it.
select(proj.end_date.day, from: "observation_when_3i")
select(Date::MONTHNAMES[proj.end_date.month], from: "observation_when_2i")
select(proj.end_date.year, from: "observation_when_1i")
+ # must be re-set, why? Seems @location should be set by previous commit
+ find_field(id: "observation_location_id",
+ type: :hidden).set(proj.location.id)
assert_difference(
"Observation.count", 1,
"Failed to created Obs after setting When within Project date range"
@@ -328,7 +339,9 @@ def test_add_out_of_range_observation_to_project
visit(new_observation_path)
assert_selector("#observation_place_name", visible: :any)
fill_in(id: "observation_place_name", visible: :any,
- with: obs_location.name)
+ with: obs_location.name) # ignored, it's the ID that matters
+ find_field(id: "observation_location_id", type: :hidden).
+ set(obs_location.id) # this is what counts
check(proj_checkbox)
# reset Observation date, making it out-of-range
select(Time.zone.today.day, from: "observation_when_3i")
diff --git a/test/models/comment_test.rb b/test/models/comment_test.rb
index defdae3916..f9101ff9ba 100644
--- a/test/models/comment_test.rb
+++ b/test/models/comment_test.rb
@@ -11,6 +11,13 @@ def teardown
QueuedEmail.queue = false
end
+ def test_find_object_for_all_types
+ Comment.all_types.each do |type|
+ assert(AbstractModel.find_object(type.to_s, type.first.id),
+ "Unable to use find_object to find #{type}")
+ end
+ end
+
def test_user_highlighting_parsing
do_highlight_test([], "")
do_highlight_test([mary], "_user #{mary.id}_")
diff --git a/test/models/translation_string_test.rb b/test/models/translation_string_test.rb
index d3a21c86b5..a257c34b2c 100644
--- a/test/models/translation_string_test.rb
+++ b/test/models/translation_string_test.rb
@@ -6,4 +6,38 @@ class TranslationStringTest < UnitTestCase
def test_banner_time
assert_not_nil(TranslationString.banner_time)
end
+
+ def test_rename_tags_upcase
+ str = TranslationString.create(
+ { tag: "JOHN", text: "Harding",
+ user: users(:rolf), language: languages(:english) }
+ )
+ TranslationString.rename_tags("JOHN" => "FRED")
+ assert_nil(TranslationString.find_by(tag: "JOHN"))
+ assert_not_nil(TranslationString.find_by(tag: "FRED"))
+ assert_equal("Harding", str.reload.text)
+ str.update(text: "Wesley")
+ assert_equal("Wesley", str.reload.text)
+
+ TranslationString.rename_tags("FRED" => "JOHN")
+ assert_nil(TranslationString.find_by(tag: "FRED"))
+ assert_not_nil(TranslationString.find_by(tag: "JOHN"))
+ assert_equal("Wesley", str.reload.text)
+ end
+
+ def test_rename_tags_snakecase
+ str = TranslationString.create(
+ { tag: "interesting_things", text: "Stuff that we may want to know.",
+ user: users(:rolf), language: languages(:english) }
+ )
+ assert_raises("Tags must be symbols or strings with no spaces.") do
+ TranslationString.rename_tags("interesting_things" => "other things")
+ end
+ assert_not_nil(TranslationString.find_by(tag: "interesting_things"))
+
+ TranslationString.rename_tags("interesting_things" => "other_stuff")
+ assert_nil(TranslationString.find_by(tag: "interesting_things"))
+ assert_not_nil(TranslationString.find_by(tag: "other_stuff"))
+ assert_equal("Stuff that we may want to know.", str.reload.text)
+ end
end
diff --git a/test/system/help_identify_system_test.rb b/test/system/help_identify_system_test.rb
index d71a2ce001..0ace9adad5 100644
--- a/test/system/help_identify_system_test.rb
+++ b/test/system/help_identify_system_test.rb
@@ -27,7 +27,7 @@ def test_identify_index_naming_and_vote_ui
within(".lg-sub-html") do
click_on("Propose a Name")
end
- assert_selector("#modal_obs_#{obs.id}_naming", wait: 9)
+ assert_selector("#modal_obs_#{obs.id}_naming", wait: 12)
assert_selector("#obs_#{obs.id}_naming_form")
ncc = names(:coprinus_comatus)
diff --git a/test/system/location_form_system_test.rb b/test/system/location_form_system_test.rb
new file mode 100644
index 0000000000..49225adfec
--- /dev/null
+++ b/test/system/location_form_system_test.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require("application_system_test_case")
+
+class LocationFormSystemTest < ApplicationSystemTestCase
+ def test_format_new_location_name
+ # browser = page.driver.browser
+ rolf = users("rolf")
+ login!(rolf)
+
+ visit("/locations/new")
+ assert_selector("body.locations__new")
+
+ assert_selector("#location_display_name")
+ assert_button(:form_locations_find_on_map.l)
+ # be sure the map is loaded!
+ assert_selector("#map_div div div")
+ fill_in("location_display_name", with: "genohlac gard france")
+ click_button(:form_locations_find_on_map.l)
+
+ assert_selector("#location_display_name.geocoded")
+ assert_field("location_display_name",
+ with: "Génolhac, Gard, Occitanie, France")
+
+ assert_field("location_north", with: "44.3726")
+ assert_field("location_east", with: "3.985")
+ assert_field("location_south", with: "44.3055")
+ assert_field("location_west", with: "3.9113")
+ assert_field("location_high", with: "1388.2098")
+ assert_field("location_low", with: "287.8201")
+ end
+end
diff --git a/test/system/observation_comment_system_test.rb b/test/system/observation_comment_system_test.rb
index fda4163c17..079189f035 100644
--- a/test/system/observation_comment_system_test.rb
+++ b/test/system/observation_comment_system_test.rb
@@ -166,7 +166,7 @@ def test_add_and_edit_comment
# It's not editable by them.
using_session("rolf_session") do
scroll_to(find("#comments_for_object"), align: :center)
- assert_selector("#comment_#{ufo.id}")
+ assert_selector("#comment_#{ufo.id}", wait: 6)
within("#comment_#{ufo.id}") do
assert_text("I am a UFO!")
assert_selector(".user_link_#{mary.id}")
@@ -177,7 +177,7 @@ def test_add_and_edit_comment
using_session("katrina_session") do
scroll_to(find("#comments_for_object"), align: :center)
- assert_selector("#comment_#{ufo.id}")
+ assert_selector("#comment_#{ufo.id}", wait: 6)
within("#comment_#{ufo.id}") do
assert_text("I am a UFO!")
assert_selector(".user_link_#{mary.id}")
@@ -204,7 +204,7 @@ def test_add_and_edit_comment
end
using_session("katrina_session") do
- assert_selector("#comment_#{ufo.id}")
+ assert_selector("#comment_#{ufo.id}", wait: 6)
within("#comment_#{ufo.id}") do
assert_text("Right on!")
assert_no_selector(".edit_comment_link_#{ufo.id}")
diff --git a/test/system/observation_form_system_test.rb b/test/system/observation_form_system_test.rb
index 3f3b6778ab..65c08d2bb6 100644
--- a/test/system/observation_form_system_test.rb
+++ b/test/system/observation_form_system_test.rb
@@ -12,28 +12,32 @@ def test_create_minimal_observation
click_on("Create Observation")
assert_selector("body.observations__new")
- within("#observation_form") do
- # MOAutocompleter replaces year select with text field
- assert_field("observation_when_1i", with: Time.zone.today.year.to_s)
- assert_select("observation_when_2i", text: Time.zone.today.strftime("%B"))
- # %e is day of month, no leading zero
- assert_select("observation_when_3i", text: Time.zone.today.strftime("%e"))
- assert_selector("#where_help",
- text: "Albion, Mendocino Co., California", visible: :all)
- fill_in("naming_name", with: "Elfin saddle")
- # don't wait for the autocompleter - we know it's an elfin saddle!
- browser.keyboard.type(:tab)
- assert_field("naming_name", with: "Elfin saddle")
- # start typing the location...
- fill_in("observation_place_name", with: locations.first.name[0, 1])
- # wait for the autocompleter...
- assert_selector(".auto_complete", wait: 6)
- browser.keyboard.type(:down, :tab) # cursor to first match + select row
- assert_field("observation_place_name", with: locations.first.name)
- click_commit
- end
+ # MOAutocompleter replaces year select with text field
+ assert_field("observation_when_1i", with: Time.zone.today.year.to_s)
+ assert_select("observation_when_2i", text: Time.zone.today.strftime("%B"))
+ # %e is day of month, no leading zero
+ assert_select("observation_when_3i", text: Time.zone.today.strftime("%e"))
+ assert_selector("#observation_place_name_help",
+ text: "Albion, Mendocino Co., California", visible: :all)
+ # start typing the location...
+ fill_in("observation_place_name", with: locations.first.name[0, 1])
+ # wait for the autocompleter...
+ assert_selector(".auto_complete", wait: 6)
+ browser.keyboard.type(:down, :tab) # cursor to first match + select row
+ assert_field("observation_place_name", with: locations.first.name)
+
+ # Move to the next step, Identification
+ step_nav_1 = find("#step-nav-1")
+ scroll_to(step_nav_1, align: :top)
+ within(step_nav_1) { click_on(:NEXT.l) }
+
+ fill_in("naming_name", with: "Elfin saddle")
+ # don't wait for the autocompleter - we know it's an elfin saddle!
+ browser.keyboard.type(:tab)
+ assert_field("naming_name", with: "Elfin saddle")
+
+ within("#observation_form") { click_commit }
- assert_selector("#name_messages", text: "MO does not recognize the name")
assert_flash_error(
:form_observations_there_is_a_problem_with_name.t.html_to_ascii
)
@@ -43,33 +47,31 @@ def test_create_minimal_observation
# click_button("map_location")
# assert_selector("#observation_form_map > div > div > iframe")
- within("#observation_form") do
- fill_in("naming_name", with: "Coprinus com")
- browser.keyboard.type(:tab)
- # wait for the autocompleter!
- assert_selector(".auto_complete")
- browser.keyboard.type(:down, :tab) # cursor to first match + select row
- browser.keyboard.type(:tab)
- assert_field("naming_name", with: "Coprinus comatus")
- # Place name should stay filled
- browser.keyboard.type(:tab)
- assert_field("observation_place_name", with: locations.first.name)
- click_commit
- end
+ assert_field("observation_place_name", with: locations.first.name)
+
+ # Move to the next step, Identification
+ step_nav_1 = find("#step-nav-1")
+ scroll_to(step_nav_1, align: :top)
+ within(step_nav_1) { click_on(:NEXT.l) }
+
+ assert_selector("#name_messages", text: "MO does not recognize the name")
+ fill_in("naming_name", with: "Coprinus com")
+ browser.keyboard.type(:tab)
+ # wait for the autocompleter!
+ assert_selector(".auto_complete")
+ browser.keyboard.type(:down, :tab) # cursor to first match + select row
+ browser.keyboard.type(:tab)
+ assert_field("naming_name", with: "Coprinus comatus")
+ # Place name should stay filled
+ browser.keyboard.type(:tab)
+
+ within("#observation_form") { click_commit }
assert_selector("body.observations__show")
assert_flash_success(/created observation/i)
end
- # The geotagged.jpg is from here.
- UNIVERSITY_PARK_EXTENTS = {
- north: 25.762050,
- south: 25.733291,
- east: -80.351868,
- west: -80.385170
- }.freeze
-
- def test_autofill_location_from_geotagged_image_nothing_matches
+ def test_trying_to_create_duplicate_location_just_uses_existing_location
setup_image_dirs # in general_extensions
login!(katrina)
@@ -82,8 +84,55 @@ def test_autofill_location_from_geotagged_image_nothing_matches
assert_geolocation_is_empty
last_obs = Observation.where(user_id: User.current.id).
order(:created_at).last
+ # This is currently "Falmouth, Massachusetts, USA"
+ existing_loc = Location.find(last_obs.location_id)
+ # We just need to check this is not the most recent location.
+ assert_not_equal(Location.last.id, existing_loc.id)
+ assert_field("observation_place_name", with: last_obs.where)
+ assert_field("observation_location_id", with: last_obs.location_id,
+ type: :hidden)
+
+ # autocompleter is unconstrained
+ assert_selector("[data-type='location']")
+ find(id: "observation_place_name").trigger("click")
+ # This should make the "create_locality" button appear.
+ click_on(:form_observations_create_locality.l)
+ assert_selector("[data-type='location_google']")
+ assert_field("observation_place_name", with: last_obs.where)
+ assert_field("observation_location_id", with: "", type: :hidden)
+
+ # Move to the next step, Identification
+ step_nav_1 = find("#step-nav-1")
+ scroll_to(step_nav_1, align: :top)
+ within(step_nav_1) { click_on(:NEXT.l) }
+
+ within("#observation_form") { click_commit }
+
+ # Observation should have saved with the existing location_id for U.P.
+ assert_flash_success(/created observation/i)
+ assert_selector("body.observations__show")
+
+ obs = Observation.last
+ assert_equal(existing_loc.name, obs.where)
+ assert_equal(existing_loc.id, obs.location_id)
+ assert_not_equal(Location.last.id, obs.location_id)
+ end
+
+ def test_autofill_location_from_geotagged_image_nothing_matches
+ setup_image_dirs # in general_extensions
+ login!(katrina)
+
+ # open_create_observation_form
+ visit(new_observation_path)
+ assert_selector("body.observations__new")
+
+ # check new observation form defaults
+ assert_date_is_now
+ assert_geolocation_is_empty
+ last_obs = Observation.recent_by_user(User.current).last
assert_selector("#observation_place_name", wait: 6)
assert_selector("#observation_location_id", visible: :all)
+ sleep(0.5)
assert_field("observation_place_name", with: last_obs.where)
assert_field("observation_location_id", with: last_obs.location_id,
type: :hidden)
@@ -92,15 +141,18 @@ def test_autofill_location_from_geotagged_image_nothing_matches
click_attach_file("geotagged.jpg")
sleep(0.5)
- # we should have the new type of location_containing autocompleter now
- assert_selector("[data-type='location_containing']")
- sleep(0.5)
# GPS should have been copied to the obs fields
- assert_equal("25.7582", find('[id$="observation_lat"]').value)
- assert_equal("-80.3731", find('[id$="observation_lng"]').value)
- assert_equal("4", find('[id$="observation_alt"]').value.to_i.to_s)
- # Place name should not have been filled, because no locations match
- assert_equal(last_obs.where, find('[id$="observation_place_name"]').value)
+ assert_image_gps_copied_to_obs(GEOTAGGED_EXIF)
+ # Date should have been copied to the obs fields
+ assert_image_date_copied_to_obs(GEOTAGGED_EXIF)
+ sleep(0.5)
+ # we should have the new type of location_google autocompleter now
+ assert_selector("[data-type='location_google'][data-stimulus='connected']")
+ # Place name should now have been filled by Google, no MO locations match
+ assert_field("observation_place_name", with: UNIVERSITY_PARK[:name],
+ wait: 6)
+ assert_field("observation_location_id", with: "-1", type: :hidden)
+
# now check that the "use_exif" button is disabled
assert_no_button(:image_use_exif.l)
end
@@ -109,13 +161,14 @@ def test_autofill_location_from_geotagged_image_matching_location
setup_image_dirs # in general_extensions
login!(katrina)
- # now create the location and start again.
- university_park = Location.new(
- name: "University Park, Miami-Dade County, Florida, USA",
- **UNIVERSITY_PARK_EXTENTS
- )
+ # Make "University Park" available as a matching location.
+ university_park = Location.new(**UNIVERSITY_PARK)
+ # Sanity check the lat/lng. `contains?(lat, lng)` is a Mappable::BoxMethod
+ assert(university_park.contains?(GEOTAGGED_EXIF[:lat],
+ GEOTAGGED_EXIF[:lng]))
university_park.save!
sleep(0.5)
+
# open_create_observation_form
visit(new_observation_path)
assert_selector("body.observations__new")
@@ -123,8 +176,8 @@ def test_autofill_location_from_geotagged_image_matching_location
# check new observation form defaults
assert_date_is_now
assert_geolocation_is_empty
- last_obs = Observation.where(user_id: User.current.id).
- order(:created_at).last
+ last_obs = Observation.recent_by_user(User.current).last
+ # This is currently "Falmouth, Massachusetts, USA"
assert_field("observation_place_name", with: last_obs.where)
assert_field("observation_location_id", with: last_obs.location_id,
type: :hidden)
@@ -138,27 +191,23 @@ def test_autofill_location_from_geotagged_image_matching_location
# we should have a location_containing autocompleter now
assert_selector("[data-type='location_containing']")
# GPS should have been copied to the obs fields
- assert_equal("25.7582", find('[id$="observation_lat"]').value)
- assert_equal("-80.3731", find('[id$="observation_lng"]').value)
- assert_equal("4", find('[id$="observation_alt"]').value.to_i.to_s)
-
+ assert_image_gps_copied_to_obs(GEOTAGGED_EXIF)
+ assert_image_date_copied_to_obs(GEOTAGGED_EXIF)
# now check that the "use_exif" button is disabled
assert_no_button(:image_use_exif.l)
- # Place name should have been filled, but query may be in progress.
- # Commenting this out for now, it's too flaky, and it's retested below.
- # assert_selector(".auto_complete")
- # assert_field("observation[place_name]", with: university_park.name,
- # wait: 6)
- # assert_field("observation[location_id]", with: university_park.id,
- # type: :hidden)
-
- # now clear a lat-lng-alt field, and the place name should clear too
- click_button(:form_observations_clear_map.t.as_displayed)
- fill_in("observation_lat", with: "")
- # assert_field("observation_place_name", with: "")
- # should have swapped autocompleter back to "location", but it doesn't
- # assert_selector("[data-type='location']")
+ # Place name should have been filled.
+ assert_field("observation[place_name]", with: university_park.name,
+ wait: 6)
+ assert_field("observation[location_id]", with: university_park.id,
+ type: :hidden)
+
+ # now clear all location fields, and the place name should clear too
+ click_button(:form_observations_clear_map.l)
+ # fill_in("observation_lat", with: "")
+ assert_field("observation_place_name", with: "")
+ # should have swapped autocompleter back to "location"
+ assert_selector("[data-type='location']")
# check that the "use_exif" button is re-enabled
assert_button(:image_use_exif.l)
@@ -166,36 +215,18 @@ def test_autofill_location_from_geotagged_image_matching_location
# wait for the form to update
assert_selector("[data-type='location_containing']")
# GPS should have been copied to the obs fields
- assert_equal("25.7582", find('[id$="observation_lat"]').value)
- assert_equal("-80.3731", find('[id$="observation_lng"]').value)
- assert_equal("4", find('[id$="observation_alt"]').value.to_i.to_s)
+ assert_image_gps_copied_to_obs(GEOTAGGED_EXIF)
+ assert_image_date_copied_to_obs(GEOTAGGED_EXIF)
# Finally, the query should have gone through and the place name filled
- # assert_field("observation[place_name]", with: university_park.name,
- # wait: 6)
- # assert_field("observation[location_id]", with: university_park.id,
- # type: :hidden)
+ assert_field("observation[place_name]", with: university_park.name,
+ wait: 6)
+ assert_field("observation[location_id]", with: university_park.id,
+ type: :hidden)
# now check that the "use_exif" button is disabled
assert_no_button(:image_use_exif.l)
end
- # Google seems to give accurate bounds to this place, but the
- # geometry.location_type of "Pasadena, California" is "APPROXIMATE".
- # Viewport and bounds are separate fields in the Geocoder response,
- # and other places' bounds may be more precise. Viewport may be padded.
- # On the right may be the accurate extents, they're hard to find.
- PASADENA_EXTENTS = {
- north: 34.251905, # 34.1774839
- south: 34.1170368, # 34.1275634561
- east: -118.0654789, # -118.0989059
- west: -118.1981391, # -118.1828198
- high: 1096.943603515625,
- low: 141.5890350341797,
- lat: 34.1477849,
- lng: -118.1445155,
- alt: 262.5840148925781
- }.freeze
-
def test_post_edit_and_destroy_with_details_and_location
# browser = page.driver.browser
setup_image_dirs # in general_extensions
@@ -210,15 +241,24 @@ def test_post_edit_and_destroy_with_details_and_location
assert_date_is_now
assert_geolocation_is_empty
- last_obs = Observation.where(user_id: User.current.id).
- order(:created_at).last
+ last_obs = Observation.recent_by_user(User.current).last
assert_field("observation_place_name", with: last_obs.where)
+ # Move to the next step, Identification
+ step_nav_1 = find("#step-nav-1")
+ scroll_to(step_nav_1, align: :top)
+ within(step_nav_1) { click_on(:NEXT.l) }
+
assert_field("naming_name", with: "")
assert(last_obs.is_collection_location)
- assert_checked_field("observation_is_collection_location")
- assert_no_checked_field("observation_specimen")
- assert_field(other_notes_id, with: "")
+ assert_checked_field("observation_is_collection_location", visible: :all)
+ assert_no_checked_field("observation_specimen", visible: :all)
+ assert_field(other_notes_id, with: "", visible: :all)
+
+ # Move to the previous step, Images/Details
+ step_nav_2 = find("#step-nav-2")
+ scroll_to(step_nav_2, align: :top)
+ within(step_nav_2) { click_on(:BACK.l) }
# Add the images separately, so we can be sure of the order. Otherwise,
# images appear in the order each upload finishes, which is unpredictable.
@@ -232,13 +272,11 @@ def test_post_edit_and_destroy_with_details_and_location
# assert_field('[id$="when_1i"]', with: "2006")
# No idea why we have to do it like this, maybe value set by JS.
within(first_image_wrapper) do
- assert_equal("2006", find('[id$="when_1i"]', visible: :all).value)
- assert_equal("11", find('[id$="when_2i"]', visible: :all).value)
- assert_equal("20", find('[id$="when_3i"]', visible: :all).value)
+ assert_image_exif_available(COPRINUS_COMATUS_EXIF)
end
# Add a second image that's geotagged.
- click_attach_file("geotagged.jpg")
+ click_attach_file("geotagged_s_pasadena.jpg")
sleep(0.5)
# Be sure we have two image wrappers. We have to wait for
# the first one to be hidden before we can see the second one.
@@ -248,22 +286,14 @@ def test_post_edit_and_destroy_with_details_and_location
# The new one is prepended, so second is "first"
second_image_wrapper = image_wrappers[0]
- # Check that it's the right image: this is geotagged.jpg's date
+ # Check that it's the right image: this is geotagged_s_pasadena.jpg's date
within(second_image_wrapper) do
- assert_equal("2018", find('[id$="when_1i"]', visible: :all).value)
- assert_equal("12", find('[id$="when_2i"]', visible: :all).value)
- assert_equal("31", find('[id$="when_3i"]', visible: :all).value)
+ assert_image_exif_available(SO_PASA_EXIF)
end
# Date should have been copied to the obs fields
- assert_equal("2018", find('[id$="observation_when_1i"]').value)
- assert_equal("12", find('[id$="observation_when_2i"]').value)
- assert_equal("31", find('[id$="observation_when_3i"]').value)
-
- # GPS should have been copied to the obs fields
- assert_equal("25.7582", find('[id$="observation_lat"]').value)
- assert_equal("-80.3731", find('[id$="observation_lng"]').value)
- assert_equal("4", find('[id$="observation_alt"]').value.to_i.to_s)
+ assert_image_gps_copied_to_obs(SO_PASA_EXIF)
+ assert_image_date_copied_to_obs(SO_PASA_EXIF)
# Ok, enough. By now, the carousel image should be showing the second image.
assert_selector(
@@ -273,27 +303,28 @@ def test_post_edit_and_destroy_with_details_and_location
# Try removing the geotagged image
scroll_to(second_image_wrapper, align: :center)
within(second_image_wrapper) { find(".remove_image_button").click }
+ sleep(1)
+ # Be sure second image has been removed
+ assert_no_selector(".carousel-item[data-image-status='upload']",
+ text: "geotagged_s_pasadena.jpg", wait: 9)
# Be sure we have only one image wrapper now
- image_wrappers = all(".carousel-item[data-image-status='upload']",
- visible: :all)
- assert_equal(1, image_wrappers.length)
+ assert_selector(".carousel-item[data-image-status='upload']",
+ visible: :all, count: 1)
- # Add geotagged.jpg again
- click_attach_file("geotagged.jpg")
+ # Add geotagged_s_pasadena.jpg again
+ click_attach_file("geotagged_s_pasadena.jpg")
sleep(0.5)
# Be sure we have two image wrappers
second_image_wrapper = find(".carousel-item[data-image-status='upload']",
- text: "25.7582")
+ text: SO_PASA_EXIF[:lat].to_s)
image_wrappers = all(".carousel-item[data-image-status='upload']",
visible: :all)
assert_equal(image_wrappers.length, 2)
within(second_image_wrapper) do
- assert_equal("2018", find('[id$="when_1i"]').value)
- assert_equal("12", find('[id$="when_2i"]').value)
- assert_equal("31", find('[id$="when_3i"]').value)
+ assert_image_exif_available(SO_PASA_EXIF)
end
# Set copyright holder and image notes on both
@@ -317,28 +348,39 @@ def test_post_edit_and_destroy_with_details_and_location
assert_no_text(:image_set_default.l)
end
- # Fill out some other stuff
+ # Override the dates from the geotagged image for this obs
obs_when = find("#observation_when_1i")
scroll_to(obs_when, align: :center)
fill_in("observation_when_1i", with: "2010")
select("August", from: "observation_when_2i")
select("14", from: "observation_when_3i")
- # intentional error: nonexistant place name
+ # intentional error: nonexistant place name. Also, katrina's preference is
+ # for postal format locations. Should not validate the country "Pasadena".
location = find("#observation_place_name")
scroll_to(location, align: :center)
fill_in("observation_place_name", with: "USA, California, Pasadena")
assert_field("observation_place_name", with: "USA, California, Pasadena")
- uncheck("observation_is_collection_location")
- check("observation_specimen")
+ uncheck("observation_is_collection_location", visible: :all)
- assert_selector("#collection_number_number")
+ # Move to the next step, Identification
+ within(step_nav_1) { click_on(:NEXT.l) }
+ sleep(1)
+
+ specimen_section = find("#observation_specimen_section", visible: :all)
+ scroll_to(specimen_section, align: :center)
+ assert_field("observation_specimen")
+ check("observation_specimen")
+ assert_field("collection_number_number")
fill_in("collection_number_number", with: "17-034a")
- fill_in(other_notes_id, with: "Notes for observation")
+ fill_in(other_notes_id, with: "Notes for observation", visible: :all)
+
+ # Move to the next step, Projects/Lists
+ within(step_nav_2) { click_on(:NEXT.l) }
# Inherited project constraints maybe messing with this observation - clear
- all('[id^="project_id_"]').each do |project_checkbox|
- project_checkbox.click if project_checkbox.checked?
+ all('[id^="project_id_"]', visible: :all).each do |project_checkbox|
+ project_checkbox.trigger("click") if project_checkbox.checked?
end
# submit_observation_form_with_errors
@@ -355,122 +397,71 @@ def test_post_edit_and_destroy_with_details_and_location
assert_select("observation_when_3i", text: "14")
assert_field("observation_place_name", with: "USA, California, Pasadena")
- assert_field("observation_lat", with: "25.7582")
- assert_field("observation_lng", with: "-80.3731")
- assert_field("observation_alt", with: "4")
- # This geolocation is for Florida, and actually should disable
- # autocompleting Pasadena
+ assert_image_gps_copied_to_obs(SO_PASA_EXIF)
+ # This geolocation is for Pasadena
- assert_field("naming_name", with: "")
- assert_no_checked_field("observation_is_collection_location")
- assert_checked_field("observation_specimen")
- assert_field("collection_number_number", with: "17-034a")
- assert_field(other_notes_id, with: "Notes for observation")
-
- # submit_observation_form_without_errors
-
- # fill_in("observation_place_name", with: "Pasadena, Calif")
- # browser.keyboard.type(:tab)
- # sleep(1)
- # assert_selector(".auto_complete")
- # browser.keyboard.type(:down, :tab) # cursor down to match, select row
+ assert_field("naming_name", with: "", visible: :all)
+ assert_no_checked_field("observation_is_collection_location", visible: :all)
+ assert_checked_field("observation_specimen", visible: :all)
+ assert_field("collection_number_number", with: "17-034a", visible: :all)
+ assert_field(other_notes_id, with: "Notes for observation", visible: :all)
+
+ # Submit observation form without errors
fill_in("observation_place_name", with: "Pasadena, California, USA")
assert_field("observation_place_name", with: "Pasadena, California, USA")
- # geo-coordinates-parser will reject internally-inconsistent notation.
- fill_in("observation_lat", with: " 12deg 36.75min N ") # == 12.6125
- fill_in("observation_lng", with: " 121deg 33.14min E ") # == 121.5523
- fill_in("observation_alt", with: " 56 ft. ")
-
- # fill_in("naming_name", with: "Agaricus campe")
- # assert_selector(".auto_complete")
- # assert_selector(".auto_complete ul li", text: "Agaricus campestris")
- # browser.keyboard.type(:down, :down, :tab) # down to second match + select
- fill_in("naming_name", with: "Agaricus campestris")
- assert_field("naming_name", with: "Agaricus campestris")
- select(Vote.confidence(Vote.next_best_vote), from: "naming_vote_value")
- assert_select("naming_vote_value",
- selected: Vote.confidence(Vote.next_best_vote))
+ # Be sure this is still the South Pasadena box:
+ assert_image_gps_copied_to_obs(SO_PASA_EXIF)
# Carousel items are re-output with image records this time.
- all(".carousel-indicator").last.click
+ all(".carousel-indicator").last.trigger("click")
- assert_selector(".carousel-item", text: "25.7582", visible: :all)
- second_item = find(".carousel-item", text: "25.7582", visible: :all)
+ assert_selector(".carousel-item", text: SO_PASA_EXIF[:lat].to_s,
+ visible: :all)
+ second_item = find(".carousel-item", text: SO_PASA_EXIF[:lat].to_s,
+ visible: :all)
items = all(".carousel-item", visible: :all)
assert_equal(items.length, 2)
within(second_item) do
- assert_equal("2018", find('[id$="when_1i"]').value)
- assert_equal("12", find('[id$="when_2i"]').value)
- assert_equal("31", find('[id$="when_3i"]').value)
+ assert_image_exif_available(SO_PASA_EXIF)
end
- # will have cleared the place_name field, lat/lng doesn't match Pasadena
- fill_in("observation_place_name", with: "Pasadena, California, USA")
+ fill_in("observation_place_name", with: "")
+ click_on(:form_observations_create_locality.l)
+ # lat/lng does not match Google's Pasadena, but does match South Pasadena
+ assert_selector("[data-type='location_google']")
+ # assert_selector(".auto_complete", wait: 6)
+ find("#observation_place_name").trigger("focus")
+ assert_selector(".dropdown-item a[data-id='-1']",
+ text: SOUTH_PASADENA[:name], visible: :all, wait: 6)
+ # There may be more than one of these, click the first
+ find(".dropdown-item a[data-id='-1']",
+ text: SOUTH_PASADENA[:name], visible: :all).trigger("click")
+
+ # Check the hidden fields returned by Google
+ assert_hidden_location_fields_filled(SOUTH_PASADENA)
+
+ # Move to the next step, Identification
+ within(step_nav_1) { click_on(:NEXT.l) }
+
+ assert_selector("[data-type='name'][data-stimulus='connected']")
+ fill_in("naming_name", with: "Agaricus campestris")
+ assert_field("naming_name", with: "Agaricus campestris")
+ select(Vote.confidence(Vote.next_best_vote), from: "naming_vote_value")
+ assert_select("naming_vote_value",
+ selected: Vote.confidence(Vote.next_best_vote))
within("#observation_form") { click_commit }
- # It should take us to create a new location
- assert_selector("body.locations__new")
- # The observation shoulda been created OK.
- assert_flash_for_create_observation
- # Check the db values
- assert_new_observation_is_correct(expected_values_after_create)
-
- # check default values of location form
- assert_field("location_display_name", with: "Pasadena, California, USA")
- assert_button(text: :form_locations_find_on_map.t.as_displayed)
- click_button(:form_locations_find_on_map.t.as_displayed)
- sleep(1)
- assert_equal(PASADENA_EXTENTS[:north].round(4),
- find("#location_north").value.to_f.round(4))
- assert_equal(PASADENA_EXTENTS[:south].round(4),
- find("#location_south").value.to_f.round(4))
- assert_equal(PASADENA_EXTENTS[:east].round(4),
- find("#location_east").value.to_f.round(4))
- assert_equal(PASADENA_EXTENTS[:west].round(4),
- find("#location_west").value.to_f.round(4))
- sleep(1) # wait for elevation service
- assert_equal(PASADENA_EXTENTS[:high].round(4),
- find("#location_high").value.to_f.round(4))
- assert_equal(PASADENA_EXTENTS[:low].round(4),
- find("#location_low").value.to_f.round(4))
-
- # submit_location_form_with_errors
- fill_in("location_display_name",
- with: "Pasadena: Disneyland, Some Co., California, USA")
- fill_in("location_notes", with: "oops")
-
- within("#location_form") { click_commit }
-
- assert_selector("body.locations__create")
- assert_has_location_warning(/Contains unexpected character/)
-
- assert_field("location_display_name",
- with: "Pasadena: Disneyland, Some Co., California, USA")
- assert_field("location_notes", with: "oops")
-
- # submit_location_form_without_errors
- fill_in("location_display_name",
- with: "Pasadena, Some Co., California, USA")
- fill_in("location_notes", with: "Notes for location")
-
- within("#location_form") { click_commit }
-
assert_flash_for_create_location
assert_selector("body.observations__show")
- # https://gorails.com/episodes/rails-system-testing-file-uploads
- #
- # attach_file "user[avatar]", file_fixture("avatar.jpg")
- # find(".dropzone").drop File.join(file_fixture_path, "avatar.jpg")
-
assert_new_location_is_correct(expected_values_after_location)
assert_new_observation_is_correct(expected_values_after_location)
assert_show_observation_page_has_important_info
- # open_edit_observation_form
- # This is more robust in case the link becomes an icon:
+ # Open edit observation form
+ # class selector is more robust in case the link becomes an icon:
new_obs = Observation.last
first(class: "edit_observation_link_#{new_obs.id}").trigger("click")
# click_link("Edit Observation")
@@ -480,18 +471,15 @@ def test_post_edit_and_destroy_with_details_and_location
assert_field("observation_when_1i", with: "2010")
assert_select("observation_when_2i", text: "August")
assert_select("observation_when_3i", text: "14")
- assert_field("observation_place_name",
- with: "Pasadena, Some Co., California, USA")
- assert_field("observation_lat", with: "12.6125") # was 12.5927
- assert_field("observation_lng", with: "121.5523") # was -121.5525
- assert_field("observation_alt", with: "17")
+ assert_field("observation_place_name", with: SOUTH_PASADENA[:name])
+ assert_image_gps_copied_to_obs(SO_PASA_EXIF)
assert_unchecked_field("observation_is_collection_location")
- assert_checked_field("observation_specimen")
- assert_field(other_notes_id, with: "Notes for observation")
+ assert_checked_field("observation_specimen", visible: :all)
+ assert_field(other_notes_id, with: "Notes for observation", visible: :all)
imgs = Image.last(2)
cci = imgs.find { |img| img[:original_name] == "Coprinus_comatus.jpg" }
- geo = imgs.find { |img| img[:original_name] == "geotagged.jpg" }
+ geo = imgs.find { |img| img[:original_name] == "geotagged_s_pasadena.jpg" }
img_ids = imgs.map(&:id)
imgs.each do |img|
assert_field("good_image_#{img.id}_when_1i",
@@ -508,20 +496,13 @@ def test_post_edit_and_destroy_with_details_and_location
assert_checked_field("thumb_image_id_#{cci.id}", visible: :all)
assert_unchecked_field("thumb_image_id_#{geo.id}", visible: :all)
- # submit_observation_form_with_changes
+ # Submit observation form with changes
obs_when = find("#observation_when_1i")
scroll_to(obs_when, align: :center)
fill_in("observation_when_1i", with: "2011")
select("April", from: "observation_when_2i")
select("15", from: "observation_when_3i")
- # this will reset the place_name field
- fill_in("observation_lat", with: "23.4567")
- fill_in("observation_lng", with: "-123.4567")
- fill_in("observation_alt", with: "987m")
- fill_in("observation_place_name",
- with: "Pasadena, Some Co., California, USA")
check("observation_is_collection_location")
- fill_in(other_notes_id, with: "New notes for observation")
img_ids.each do |img_id|
find("#carousel_thumbnail_#{img_id}").click
@@ -536,8 +517,14 @@ def test_post_edit_and_destroy_with_details_and_location
choose("thumb_image_id_#{geo.id}", visible: :all)
sleep(1)
+ # Move to the next step, Identification
+ within(step_nav_1) { click_on(:NEXT.l) }
+ sleep(1)
+
obs_notes = find("#observation_notes")
scroll_to(obs_notes, align: :top)
+ fill_in(other_notes_id, with: "New notes for observation")
+
within("#observation_form") { click_commit }
assert_selector("body.observations__show")
@@ -545,12 +532,12 @@ def test_post_edit_and_destroy_with_details_and_location
assert_edit_observation_is_correct(expected_values_after_edit)
assert_show_observation_page_has_important_info
- # make_sure_observation_is_in_log_index
+ # Make sure observation is in log index
obs = Observation.last
visit(activity_logs_path)
assert_link(href: %r{/#{obs.id}?})
- # destroy_observation
+ # Destroy observation
visit(observation_path(obs.id))
new_obs = Observation.last
assert_selector("body.observations__show")
@@ -560,12 +547,80 @@ def test_post_edit_and_destroy_with_details_and_location
assert_flash_for_destroy_observation
assert_selector("body.observations__index")
- # make_sure_observation_is_not_in_log_index
+ # Make sure observation is not in log index
visit(activity_logs_path)
assert_no_link(href: %r{/#{obs.id}/})
assert_link(href: /activity_logs/, text: /Agaricus campestris/)
end
+ ##############################################################################
+ # Helper methods
+ #
+
+ # This image only has a date.
+ COPRINUS_COMATUS_EXIF = {
+ year: 2006,
+ month: 11,
+ day: 20
+ }.freeze
+
+ # The geotagged.jpg is from University Park, Florida.
+ UNIVERSITY_PARK = {
+ name: "University Park, Miami-Dade Co., Florida, USA",
+ north: 25.762050,
+ south: 25.733291,
+ east: -80.351868,
+ west: -80.385170
+ }.freeze
+
+ # The image geotagged.jpg has this data.
+ GEOTAGGED_EXIF = {
+ lat: 25.7582,
+ lng: -80.3731,
+ alt: 4,
+ year: 2018,
+ month: 12,
+ day: 31
+ }.freeze
+
+ # Google seems to give accurate bounds to this place, but the
+ # geometry.location_type of "Pasadena, California" is "APPROXIMATE".
+ # Viewport and bounds are separate fields in the Geocoder response,
+ # and other places' bounds may be more precise. Viewport may be padded.
+ # On the right may be the accurate extents, they're hard to find.
+ PASADENA_EXTENTS = {
+ north: 34.251905, # 34.1774839
+ south: 34.1170368, # 34.1275634561
+ east: -118.0654789, # -118.0989059
+ west: -118.1981391, # -118.1828198
+ high: 1096.943603515625,
+ low: 141.5890350341797,
+ lat: 34.1477849,
+ lng: -118.1445155,
+ alt: 262.5840148925781
+ }.freeze
+
+ # Current results from Google Maps API, formatted by our JS map_controller.
+ SOUTH_PASADENA = {
+ name: "South Pasadena, Los Angeles Co., California, USA",
+ north: 34.1257,
+ south: 34.0986,
+ east: -118.1345,
+ west: -118.178,
+ high: 235,
+ low: 159
+ }.freeze
+
+ # The image geotagged_s_pasadena.jpg has this data.
+ SO_PASA_EXIF = {
+ lat: 34.1231,
+ lng: -118.1489,
+ alt: 248,
+ year: 2020,
+ month: 6,
+ day: 30
+ }.freeze
+
def assert_date_is_now
local_now = Time.zone.now.in_time_zone
@@ -581,6 +636,51 @@ def assert_geolocation_is_empty
assert_field("observation_alt", with: "")
end
+ def assert_image_exif_available(image_data)
+ assert_selector('[id$="when_1i"]', visible: :all)
+ assert_selector('[id$="when_2i"]', visible: :all)
+ assert_selector('[id$="when_3i"]', visible: :all)
+ assert_equal(image_data[:year].to_s,
+ find('[id$="when_1i"]', visible: :all).value)
+ assert_equal(image_data[:month].to_s,
+ find('[id$="when_2i"]', visible: :all).value)
+ assert_equal(image_data[:day].to_s,
+ find('[id$="when_3i"]', visible: :all).value)
+ end
+
+ def assert_image_gps_copied_to_obs(image_data)
+ assert_field("observation_lat", with: image_data[:lat].to_s)
+ assert_field("observation_lng", with: image_data[:lng].to_s)
+ # We look up the alt from lat/lng, so it's not copied from the image.
+ # assert_field("observation_alt", with: image_data[:alt].to_i.to_s)
+ end
+
+ def assert_image_date_copied_to_obs(image_data)
+ assert_equal(image_data[:year].to_s,
+ find('[id$="observation_when_1i"]').value)
+ assert_equal(image_data[:month].to_s,
+ find('[id$="observation_when_2i"]').value)
+ assert_equal(image_data[:day].to_s,
+ find('[id$="observation_when_3i"]').value)
+ end
+
+ def assert_hidden_location_fields_filled(location_data)
+ assert_field("observation[location_id]", type: :hidden, with: "-1")
+ assert_field("location_north", type: :hidden,
+ with: location_data[:north].to_s)
+ assert_field("location_south", type: :hidden,
+ with: location_data[:south].to_s)
+ assert_field("location_west", type: :hidden,
+ with: location_data[:west].to_s)
+ assert_field("location_east", type: :hidden,
+ with: location_data[:east].to_s)
+ # Will be waiting on a call to the elevation service. Maybe ready later.
+ # assert_field("location_low", type: :hidden,
+ # with: location_data[:low].to_s)
+ # assert_field("location_high", type: :hidden,
+ # with: location_data[:high].to_s)
+ end
+
# Rename from new_observation to just observation ***
def assert_edit_observation_is_correct(expected_values)
assert_edit_observation_has_correct_data(expected_values)
@@ -631,7 +731,8 @@ def assert_observation_has_correct_location(expected_values)
end
assert_gps_equal(expected_values[:lat], new_obs.lat.to_f)
assert_gps_equal(expected_values[:lng], new_obs.lng.to_f)
- assert_gps_equal(expected_values[:alt], new_obs.alt.to_f)
+ # We look up the alt from lat/lng, so it's not copied from the image.
+ # assert_gps_equal(expected_values[:alt], new_obs.alt.to_f)
end
def assert_observation_has_correct_name(expected_values)
@@ -724,11 +825,11 @@ def expected_values_after_create
{
user: katrina,
when: Date.parse("2010-08-14"),
- where: "Pasadena, California, USA",
+ where: SOUTH_PASADENA[:name],
location: nil,
- lat: 12.6125, # was 12.5760 values tweaked to move it to land
- lng: 121.5523, # was -123.7519 was in the ocean
- alt: 17,
+ lat: SO_PASA_EXIF[:lat],
+ lng: SO_PASA_EXIF[:lng],
+ alt: SO_PASA_EXIF[:alt],
name: names(:agaricus_campestris),
vote: Vote.next_best_vote,
is_collection_location: false,
@@ -742,13 +843,13 @@ def expected_values_after_create
def expected_values_after_location
expected_values_after_create.merge(
where: nil,
- location: "Pasadena, Some Co., California, USA",
- north: PASADENA_EXTENTS[:north],
- south: PASADENA_EXTENTS[:south],
- east: PASADENA_EXTENTS[:east],
- west: PASADENA_EXTENTS[:west],
- high: 5678,
- low: 1234,
+ location: SOUTH_PASADENA[:name],
+ north: SOUTH_PASADENA[:north],
+ south: SOUTH_PASADENA[:south],
+ east: SOUTH_PASADENA[:east],
+ west: SOUTH_PASADENA[:west],
+ high: SOUTH_PASADENA[:high],
+ low: SOUTH_PASADENA[:low],
location_notes: "Notes for location"
)
end
@@ -756,14 +857,16 @@ def expected_values_after_location
def expected_values_after_edit
expected_values_after_location.merge(
when: Date.parse("2011-04-15"),
- lat: 23.4567,
- lng: -123.4567,
- alt: 987,
+ # lat: 23.4567,
+ # lng: -123.4567,
+ # alt: 987,
is_collection_location: true,
specimen: false,
notes: "New notes for observation", # displayed in observations/show
image_notes: "New notes for image",
- thumb_image_id: Image.find_by(original_name: "geotagged.jpg").id
+ thumb_image_id: Image.find_by(
+ original_name: "geotagged_s_pasadena.jpg"
+ ).id
)
end
end