- {{ wellObj.run_name }} |
+ {{ wellObj.run_name }} |
{
+ test('Component is "folded" by default', () => {
+ expect(wrapper.getComponent('transition-stub').attributes()['appear']).toEqual('false')
+ })
+
+ test('Coefficient of variance showing', async () => {
+ let topStat = wrapper.find('p')
+ await topStat.trigger('focus')
+ expect(topStat.classes('el-tooltip__trigger')).toBeTruthy()
+
+ expect(topStat.text()).toEqual('Coefficient of Variance: 47.2')
+ })
+
+ test('Table looks about right', () => {
+ let rows = wrapper.findAll('tr')
+ expect(rows.length).toEqual(3)
+
+ // Check tag 1 has been set
+ expect(rows[1].find('td').text()).toEqual('TTTTTTTT')
+ expect(rows[2].find('td').text()).toEqual('GGGGGGGG')
+ })
+})
\ No newline at end of file
diff --git a/frontend/src/components/__tests__/QcView.spec.js b/frontend/src/components/__tests__/QcView.spec.js
index 9d9530f..066e2c1 100644
--- a/frontend/src/components/__tests__/QcView.spec.js
+++ b/frontend/src/components/__tests__/QcView.spec.js
@@ -6,6 +6,11 @@ import QcView from '../QcView.vue';
describe('Component renders', () => {
+ // Supply PoolStats element with some data
+ fetch.mockResponse(
+ JSON.stringify({})
+ )
+
afterEach(async () => {
cleanup()
});
diff --git a/frontend/src/utils/__tests__/langqc.spec.js b/frontend/src/utils/__tests__/langqc.spec.js
index a1fc14d..eefe81d 100644
--- a/frontend/src/utils/__tests__/langqc.spec.js
+++ b/frontend/src/utils/__tests__/langqc.spec.js
@@ -95,6 +95,9 @@ describe('Example fake remote api call', () => {
client.getWellsForRunPromise('blah')
expect(fetch.mock.calls[6][0]).toEqual('/api/pacbio/run/blah?page_size=100&page=1')
+
+ client.getPoolMetrics('A12345');
+ expect(fetch.mock.calls[7][0]).toEqual('/api/pacbio/products/A12345/seq_level/pool')
});
});
diff --git a/frontend/src/utils/langqc.js b/frontend/src/utils/langqc.js
index 2e315b5..daf8857 100644
--- a/frontend/src/utils/langqc.js
+++ b/frontend/src/utils/langqc.js
@@ -118,4 +118,10 @@ export default class LangQc {
}
)
}
+
+ getPoolMetrics(id_product) {
+ // Use the product metrics endpoint to get additional metrics
+ // for a well.
+ return this.fetchWrapper(this.buildUrl(['products', id_product, 'seq_level', 'pool']));
+ }
}
diff --git a/frontend/src/views/__tests__/WellsByRun.spec.js b/frontend/src/views/__tests__/WellsByRun.spec.js
index fa1991e..828ae60 100644
--- a/frontend/src/views/__tests__/WellsByRun.spec.js
+++ b/frontend/src/views/__tests__/WellsByRun.spec.js
@@ -136,8 +136,9 @@ describe('Does it work?', async () => {
test('Click a well selection, QC View appears (because URL alters)', async () => {
// Not providing precisely the right data, but serves for the component
- fetch.mockResponseOnce(
- JSON.stringify(secondaryRun)
+ fetch.mockResponses(
+ [JSON.stringify(secondaryRun)], // well QC data loading
+ [JSON.stringify({})] // Pool stats loading
)
let buttons = wrapper.findAll('button')
@@ -168,16 +169,15 @@ describe('Does it work?', async () => {
]
)
await wrapper.setProps({runName: ['TRACTION-RUN-211', 'TRACTION-RUN-210']})
+ await flushPromises()
- test('Table now contains wells from both runs', () => {
- const table = wrapper.get('table')
- expect(table.exists()).toBe(true)
+ const table = wrapper.get('table')
+ expect(table.exists()).toBe(true)
- expect(table.find('TRACTION-RUN-211').exists()).toBe(true)
- expect(table.find('TRACTION-RUN-210').exists()).toBe(true)
+ expect(table.find("td#TRACTION-RUN-211").exists()).toBe(true)
+ expect(table.find("td#TRACTION-RUN-210").exists()).toBe(true)
- const rows = table.findAll('tr')
- expect(rows.length).toEqual(4)
- })
+ const rows = table.findAll('tr')
+ expect(rows.length).toEqual(4)
})
})
diff --git a/lang_qc/endpoints/pacbio_well.py b/lang_qc/endpoints/pacbio_well.py
index eea981a..e72e7c9 100644
--- a/lang_qc/endpoints/pacbio_well.py
+++ b/lang_qc/endpoints/pacbio_well.py
@@ -225,17 +225,17 @@ def get_seq_metrics(
status.HTTP_409_CONFLICT: {"description": "Missing or incomplete LIMS data"},
status.HTTP_422_UNPROCESSABLE_ENTITY: {"description": "Invalid product ID"},
},
- response_model=QCPoolMetrics,
+ response_model=QCPoolMetrics | None,
)
def get_product_metrics(
id_product: PacBioWellSHA256, mlwhdb_session: Session = Depends(get_mlwh_db)
-) -> QCPoolMetrics:
+) -> QCPoolMetrics | None:
mlwh_well = _find_well_product_or_error(id_product, mlwhdb_session)
try:
metrics = QCPoolMetrics(db_well=mlwh_well)
- except MissingLimsDataError as err:
- raise HTTPException(409, detail=str(err))
+ except MissingLimsDataError:
+ return
return metrics
diff --git a/lang_qc/models/pacbio/qc_data.py b/lang_qc/models/pacbio/qc_data.py
index 6aa6a0a..ca29192 100644
--- a/lang_qc/models/pacbio/qc_data.py
+++ b/lang_qc/models/pacbio/qc_data.py
@@ -173,7 +173,7 @@ class SampleDeplexingStats(BaseModel):
tag1_name: str | None
tag2_name: str | None
deplexing_barcode: str | None
- hifi_read_bases: int | None
+ hifi_read_bases: float | None = Field(title="HiFi read bases (Gb)")
hifi_num_reads: int | None
hifi_read_length_mean: float | None
hifi_bases_percent: float | None
@@ -208,7 +208,7 @@ def pre_root(cls, values: dict[str, Any]) -> dict[str, Any]:
if well is None:
raise ValueError(f"None {db_well_key_name} value is not allowed.")
- cov: float = None
+ cov: float | None = None
sample_stats = []
if well.demultiplex_mode and "Instrument" in well.demultiplex_mode:
@@ -227,21 +227,21 @@ def pre_root(cls, values: dict[str, Any]) -> dict[str, Any]:
cov = None
else:
hifi_reads = [prod.hifi_num_reads for prod in product_metrics]
- cov = stdev(hifi_reads) / mean(hifi_reads) * 100
+ cov = round(stdev(hifi_reads) / mean(hifi_reads) * 100, 2)
- for (i, prod) in enumerate(product_metrics):
+ for i, prod in enumerate(product_metrics):
sample_stats.append(
SampleDeplexingStats(
id_product=prod.id_pac_bio_product,
tag1_name=lib_lims_data[i].tag_identifier,
tag2_name=lib_lims_data[i].tag2_identifier,
deplexing_barcode=prod.barcode4deplexing,
- hifi_read_bases=prod.hifi_read_bases,
+ hifi_read_bases=convert_to_gigabase(prod, "hifi_read_bases"),
hifi_num_reads=prod.hifi_num_reads,
hifi_read_length_mean=prod.hifi_read_length_mean,
hifi_bases_percent=prod.hifi_bases_percent,
percentage_total_reads=(
- prod.hifi_num_reads / well.hifi_num_reads * 100
+ round(prod.hifi_num_reads / well.hifi_num_reads * 100, 2)
if (well.hifi_num_reads and prod.hifi_num_reads)
else None
),
diff --git a/tests/fixtures/sample_data.py b/tests/fixtures/sample_data.py
index e86fbb5..436cc67 100644
--- a/tests/fixtures/sample_data.py
+++ b/tests/fixtures/sample_data.py
@@ -59,9 +59,9 @@ def simplex_run(request, mlwhdb_test_session):
tags=tag1,
).hash_product_id(),
qc=1,
- hifi_read_bases=900,
+ hifi_read_bases=90000000,
hifi_num_reads=10,
- hifi_read_length_mean=90,
+ hifi_read_length_mean=9000000,
barcode_quality_score_mean=34,
hifi_bases_percent=90.001,
pac_bio_run_well_metrics=well_metrics_a1,
@@ -148,9 +148,9 @@ def multiplexed_run(mlwhdb_test_session):
tags=tag1,
).hash_product_id(),
qc=1,
- hifi_read_bases=900,
+ hifi_read_bases=90000000,
hifi_num_reads=20,
- hifi_read_length_mean=45,
+ hifi_read_length_mean=4500000,
barcode_quality_score_mean=34,
hifi_bases_percent=90.001,
pac_bio_run_well_metrics=well_metrics_b1,
@@ -180,9 +180,9 @@ def multiplexed_run(mlwhdb_test_session):
tags=tag1_2,
).hash_product_id(),
qc=1,
- hifi_read_bases=100,
+ hifi_read_bases=10000000,
hifi_num_reads=10,
- hifi_read_length_mean=10,
+ hifi_read_length_mean=1000000,
barcode_quality_score_mean=34,
hifi_bases_percent=100.00,
pac_bio_run_well_metrics=well_metrics_b1,
diff --git a/tests/test_pac_bio_qc_data_well.py b/tests/test_pac_bio_qc_data_well.py
index 772a9cb..fb83be2 100644
--- a/tests/test_pac_bio_qc_data_well.py
+++ b/tests/test_pac_bio_qc_data_well.py
@@ -132,19 +132,19 @@ def test_pool_metrics_from_well(mlwhdb_test_session, multiplexed_run):
for metrics in [metrics_via_db, metrics_direct]:
assert (
int(metrics.pool_coeff_of_variance) == 47
- ), "Variance between 20 and 10 is ~47%"
+ ), "Variance between 20 reads and 10 reads is ~47%"
- assert metrics.products[0].hifi_read_bases == 100
+ assert metrics.products[0].hifi_read_bases == 0.01
assert (
- metrics.products[1].hifi_read_bases == 900
- ), "hifi read base counts are faithfully copied"
+ metrics.products[1].hifi_read_bases == 0.09
+ ), "hifi read base counts are scaled to Gigabases"
assert (
- int(metrics.products[0].percentage_total_reads) == 33
- ), "10 of 30 reads is 33.3%"
+ metrics.products[0].percentage_total_reads == 33.33
+ ), "10Mb of 30Mb reads is 33.33% (2 d.p.)"
assert (
- int(metrics.products[1].percentage_total_reads) == 66
- ), "20 of 30 reads is 66.6%"
+ metrics.products[1].percentage_total_reads == 66.67
+ ), "20Mb of 30Mb reads is 66.67% (2 d.p.)"
def test_errors_instantiating_pool_metrics(mlwhdb_test_session):
|