Add a metadata field, with feature and unit tests - RepoCamp/ohsu2018 GitHub Wiki
Goals
Setup
(OPTIONAL) Save your current changes
If you have changes in your current branch -- you can check on this via git status
-- you'll want to save those before starting this lesson (which uses a separate branch):
git checkout -b work_in_progress
git add .
git commit -m 'checkpoint before beginning first metadata lesson'
Check out working branch
git checkout lesson_5_start
NOTE: If you make experimental changes and want to get back to the minimal code state necessary to run this lesson, you can check the starting code out again using:
git checkout lesson_5_start
Lesson
Analyze a feature spec for adding a Work
- Observe the following test scenario in
spec/features/create_work_spec.rb
:scenario do visit '/dashboard' click_link "Works" click_link "Add new work" # If you generate more than one work uncomment these lines # choose "payload_concern", option: "Work" # click_button "Create work" expect(page).to have_content "Add New Work" click_link "Files" # switch tab expect(page).to have_content "Add files" expect(page).to have_content "Add folder" within('span#addfiles') do attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/image.jp2", visible: false) attach_file("files[]", "#{Hyrax::Engine.root}/spec/fixtures/jp2_fits.xml", visible: false) end click_link "Descriptions" # switch tab fill_in('Title', with: 'My Test Work') fill_in('Creator', with: 'Doe, Jane') fill_in('Keyword', with: 'testing') select('In Copyright', from: 'Rights statement') # With selenium and the chrome driver, focus remains on the # select box. Click outside the box so the next line can't find # its element find('body').click choose('work_visibility_open') expect(page).to have_content('Please note, making something visible to the world (i.e. marking this as Public) may be viewed as publishing which could impact your ability to') check('agreement') click_on('Save') expect(page).to have_content('My Test Work') expect(page).to have_content "Your files are being processed by Hyrax in the background." end
- This feature test interacts with the browser. Try to do these things in the browser. Will this test pass?
- Run your test suite:
OR Run your feature test by itself:rails ci
- Start the test environment:
rake hydra:test_server
- Run just the test you want to focus on:
rspec spec/features/create_work_spec.rb
- Start the test environment:
Add a metadata field
A Work, in addition to title, creator, keyword, and the metadata fields that are common to all Hyrax objects, also has some special Work metadata. For our work, we need to know the year, extent (number of pages, or length of media), and referenced resources associated with this document. Because Fedora 4 stores content as linked data, we need to know not only the name of the field we want to add, but also the linked data predicate we should use. In this example, we're going to add:
- year: http://www.europeana.eu/schemas/edm/year
- references: http://purl.org/dc/terms/references
- extent: http://purl.org/dc/terms/extent
Add a new metadata field to our feature spec
- Add these lines to
spec/features/create_work_spec.rb
:
click_link("Additional fields")
fill_in "Year", with: "2005"
- Run your test suite again. It will fail with the error:
$ rails ci # or rails spec
Failure/Error: fill_in 'Year', with: '2005'
Capybara::ElementNotFound
Unable to find visible field "Year" that is not disabled
Add a new metadata field to our model
Recall that Rails uses the MVC (model/view/controller) pattern. In order to add a field to our Work object, we first need to add it to the Work model.
So far we've only been writing feature specs, also sometimes called integration tests.
These are a kind of automated test that exercises many parts of the application at once.
For example, our create_work_spec
feature is testing whether:
- we can create a user and log in
- a logged in user can access the new Work url
- the expected fields are present on that page
- a file can be attached
- a Work can be submitted without error given a set up metadata and a file
- a new page will be displayed saying the Work has been submitted
- that new page will contain the expected metadata
In contrast, we are now going to write a unit test, which will only test one thing: Whether the Work model has a year field.
- Open
spec/models/work_spec.rb
. Notice that this is a stub test that was auto-generated when we created our Work work type. Replace lines 6 - 8 (the bits inside theRSpec.describe
block) with this:
describe "#year" do
context "with a new Work" do
it "has no year value when it is first created" do
work = Work.new
expect(work.year).to be_empty
end
end
context "with a Work that has a year defined" do
it "can set and retrieve a year value" do
work = Work.new
work.year = ["2005"]
expect(work.year).to eq(["2005"])
end
end
end
- Run your test suite again. Now you have three failing tests! Our unit tests are
failing with an error something like
method_missing: undefined method 'year'
- Edit
app/models/work.rb
and add this line at the bottom of the class block, but before the line that saysinclude ::Hyrax::BasicMetadata
:
property :year, predicate: "http://www.europeana.eu/schemas/edm/year"
- Run your test suite again. Now your unit test should pass. However, your feature test is still failing.
Pair exercise
We added one metadata field here: year. As a pair, start from Setup
and get your unit tests passing for this field.
Then: choose either extent or references and add a second metadata field. Or, define your own metadata field (pick something where the value can be a simple string).
For discussion:
- Compare this with entering the same information manually into our local development environment.
- What is a fixture?
- Why do we have feature tests and unit tests?
- What is Capybara?
Add a new metadata field to our form
At this point, our Work model has the field we want to add but that field isn't being shown on our new Work form.
- As before, we will add our test first. Edit
spec/forms/hyrax/work_form_spec.rb
and replace the parts inside theRspec.describe
block with:
subject { form }
let(:work) { Work.new }
let(:ability) { Ability.new(nil) }
let(:request) { nil }
let(:form) { described_class.new(work, ability, request) }
it "has the expected terms" do
expect(form.terms).to include(:title)
expect(form.terms).to include(:year)
end
- Run your test suite and notice that the work_form_spec is now failing:
Failure/Error: expect(form.terms).to include(:year)
- Edit
app/forms/hyrax/work_form.rb
and add this line:
self.terms += [:year]
- Run your test suite again (
rails ci
) and all your tests, including your feature test, should now pass.
Note: You can see all the changes made during this exercise on the github repo.
Pair exercise (time allowing)
Add your additional metadata field to the form. Be sure to include feature and unit tests.
For discussion:
- How are the model test and the form test different? How are they the same?
- This lesson represents a realistic use case. Let's look at a related ticket in our issue tracker.
- What makes a good ticket?
- How do metadata decisions get made?
- How do you track them? See, e.g., this spreadsheet from the Metadata Interest Working Group