Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Y24-149 exhaust samples moved to destroyed location #2121

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from

Conversation

seenanair
Copy link
Contributor

@seenanair seenanair commented Dec 16, 2024

Closes #1780

Changes proposed in this pull request

  • Exhaust library volumes for all barcodes scanned to destroyed location

Instructions for Reviewers

[All PRs] - Confirm PR template filled
[Feature Branches] - Review code
[Production Merges to main]
    - Check story numbers included
    - Check for debug code
    - Check version

Copy link
Collaborator

@BenTopping BenTopping left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start, couple questions.

Do we have some way in Traction UI of representing exhausted libraries. Is an exhausted library just one thats volume equals its used_volume or does it also have to be destroyed? Might be useful to have an exhausted badge or something?

src/services/labwhere/client.js Show resolved Hide resolved

async fetchLibraries(filterOptions) {
const { success, data, meta, errors, libraries, tubes, tags, requests } =
await fetchLibraries({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this naming should be changed so its clear this isnt a recursive function.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What decides whether a method goes in utilities or goes into the store? I normally consider utilities as data formatting, etc but some of these make requests to the service as well. Not sure whether that belongs better in the store or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the primary aim is to enable methods that format data, specifically those requiring additional information, to return the expected data. For example, the librariesArray method requires tubes, requests, and tags to return the information it expects. Splitting these into separate utility functions allows for easier unit testing locally, as it is much trickier to test this functionality using the factory.

I have splitted other methods based on how they are reused across different parts of the application. For instance, fetching libraries is used within the store, but it is also required in other places that do not need to rely on the store method or store state. By splitting it out, these methods can operate independently. Fetching can now be done outside the store, and the same method can be used within store to set store values as needed.

Another approach could have been to split these internally into two separate methods within the store - one method explicitly to fetch information and another method that uses this method to set the store state. However, I felt that separating them into utilities makes the logic clearer and keeps the fetchLibraries method more generic.

Hope it makes sense. Please share your thoughts.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth a general review to set a standard so we know where to put stuff.

We do have situations where we have calls to the service outside the store but maybe we should think about moving all calls to services in the services folder and standardising naming to remove any ambiguity.

location_barcode.value,
uniqueBarcodesArray.value,
)
if (success && exhaustedLibraries.length > 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message formatting should probably be handled by exhaustLibraryVolumeIfDestroyed as exhaustedLibraries are only used for the message.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I have noticed this pattern where we are checking the length as well as success. It seems pertinent to move it handle response with a flag e.g. hasData.

@seenanair
Copy link
Contributor Author

Good start, couple questions.

Do we have some way in Traction UI of representing exhausted libraries. Is an exhausted library just one thats volume equals its used_volume or does it also have to be destroyed? Might be useful to have an exhausted badge or something?

I thought the same.
At present, there is no representation of exhausted libraries.
It would be good

  • to have an indication to show whether a library is exhausted and
  • to disable or doesn't allow editing the volume for exhausted libraries, as it doesn’t make sense to allow it again.

stevieing
stevieing previously approved these changes Dec 18, 2024
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth a general review to set a standard so we know where to put stuff.

We do have situations where we have calls to the service outside the store but maybe we should think about moving all calls to services in the services folder and standardising naming to remove any ambiguity.

location_barcode.value,
uniqueBarcodesArray.value,
)
if (success && exhaustedLibraries.length > 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I have noticed this pattern where we are checking the length as well as success. It seems pertinent to move it handle response with a flag e.g. hasData.

} from '@/stores/utilities/pacbioLibraries.js'
import PacbioLibraryFactory from '@tests/factories/PacbioLibraryFactory.js'
import { beforeEach, describe, expect, it } from 'vitest'
import { libraryPayload } from '../../../../src/stores/utilities/pacbioLibraries'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a file type to pacbioLibraries?

@seenanair seenanair marked this pull request as draft January 6, 2025 11:27
@seenanair seenanair marked this pull request as ready for review January 6, 2025 16:15
Copy link
Collaborator

@stevieing stevieing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added lots of advisory comments.

I struggled a bit to understand what was going on as there is a lot of mocking.

I don't think these comments should stop deployment from branch if it is working.

VITE_ENVIRONMENT=development
VITE_DESTROYED_LOCATION_BARCODE=lw-destroyed-217
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are youn planning to add the destroyed location to the deployment project or just the .env files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already added in deployment project https://github.com/sanger/deployment/pull/533

@@ -2,7 +2,8 @@ VITE_TRACTION_BASE_URL=http://traction
VITE_TRACTION_GRAPHQL_URL=http://traction/graphql
VITE_PRINTMYBARCODE_BASE_URL=http://printmybarcode
VITE_SAMPLEEXTRACTION_BASE_URL=http://sampleextraction
VITE_LABWHERE_BASE_URL=http://labwhere
VITE_LABWHERE_BASE_URL=http://localhost:3003
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to do this in .env.development.local

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an e2e test to check for volume exhaustion when the entered location barcode matches the destroyed location barcode, as specified in the corresponding .env file. This test will fail during CI if the correct configuration is not set. Is there are any better approaches to handle this scenario?

Copy link
Collaborator

@stevieing stevieing Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok. That is a problem. How does it work for all of our other api calls. We don't set traction url to a real one? It sounds like the intercept is not being handled correctly maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we are simply comparing the entered barcode with the value of the environment variable read within the method. I think this is different from other cases where we can intercept commands to mock network requests and responses, eliminating the need for the real ones. I tried various approaches, such as using Cypress config to define a value, but it didn't work

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand now. It is the barcode you are checking which is why it needs to be in .env

exhaustLibrayVolume,
formatAndTransformLibraries,
} from '@/stores/utilities/pacbioLibraries.js'
import { getPacbioLibraryResources } from '@/services/traction/PacbioLibrary.js'

const labwhereFetch = FetchWrapper(import.meta.env['VITE_LABWHERE_BASE_URL'], 'LabWhere')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Advisory: Creating the variables like this rather than using dependency injection makes it more difficult to test which is why you need to mock fetch globally I think!

A different way to do it would be to pass a type into the function which could have the various bits of configuration.

describe('client', () => {
const mockFetch = vi.fn()
const labwhereLocationsFactory = LabwhereLocationsFactory()
beforeEach(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I am referring to above.

We are essentially mocking fetch globally because of what we are doing in the client.

]

beforeEach(() => {
vi.clearAllMocks()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure what is going on but would be slightly concerned that we are pretty much mocking all of the functions. It would be good to know why. This could create technical debt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ones you mentioned are not included as part of this PR.
The current implementation of the LabWhere client methods and FetchWrapper directly calls the fetch API to interact with LabWhere services. I believe this approach was taken because the LabWhere APIs do not always return JSON responses, and the client methods are designed as wrappers around these APIs to handle various response formats and content types.
These methods are globally mocked since all exported methods involve calling LabWhere, and the tests need to simulate different response formats for different methods. As you mentioned, it could likely be rewritten to pass in a fetch function, allowing tests to be written without relying on global mocking.

@seenanair seenanair requested a review from stevieing January 7, 2025 15:25
Copy link
Collaborator

@stevieing stevieing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice piece of work.

I think we could also use dependency injection for the destroyed location barcode and turn it into a type but I think you have done more than enough on this for now. There will be more work on location tracking so we can look again in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants