From 3dd299a95499a3273747e73e580541853f25dd21 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Thu, 26 Oct 2023 13:17:29 -0400 Subject: [PATCH 1/3] Implemented annotation workflow for healthy controls --- components/annot-categorical.vue | 19 ++++++++++++++++++- store/index.js | 3 ++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/components/annot-categorical.vue b/components/annot-categorical.vue index 7dbd27b5..27ae06d5 100644 --- a/components/annot-categorical.vue +++ b/components/annot-categorical.vue @@ -40,6 +40,14 @@ {{ uiText.missingValueButton }} + @@ -85,7 +93,8 @@ instructions: "Annotate each unique value", missingValueButton: "Mark as missing", - saveButton: "Save Annotation" + saveButton: "Save Annotation", + isControlButton: "Mark as healthy control" } }; @@ -125,6 +134,14 @@ } }, + mounted() { + if (this.activeCategory == 'Diagnosis') { + this.exampleFields.push("isControl"); + } + + + }, + methods: { ...mapMutations([ diff --git a/store/index.js b/store/index.js index b7d53adc..c9c87dd2 100644 --- a/store/index.js +++ b/store/index.js @@ -42,7 +42,8 @@ export const state = () => ({ {label: "Social phobia", identifier: "snomed:25501002"}, {label: "Specific spelling disorder", identifier: "snomed:268738002"}, {label: "Traumatic brain injury", identifier: "snomed:127295002"}, - {label: "Visual impairment", identifier: "snomed:397540003"} + {label: "Visual impairment", identifier: "snomed:397540003"}, + {label: "Healthy Control", identifier: "ncit:C94342"} ] }, From 8d4284bbdcd7bdbeef617610a046c621b2a620cc Mon Sep 17 00:00:00 2001 From: rmanaem Date: Thu, 26 Oct 2023 13:18:23 -0400 Subject: [PATCH 2/3] Added tests for the healthy control workflow --- cypress/component/annot-categorical.cy.js | 52 ++++++++++++++++++++--- cypress/e2e/app/simple-e2etest.cy.js | 27 +++++++++++- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/cypress/component/annot-categorical.cy.js b/cypress/component/annot-categorical.cy.js index 34c1ac43..35a46e44 100644 --- a/cypress/component/annot-categorical.cy.js +++ b/cypress/component/annot-categorical.cy.js @@ -2,16 +2,16 @@ import annotCategorical from "~/components/annot-categorical.vue"; let store; - -const props = { - - activeCategory: "category1" -}; +let props; describe("Categorical annotation", () => { beforeEach(() => { + props = { + + activeCategory: "category1" + }; store = { @@ -175,4 +175,46 @@ describe("Categorical annotation", () => { propsData: props }); }); + + it("Does not display the is healthy control button when the active category is not 'Diagnosis' ", () => { + cy.mount(annotCategorical, { + computed: store.getters, + mocks: {$store: store}, + propsData: props + }); + cy.get("[data-cy='isControlButton_0']").should("not.exist"); + cy.get("[data-cy='categoricalTable']").should("not.contain", "Is Control"); + + }); + + it("Can find the is healthy control button", () => { + props.activeCategory = "Diagnosis"; + cy.mount(annotCategorical, { + computed: store.getters, + mocks: {$store: store}, + propsData: props + }); + cy.get("[data-cy='isControlButton_0']").should("be.visible"); + }); + + it("Fires the selectCategorialOption mutation with the correct payload if the is healthy control button is clicked", () => { + + // Setup + props.activeCategory = "Diagnosis"; + + cy.spy(store, "commit").as("spy"); + + cy.mount(annotCategorical, { + computed: store.getters, + mocks: {$store: store}, + propsData: props + }); + cy.get("[data-cy='isControlButton_1']").click(); + cy.get("@spy").should("have.been.calledWith", "selectCategoricalOption", { + optionValue: "ncit:C94342", + columnName: "column1", + rawValue: "HC" + }); + }); + }); diff --git a/cypress/e2e/app/simple-e2etest.cy.js b/cypress/e2e/app/simple-e2etest.cy.js index 45bd30b2..e94f7c9f 100644 --- a/cypress/e2e/app/simple-e2etest.cy.js +++ b/cypress/e2e/app/simple-e2etest.cy.js @@ -33,7 +33,8 @@ describe("End to end test using a simple UI path through the app", () => { categories: [ ["Subject ID", 1], - ["Age", 1] + ["Age", 1], + ["Diagnosis", 1] ] }; @@ -75,8 +76,9 @@ describe("End to end test using a simple UI path through the app", () => { // at least one other column must be categorized. cy.assertNextPageAccess("annotation", false); - // D. Categorize "age" as "Age" + // D. Categorize "age" as "Age" and "group" as "Diagnosis" cy.categorizeColumn("Age", p_dataset["category_columns"]["Age"][0]); + cy.categorizeColumn("Diagnosis", p_dataset["category_columns"]["Diagnosis"][0]); // Since Age and subject ID have been categorized // annotation page is no accessible. @@ -104,6 +106,18 @@ describe("End to end test using a simple UI path through the app", () => { cy.get("[data-cy='selectTransform_age']").click(); cy.get("[data-cy='selectTransform_age']").type("float{enter}"); + + // B. Click on the 'Diagnosis' tab + cy.get("[data-cy='annotation-category-tabs'] ul") + .contains("li", "Diagnosis") + .click(); + + cy.get("[data-cy='categoricalSelector_0']").type("Acute{enter}"); + cy.get("[data-cy='isControlButton_1']").type("Acute{enter}"); + cy.get("[data-cy='categoricalSelector_2']").type("Hearing{enter}"); + + + // D. Assert that next page nav and button are enabled for download page cy.assertNextPageAccess("download", true); @@ -118,6 +132,15 @@ describe("End to end test using a simple UI path through the app", () => { // B. Assert that csv file has downloaded // cy.verifyDownload(".json", { contains: true }); + + // C. Check the contents of the output + cy.task("downloads", "cypress/downloads").then(folderStateAfter => { + cy.readFile('cypress/downloads/' + folderStateAfter[folderStateAfter.length - 1]).then((fileContent) => { + expect(fileContent.group.Annotations.Levels.HC.Label).to.eq("Healthy Control"); + expect(fileContent.group.Annotations.Levels.HC.TermURL).to.eq("ncit:C94342"); + }); + }); + } } }); From 71e9410ff547cabd4153d0954a35b8494ce38530 Mon Sep 17 00:00:00 2001 From: rmanaem Date: Thu, 26 Oct 2023 13:40:32 -0400 Subject: [PATCH 3/3] Refactored getJSONOutput getter --- store/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/store/index.js b/store/index.js index c9c87dd2..10e0e463 100644 --- a/store/index.js +++ b/store/index.js @@ -49,7 +49,10 @@ export const state = () => ({ categories: { - "Subject ID": {}, + "Subject ID": { + // Added to be used as a case inside the switch statement of getJSONOutput + componentName: "participantID" + }, "Age": { componentName: "annot-continuous-values", @@ -441,7 +444,7 @@ export const getters = { columnOutput = p_getters.getContinuousJsonOutput(columnName); break; - default: + case "participantID": columnOutput = { "Description": "A participant ID", Annotations: {