Skip to content

Commit

Permalink
Merge pull request #1940 from sanger/develop
Browse files Browse the repository at this point in the history
[automated] Merge Develop into Master
  • Loading branch information
StephenHulme authored Sep 20, 2024
2 parents db02507 + ea5e742 commit dac2eb4
Show file tree
Hide file tree
Showing 127 changed files with 2,337 additions and 2,032 deletions.
2 changes: 1 addition & 1 deletion .release-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.59.2
3.59.3
58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,68 @@ There are a few tools available to assist with writing specs:

- Helpers: `with_has_many_associations` and `with_belongs_to_associations` can be used in factories to set up the relevant json. They won't actually mock up the relevant requests, but ensure that things like actions are defined so that the api knows where to find them.

#### Request stubbing
#### Request stubbing for the Sequencescape v1 API

Request stubs are provided by webmock. Two helper methods will assist with the majority of mocking requests to the api, `stub_api_get` and `stub_api_post`. See `spec/support/api_url_helper.rb` for details.

**Note**: Due to the way the api functions, the factories don't yet support nested associations.

#### Request stubbing for the Sequencescape v2 API

The V2 API uses `JsonApiClient::Resource` sub-classes to represent the records in memory.
Generally these are quite dynamic so you don't need to explicitly specify every property the API will respond with.
The base class also provides us with methods that are familiar to Rails for finding one or more records that match criteria.
So to stub the API, the easiest thing to do is to get FactoryBot to make up resources using the specific resource sub-class for the V2 API, and then mock the calls to those lookup methods.
Many of these have already been done for you in `spec/support/api_url_helper.rb` such as `stub_v2_study` and `stub_v2_tag_layout_templates` which sets up the `find` method for studies by name and the `all` method for tag layout templates, respectively.
However there's also `stub_api_v2_post`, `stub_api_v2_patch` and `stub_api_v2_save` which ensures that any calls to the `create`, `update` and the `save` method for resources of a particular type are expected and give a return value.
If none of the existing method suit your needs, you should add new ones.

##### FactoryBot is not mocking my related resources correctly

Nested relationships, such as Wells inside a Plate, the resource should indicate this with keywords like `has_one`, `has_many`, `belongs_to`, etc.
See the [json_api_client repository](https://github.com/JsonApiClient/json_api_client) for this topic and more.
However, FactoryBot does not get on well with some of these relationship methods and will not mock them properly using standard FactoryBot definitions.

If you find that FactoryBot is not giving you the expected resource for a related record, you can inject the related resource directly into the `JsonApiClient::Resource`'s cache of relationships.
To do that, define the related resource as a `transient` variable and use an `after(:build)` block to assign the resource to the `_cached_relationship` method.
For example, where the Resource might be defined as the following class:

```ruby
class Sequencescape::Api::V2::RootRecord < JsonApiClient::Resource
has_one :related_thing
end
```

You might expect to be able to use FactoryBot in the following way:

```ruby
FactoryBot.define do
factory :root_record, class: Sequencescape::Api::V2::RootRecord do
skip_create

related_thing { create :related_thing }
end
end
```

But the related thing will not be the one you defined to be generated by another factory.
It appears the `has_one` method in the resource over-rides the mocked value and you get an empty record back instead.
So, instead, you should create the `related_thing` record as a transient and assign it to the `root_record` in an `after(:build)` block as shown here.

```ruby
FactoryBot.define do
factory :root_record, class: Sequencescape::Api::V2::RootRecord do
skip_create

transient { related_thing { create :v2_tag_group_with_tags } }

after(:build) do |record, factory|
record._cached_relationship(:related_thing) { factory.related_thing } if evaluator.related_thing
end
end
end
```

#### Feature debugging

To help with debugging feature specs, temporarily comment out the line `options.add_argument('--headless')` in `spec/spec_helper.rb`. This will allow you to see the browser as the tests run. To pause the execution at certain point, possibly before an expected failure, insert `binding.pry` at the appropriate place in the spec.
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/labware_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ def locate_labware
end

def find_printers
@printers = api.barcode_printer.all
@printers = Sequencescape::Api::V2::BarcodePrinter.all
end

def state_changer_for(purpose_uuid, labware_uuid)
StateChangers.lookup_for(purpose_uuid).new(api, labware_uuid, current_user_uuid)
end

def presenter_for(labware)
Presenters.lookup_for(labware).new(api: api, labware: labware)
Presenters.lookup_for(labware).new(labware: labware)
end
end
10 changes: 5 additions & 5 deletions app/controllers/plates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ def fail_wells # rubocop:todo Metrics/AbcSize
notice: 'No wells were selected to fail' # rubocop:todo Rails/I18nLocaleTexts
)
else
api.state_change.create!(
user: current_user_uuid,
target: params[:id],
Sequencescape::Api::V2::StateChange.create!(
contents: wells_to_fail,
target_state: 'failed',
customer_accepts_responsibility: params[:customer_accepts_responsibility],
reason: 'Individual Well Failure',
customer_accepts_responsibility: params[:customer_accepts_responsibility]
target_state: 'failed',
target_uuid: params[:id],
user_uuid: current_user_uuid
)
redirect_to(
limber_plate_path(params[:id]),
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/print_jobs_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def print_job_params
def find_printer_from_name
# there's bound to be a better way of doing this, so we don't have to
# requery all the printers here to find the right one
printers = api.barcode_printer.all
printers = Sequencescape::Api::V2::BarcodePrinter.all
printers.find { |p| p.name == print_job_params[:printer_name] }
end
end
2 changes: 1 addition & 1 deletion app/controllers/robots_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def update_bed_labware_metadata(bed, robot_barcode)
#
def labware_created_with_robot(labware_barcode, robot_barcode)
LabwareMetadata
.new(api: api, user: current_user_uuid, barcode: labware_barcode)
.new(user_uuid: current_user_uuid, barcode: labware_barcode)
.update!(created_with_robot: robot_barcode)
end

Expand Down
Loading

0 comments on commit dac2eb4

Please sign in to comment.