From face1b3033486d697f167133ef395e680a3cf416 Mon Sep 17 00:00:00 2001 From: Colin Megill Date: Thu, 1 Jul 2021 18:29:06 -0700 Subject: [PATCH] genesets e2e tests (#2241) * __test: create geneset * example dataset test geneset * delete geneset test * edit __test * gene crud * Update client/Makefile Co-authored-by: Severiano Badajoz * copy gene sets separately * make fix * ignore test files locally * csv update * updated csvs * fix unit tests for gene set load routes * add missing fix to czi_hosted unit test * pin tiledb version, for czi_hosted backend, to <0.9 * Revert tiledb pin to be less than 0.9. Broken tests have been updated in main branch. * newline, gitignore * color by and subset * diffexp sets equal * add diff exp test class * fix data class * diffexp snapshot * snapshot * snap3 * snapshot parentInnerhtml * remove snap * updated anno snaps * add test class to gene list div * new snapshots * kick off * Revert "kick off" This reverts commit 743f551d55ce27210eaa402b25f095242ef53425. * remove import * eol * revert changes to csv re: gene tests * global name Co-authored-by: Severiano Badajoz Co-authored-by: bkmartinjr Co-authored-by: Arathi Mani Co-authored-by: maniarathi --- backend/test/fixtures/pbmc3k-genesets.csv | 9 +- .../test_czi_hosted/unit/common/test_api.py | 28 ++- .../test/test_server/unit/common/test_api.py | 28 ++- client/Makefile | 6 +- .../__snapshots__/e2eAnnotations.test.js.snap | 4 + client/__tests__/e2e/cellxgeneActions.js | 131 +++++++++++ client/__tests__/e2e/diffexpGeneSets.js | 105 +++++++++ client/__tests__/e2e/e2eAnnotations.test.js | 210 +++++++++++++++++- client/__tests__/e2e/puppeteerUtils.js | 2 +- .../components/brushableHistogram/index.js | 10 +- .../components/brushableHistogram/loading.js | 1 + .../src/components/continuousLegend/index.js | 2 + client/src/components/geneExpression/gene.js | 2 +- .../src/components/geneExpression/geneSet.js | 38 ++-- client/src/components/geneExpression/index.js | 2 +- .../menus/addGeneToGenesetDialogue.js | 2 +- .../menus/createGenesetDialogue.js | 8 +- .../geneExpression/menus/genesetMenus.js | 12 +- .../components/geneExpression/quickGene.js | 2 +- client/src/globals.js | 3 + client/src/reducers/genesets.js | 6 +- 21 files changed, 564 insertions(+), 47 deletions(-) create mode 100644 client/__tests__/e2e/diffexpGeneSets.js diff --git a/backend/test/fixtures/pbmc3k-genesets.csv b/backend/test/fixtures/pbmc3k-genesets.csv index da62da69..83340d4c 100644 --- a/backend/test/fixtures/pbmc3k-genesets.csv +++ b/backend/test/fixtures/pbmc3k-genesets.csv @@ -5,8 +5,8 @@ first gene set name,a description,NO_SUCH_GENE, non-existent gene first gene set name,a description,F5, duplicate gene first gene set name, a description,SUMO3, first gene set name,,SRM, -second gene set,,RER1 -second gene set,,SIK1 +second_gene_set,,RER1 +second_gene_set,,SIK1 third gene set,,NO_SUCH_GENE fourth_gene_set,fourth description,,gene intentionally missing fifth_dataset,,, @@ -14,3 +14,8 @@ summary test,,ACD, summary test,,AATF, summary test,,F5, summary test,,PIGU, +geneset_to_delete,,, +geneset_to_edit,,, +fill_this_geneset,,RER1, +empty_this_geneset,,SIK1, +brush_this_gene,,SIK1, \ No newline at end of file diff --git a/backend/test/test_czi_hosted/unit/common/test_api.py b/backend/test/test_czi_hosted/unit/common/test_api.py index 37da2f57..3bd021bf 100644 --- a/backend/test/test_czi_hosted/unit/common/test_api.py +++ b/backend/test/test_czi_hosted/unit/common/test_api.py @@ -453,7 +453,7 @@ class EndPointsCxg(EndPoints): {"gene_description": "", "gene_symbol": "SIK1"}, ], "geneset_description": "", - "geneset_name": "second gene set", + "geneset_name": "second_gene_set", }, {"genes": [], "geneset_description": "", "geneset_name": "third gene set"}, {"genes": [], "geneset_description": "fourth description", "geneset_name": "fourth_gene_set"}, @@ -468,6 +468,23 @@ class EndPointsCxg(EndPoints): "geneset_description": "", "geneset_name": "summary test", }, + {'genes': [], 'geneset_description': '', 'geneset_name': 'geneset_to_delete'}, + {'genes': [], 'geneset_description': '', 'geneset_name': 'geneset_to_edit'}, + { + 'genes': [{'gene_description': '', 'gene_symbol': 'RER1'}], + 'geneset_description': '', + 'geneset_name': 'fill_this_geneset' + }, + { + 'genes': [{'gene_description': '', 'gene_symbol': 'SIK1'}], + 'geneset_description': '', + 'geneset_name': 'empty_this_geneset' + }, + { + 'genes': [{'gene_description': '', 'gene_symbol': 'SIK1'}], + 'geneset_description': '', + 'geneset_name': 'brush_this_gene' + } ], "tid": 0, }, @@ -484,8 +501,8 @@ class EndPointsCxg(EndPoints): first gene set name,a description,F5, a gene_description\r first gene set name,a description,SUMO3,\r first gene set name,a description,SRM,\r -second gene set,,RER1,\r -second gene set,,SIK1,\r +second_gene_set,,RER1,\r +second_gene_set,,SIK1,\r third gene set,,,\r fourth_gene_set,fourth description,,\r fifth_dataset,,,\r @@ -493,6 +510,11 @@ summary test,,ACD,\r summary test,,AATF,\r summary test,,F5,\r summary test,,PIGU,\r +geneset_to_delete,,,\r +geneset_to_edit,,,\r +fill_this_geneset,,RER1,\r +empty_this_geneset,,SIK1,\r +brush_this_gene,,SIK1,\r """ self.assertEqual(result.data.decode("utf-8"), expected_data) diff --git a/backend/test/test_server/unit/common/test_api.py b/backend/test/test_server/unit/common/test_api.py index 9c8984e4..8633d46b 100644 --- a/backend/test/test_server/unit/common/test_api.py +++ b/backend/test/test_server/unit/common/test_api.py @@ -575,7 +575,7 @@ class EndPointsAnnDataGenesets(unittest.TestCase, EndPoints): {"gene_description": "", "gene_symbol": "SIK1"}, ], "geneset_description": "", - "geneset_name": "second gene set", + "geneset_name": "second_gene_set", }, {"genes": [], "geneset_description": "", "geneset_name": "third gene set"}, {"genes": [], "geneset_description": "fourth description", "geneset_name": "fourth_gene_set"}, @@ -590,6 +590,23 @@ class EndPointsAnnDataGenesets(unittest.TestCase, EndPoints): "geneset_description": "", "geneset_name": "summary test", }, + {'genes': [], 'geneset_description': '', 'geneset_name': 'geneset_to_delete'}, + {'genes': [], 'geneset_description': '', 'geneset_name': 'geneset_to_edit'}, + { + 'genes': [{'gene_description': '', 'gene_symbol': 'RER1'}], + 'geneset_description': '', + 'geneset_name': 'fill_this_geneset' + }, + { + 'genes': [{'gene_description': '', 'gene_symbol': 'SIK1'}], + 'geneset_description': '', + 'geneset_name': 'empty_this_geneset' + }, + { + 'genes': [{'gene_description': '', 'gene_symbol': 'SIK1'}], + 'geneset_description': '', + 'geneset_name': 'brush_this_gene' + } ], "tid": 0, }, @@ -607,8 +624,8 @@ class EndPointsAnnDataGenesets(unittest.TestCase, EndPoints): first gene set name,a description,F5, a gene_description\r first gene set name,a description,SUMO3,\r first gene set name,a description,SRM,\r -second gene set,,RER1,\r -second gene set,,SIK1,\r +second_gene_set,,RER1,\r +second_gene_set,,SIK1,\r third gene set,,,\r fourth_gene_set,fourth description,,\r fifth_dataset,,,\r @@ -616,6 +633,11 @@ summary test,,ACD,\r summary test,,AATF,\r summary test,,F5,\r summary test,,PIGU,\r +geneset_to_delete,,,\r +geneset_to_edit,,,\r +fill_this_geneset,,RER1,\r +empty_this_geneset,,SIK1,\r +brush_this_gene,,SIK1,\r """, ) diff --git a/client/Makefile b/client/Makefile index 33b02144..fbf7dab4 100644 --- a/client/Makefile +++ b/client/Makefile @@ -1,10 +1,13 @@ include ../common.mk ANNOTATIONS := $(if $(ANNOTATIONS),$(ANNOTATIONS),../backend/test/fixtures/pbmc3k-annotations.csv) +GENE_SETS := $(if $(GENE_SETS),$(GENE_SETS),../backend/test/fixtures/pbmc3k-genesets.csv) ANNOTATIONS_FILENAME := $(shell basename $(ANNOTATIONS)) +GENE_SETS_FILENAME := $(shell basename $(GENE_SETS)) CXG_CONFIG := $(if $(CXG_CONFIG), $(CXG_CONFIG), ./__tests__/e2e/test_config.yaml) + # Packaging .PHONY: clean clean: @@ -42,8 +45,9 @@ smoke-test: smoke-test-annotations: $(eval TMP_DIR := $(shell mktemp -d /tmp/cellxgene_XXXXXX)) cp $(ANNOTATIONS) $(TMP_DIR)/ && \ + cp $(GENE_SETS) $(TMP_DIR)/ && \ start_server_and_test \ - 'CXG_OPTIONS="--annotations-file $(TMP_DIR)/$(ANNOTATIONS_FILENAME)" $(MAKE) start-server' \ + 'CXG_OPTIONS="--annotations-file $(TMP_DIR)/$(ANNOTATIONS_FILENAME) --gene-sets-file $(TMP_DIR)/$(GENE_SETS_FILENAME)" $(MAKE) start-server' \ $(CXG_SERVER_PORT) \ 'CXG_URL_BASE="http://localhost:$(CXG_SERVER_PORT)" npm run e2e-annotations -- --verbose false' rm -rf $(TMP_DIR) diff --git a/client/__tests__/e2e/__snapshots__/e2eAnnotations.test.js.snap b/client/__tests__/e2e/__snapshots__/e2eAnnotations.test.js.snap index b2c6342d..ca759215 100644 --- a/client/__tests__/e2e/__snapshots__/e2eAnnotations.test.js.snap +++ b/client/__tests__/e2e/__snapshots__/e2eAnnotations.test.js.snap @@ -21,3 +21,7 @@ exports[`annotations truncate midpoint whitespace 2`] = `"T"`; exports[`annotations truncate single character 2`] = `"T"`; + +exports[`geneSET crud operations and interactions diffexp 1`] = `"
drag-handle-horizontalCD79A79A
drag-handle-horizontalHLA-DRB1DRB1
drag-handle-horizontalHLA-DQA1DQA1
drag-handle-horizontalHLA-DPB1DPB1
drag-handle-horizontalHLA-DQB1DQB1
drag-handle-horizontalHLA-DPA1DPA1
drag-handle-horizontalMS4A14A1
drag-handle-horizontalLTBTB
drag-handle-horizontalCD79B79B
drag-handle-horizontalCD3737
drag-handle-horizontalHLA-DMA-DMA
drag-handle-horizontalTCL1AL1A
drag-handle-horizontalLINC0092600926
drag-handle-horizontalHLA-DMB-DMB
drag-handle-horizontalHVCN1CN1
drag-handle-horizontalEAF2F2
drag-handle-horizontalFCRLARLA
drag-handle-horizontalIRF8F8
drag-handle-horizontalPKIGIG
drag-handle-horizontalP2RX5RX5
drag-handle-horizontalHLA-DOB-DOB
drag-handle-horizontalSPIBIB
drag-handle-horizontalBLNKNK
drag-handle-horizontalSWAP70P70
drag-handle-horizontalPNOCOC
drag-handle-horizontalCD1919
drag-handle-horizontalSMIM14M14
drag-handle-horizontalCD7272
drag-handle-horizontalKIAA01250125
drag-handle-horizontalIGLL5LL5
drag-handle-horizontalARHGAP24AP24
drag-handle-horizontalCOTL1TL1
drag-handle-horizontalC16orf74rf74
drag-handle-horizontalBTKTK
drag-handle-horizontalSNX29P229P2
drag-handle-horizontalADAM28M28
drag-handle-horizontalFCGR2BR2B
drag-handle-horizontalPLD4D4
drag-handle-horizontalPPP1R14AR14A
drag-handle-horizontalMZB1B1
drag-handle-horizontalKIAA00400040
drag-handle-horizontalPHACTR1CTR1
drag-handle-horizontalFCRL2RL2
drag-handle-horizontalRIC3C3
drag-handle-horizontalP2RY10Y10
drag-handle-horizontalSCPEP1EP1
drag-handle-horizontalDRAM2AM2
drag-handle-horizontalRP5-887A10.17A10.1
drag-handle-horizontalCD8282
drag-handle-horizontalGPX1X1
"`; + +exports[`geneSET crud operations and interactions diffexp 2`] = `"
drag-handle-horizontalCD79A79A
drag-handle-horizontalHLA-DRB1DRB1
drag-handle-horizontalHLA-DQA1DQA1
drag-handle-horizontalHLA-DPB1DPB1
drag-handle-horizontalHLA-DQB1DQB1
drag-handle-horizontalHLA-DPA1DPA1
drag-handle-horizontalMS4A14A1
drag-handle-horizontalLTBTB
drag-handle-horizontalCD79B79B
drag-handle-horizontalCD3737
drag-handle-horizontalHLA-DMA-DMA
drag-handle-horizontalTCL1AL1A
drag-handle-horizontalLINC0092600926
drag-handle-horizontalHLA-DMB-DMB
drag-handle-horizontalHVCN1CN1
drag-handle-horizontalEAF2F2
drag-handle-horizontalFCRLARLA
drag-handle-horizontalIRF8F8
drag-handle-horizontalPKIGIG
drag-handle-horizontalP2RX5RX5
drag-handle-horizontalHLA-DOB-DOB
drag-handle-horizontalSPIBIB
drag-handle-horizontalBLNKNK
drag-handle-horizontalSWAP70P70
drag-handle-horizontalPNOCOC
drag-handle-horizontalCD1919
drag-handle-horizontalSMIM14M14
drag-handle-horizontalCD7272
drag-handle-horizontalKIAA01250125
drag-handle-horizontalIGLL5LL5
drag-handle-horizontalARHGAP24AP24
drag-handle-horizontalCOTL1TL1
drag-handle-horizontalC16orf74rf74
drag-handle-horizontalBTKTK
drag-handle-horizontalSNX29P229P2
drag-handle-horizontalADAM28M28
drag-handle-horizontalFCGR2BR2B
drag-handle-horizontalPLD4D4
drag-handle-horizontalPPP1R14AR14A
drag-handle-horizontalMZB1B1
drag-handle-horizontalKIAA00400040
drag-handle-horizontalPHACTR1CTR1
drag-handle-horizontalFCRL2RL2
drag-handle-horizontalRIC3C3
drag-handle-horizontalP2RY10Y10
drag-handle-horizontalSCPEP1EP1
drag-handle-horizontalDRAM2AM2
drag-handle-horizontalRP5-887A10.17A10.1
drag-handle-horizontalCD8282
drag-handle-horizontalGPX1X1
"`; diff --git a/client/__tests__/e2e/cellxgeneActions.js b/client/__tests__/e2e/cellxgeneActions.js index ba1f4f08..0f5bf77c 100644 --- a/client/__tests__/e2e/cellxgeneActions.js +++ b/client/__tests__/e2e/cellxgeneActions.js @@ -176,6 +176,137 @@ export async function createCategory(categoryName) { await clickOn("submit-category"); } +/* + + GENESET + +*/ + +export async function colorByGeneset(genesetName) { + await clickOn(`${genesetName}:colorby-entire-geneset`); +} + +export async function colorByGene(gene) { + await clickOn(`colorby-${gene}`); +} + +export async function assertColorLegendLabel(label) { + const handle = await waitByID("continuous_legend_color_by_label"); + + const result = await handle.evaluate((node) => { + return node.getAttribute("aria-label"); + }); + + return expect(result).toBe(label); +} + +export async function expandGeneset(genesetName) { + const expand = await waitByID(`${genesetName}:geneset-expand`); + const notExpanded = await expand.$( + "[data-testclass='geneset-expand-is-not-expanded']" + ); + if (notExpanded) await clickOn(`${genesetName}:geneset-expand`); +} + +export async function createGeneset(genesetName) { + await clickOnUntil("open-create-geneset-dialog", async () => { + await expect(page).toMatchElement(getTestId("create-geneset-input")); + }); + + await typeInto("create-geneset-input", genesetName); + await clickOn("submit-geneset"); + await waitByClass("autosave-complete"); +} + +export async function editGenesetName(genesetName, editText) { + const editButton = `${genesetName}:edit-genesetName-mode`; + const submitButton = `${genesetName}:submit-geneset`; + await clickOnUntil(`${genesetName}:see-actions`, async () => { + await expect(page).toMatchElement(getTestId(editButton)); + }); + await clickOn(editButton); + await typeInto("rename-geneset-modal", editText); + await clickOn(submitButton); +} + +export async function deleteGeneset(genesetName) { + const targetId = `${genesetName}:delete-geneset`; + + await clickOnUntil(`${genesetName}:see-actions`, async () => { + await expect(page).toMatchElement(getTestId(targetId)); + }); + + await clickOn(targetId); + + await assertGenesetDoesNotExist(genesetName); + await waitByClass("autosave-complete"); +} + +export async function assertGenesetDoesNotExist(genesetName) { + const result = await isElementPresent( + getTestId(`${genesetName}:geneset-name`) + ); + await expect(result).toBe(false); +} + +export async function assertGenesetExists(genesetName) { + const handle = await waitByID(`${genesetName}:geneset-name`); + + const result = await handle.evaluate((node) => { + return node.getAttribute("aria-label"); + }); + + return expect(result).toBe(genesetName); +} + +/* + + GENE + +*/ + +export async function addGeneToSet(genesetName, geneToAddToSet) { + const submitButton = `${genesetName}:submit-gene`; + + await clickOn(`${genesetName}:add-new-gene-to-geneset`); + await typeInto("add-genes", geneToAddToSet); + await clickOn(submitButton); +} + +export async function removeGene(geneSymbol) { + const targetId = `delete-from-geneset:${geneSymbol}`; + + await clickOn(targetId); + + await waitByClass("autosave-complete"); +} + +export async function assertGeneExistsInGeneset(geneSymbol) { + const handle = await waitByID(`${geneSymbol}:gene-label`); + + const result = await handle.evaluate((node) => { + return node.getAttribute("aria-label"); + }); + + return expect(result).toBe(geneSymbol); +} + +export async function assertGeneDoesNotExist(geneSymbol) { + const result = await isElementPresent(getTestId(`${geneSymbol}:gene-label`)); + + await expect(result).toBe(false); +} + +export async function expandGene(geneSymbol) { + await clickOn(`maximize-${geneSymbol}`); +} + +/* + + CATEGORY + +*/ + export async function duplicateCategory(categoryName) { await clickOn("open-annotation-dialog"); diff --git a/client/__tests__/e2e/diffexpGeneSets.js b/client/__tests__/e2e/diffexpGeneSets.js new file mode 100644 index 00000000..627861c4 --- /dev/null +++ b/client/__tests__/e2e/diffexpGeneSets.js @@ -0,0 +1,105 @@ +export const diffexpPop1Genes = [ + "CD79A", + "HLA-DRB1", + "HLA-DQA1", + "HLA-DPB1", + "HLA-DQB1", + "HLA-DPA1", + "MS4A1", + "LTB", + "CD79B", + "CD37", + "HLA-DMA", + "TCL1A", + "LINC00926", + "HLA-DMB", + "HVCN1", + "EAF2", + "FCRLA", + "IRF8", + "PKIG", + "P2RX5", + "HLA-DOB", + "SPIB", + "BLNK", + "SWAP70", + "PNOC", + "CD19", + "SMIM14", + "CD72", + "KIAA0125", + "IGLL5", + "ARHGAP24", + "COTL1", + "C16orf74", + "BTK", + "SNX29P2", + "ADAM28", + "FCGR2B", + "PLD4", + "PPP1R14A", + "MZB1", + "KIAA0040", + "PHACTR1", + "FCRL2", + "RIC3", + "P2RY10", + "SCPEP1", + "DRAM2", + "RP5-887A10.1", + "CD82", + "GPX1", +]; + +export const diffexpPop2Genes = [ + "NKG7", + "GZMB", + "CTSW", + "PRF1", + "GNLY", + "GZMA", + "CST7", + "FGFBP2", + "SRGN", + "CD247", + "FCGR3A", + "TYROBP", + "FCER1G", + "ID2", + "SPON2", + "CCL4", + "CCL5", + "GZMH", + "GIMAP7", + "CLIC3", + "HOPX", + "XCL2", + "LGALS1", + "IGFBP7", + "AKR1C3", + "IL32", + "EFHD2", + "PRSS23", + "TTC38", + "ZAP70", + "S1PR5", + "SAMD3", + "GIMAP4", + "CCL3", + "ABI3", + "XCL1", + "S100A6", + "UBB", + "GPR56", + "PDIA3", + "S100A11", + "APOBEC3G", + "HAVCR2", + "PLEKHF1", + "LITAF", + "ARPC5L", + "PTGDR", + "PRMT2", + "GSTP1", + "FCRL6", +]; diff --git a/client/__tests__/e2e/e2eAnnotations.test.js b/client/__tests__/e2e/e2eAnnotations.test.js index e998da6b..1430600c 100644 --- a/client/__tests__/e2e/e2eAnnotations.test.js +++ b/client/__tests__/e2e/e2eAnnotations.test.js @@ -12,6 +12,7 @@ import { getTestId, getTestClass, getAllByClass, + getOneElementInnerHTML, } from "./puppeteerUtils"; import { @@ -27,6 +28,21 @@ import { renameLabel, subset, duplicateCategory, + createGeneset, + deleteGeneset, + assertGenesetExists, + assertGenesetDoesNotExist, + getCellSetCount, + expandGeneset, + editGenesetName, + addGeneToSet, + assertGeneExistsInGeneset, + removeGene, + assertGeneDoesNotExist, + expandGene, + colorByGeneset, + assertColorLegendLabel, + colorByGene, } from "./cellxgeneActions"; const data = datasets[DATASET]; @@ -34,12 +50,40 @@ const data = datasets[DATASET]; const perTestCategoryName = "TEST-CATEGORY"; const perTestLabelName = "TEST-LABEL"; +// geneset CRUD +const genesetToDeleteName = "geneset_to_delete"; +const preExistingGenesetName = "fifth_dataset"; +const meanExpressionBrushGenesetName = "second_gene_set"; +const meanExpressionBrushCellsSelected = "557"; +const subsetMeanExpressionBrushCellsSelected = "452"; + +// initial text, the text we type in, the result +const editableGenesetName = "geneset_to_edit"; +const editText = "_111"; +const newGenesetName = "geneset_to_edit_111"; + +// add gene to set +const geneToAddToSet = "RER1"; +const setToAddGeneTo = "fill_this_geneset"; + +// remove gene from set +const geneToRemove = "SIK1"; +const setToRemoveFrom = "empty_this_geneset"; + +// brush a gene +const geneToBrushAndColorBy = "SIK1"; +const brushThisGeneGeneset = "brush_this_gene"; +const geneBrushedCellCount = "109"; +const subsetGeneBrushedCellCount = "96"; + async function setup(config) { await goToPage(appUrlBase); - // setup the test fixtures - await createCategory(perTestCategoryName); - await createLabel(perTestCategoryName, perTestLabelName); + if (config.categoricalAnno) { + // setup the test fixtures + await createCategory(perTestCategoryName); + await createLabel(perTestCategoryName, perTestLabelName); + } if (config.withSubset) { await subset({ x1: 0.1, y1: 0.1, x2: 0.8, y2: 0.8 }); @@ -51,6 +95,166 @@ async function setup(config) { describe.each([ { withSubset: true, tag: "subset" }, { withSubset: false, tag: "whole" }, +])("geneSET crud operations and interactions", (config) => { + test("genesets load from csv", async () => { + await setup(config); + + await assertGenesetExists(preExistingGenesetName); + }); + test("brush on geneset mean", async () => { + await setup(config); + + await expandGeneset(meanExpressionBrushGenesetName); + + const histBrushableAreaId = `histogram-${meanExpressionBrushGenesetName}-plot-brushable-area`; + + const coords = await calcDragCoordinates(histBrushableAreaId, { + x1: 0.25, + y1: 0.5, + x2: 0.55, + y2: 0.5, + }); + + await drag(histBrushableAreaId, coords.start, coords.end); + + const cellCount = await getCellSetCount(1); + if (config.withSubset) { + expect(cellCount).toBe(subsetMeanExpressionBrushCellsSelected); + } else { + expect(cellCount).toBe(meanExpressionBrushCellsSelected); + } + }); + test("color by mean expression", async () => { + await setup(config); + + await colorByGeneset(meanExpressionBrushGenesetName); + await assertColorLegendLabel(meanExpressionBrushGenesetName); + }); + test("diffexp", async () => { + if (config.withSubset) return; + + await setup(config); + + // set the two cell sets to b cells vs nk cells + await expandCategory(`louvain`); + await clickOn(`louvain:category-select`); + await clickOn(`categorical-value-select-louvain-B cells`); + await clickOn(`cellset-button-1`); + await clickOn(`categorical-value-select-louvain-B cells`); + await clickOn(`categorical-value-select-louvain-NK cells`); + await clickOn(`cellset-button-2`); + + // run diffexp + await clickOn(`diffexp-button`); + await waitByClass("pop-1-geneset-expand"); + await expect(page).toClick(getTestClass("pop-1-geneset-expand")); + + await page.waitForFunction( + (selector) => !document.querySelector(selector), + {}, + getTestClass("gene-loading-spinner") + ); + + let genesHTML = await getOneElementInnerHTML( + getTestClass("gene-set-genes") + ); + + expect(genesHTML).toMatchSnapshot(); + + await expect(page).toClick(getTestClass("pop-1-geneset-expand")); + await expect(page).toClick(getTestClass("pop-2-geneset-expand")); + + await page.waitForFunction( + (selector) => !document.querySelector(selector), + {}, + getTestClass("gene-loading-spinner") + ); + + genesHTML = await getOneElementInnerHTML(getTestClass("gene-set-genes")); + + expect(genesHTML).toMatchSnapshot(); + }); + test("create a new geneset", async () => { + if (config.withSubset) return; + + await setup(config); + + const genesetName = `test-geneset-foo-123`; + await assertGenesetDoesNotExist(genesetName); + await createGeneset(genesetName); + /* note: as of June 2021, the aria label is in the truncate component which clones the element */ + await assertGenesetExists(genesetName); + }); + test("edit geneset name", async () => { + await setup(config); + + await editGenesetName(editableGenesetName, editText); + await assertGenesetExists(newGenesetName); + }); + test("delete a geneset", async () => { + if (config.withSubset) return; + + await setup(config); + + await deleteGeneset(genesetToDeleteName); + }); +}); + +describe.each([ + { withSubset: true, tag: "subset" }, + { withSubset: false, tag: "whole" }, +])("GENE crud operations and interactions", (config) => { + test("add a gene to geneset", async () => { + await setup(config); + + await addGeneToSet(setToAddGeneTo, geneToAddToSet); + await expandGeneset(setToAddGeneTo); + await assertGeneExistsInGeneset(geneToAddToSet); + }); + test("expand gene and brush", async () => { + await setup(config); + + await expandGeneset(brushThisGeneGeneset); + await expandGene(geneToBrushAndColorBy); + const histBrushableAreaId = `histogram-${geneToBrushAndColorBy}-plot-brushable-area`; + + const coords = await calcDragCoordinates(histBrushableAreaId, { + x1: 0.25, + y1: 0.5, + x2: 0.55, + y2: 0.5, + }); + await drag(histBrushableAreaId, coords.start, coords.end); + const cellCount = await getCellSetCount(1); + if (config.withSubset) { + expect(cellCount).toBe(subsetGeneBrushedCellCount); + } else { + expect(cellCount).toBe(geneBrushedCellCount); + } + }); + test("color by gene in geneset", async () => { + await setup(config); + + await expandGeneset(meanExpressionBrushGenesetName); + + await colorByGene(geneToBrushAndColorBy); + await assertColorLegendLabel(geneToBrushAndColorBy); + }); + test("delete gene from geneset", async () => { + // We've already deleted the gene + if (config.withSubset) return; + + await setup(config); + + await expandGeneset(setToRemoveFrom); + await removeGene(geneToRemove); + await assertGeneDoesNotExist(geneToRemove); + }); +}); + +describe.each([ + { withSubset: true, tag: "subset", categoricalAnno: true }, + { withSubset: false, tag: "whole", categoricalAnno: true }, ])("annotations", (config) => { test("create a category", async () => { await setup(config); diff --git a/client/__tests__/e2e/puppeteerUtils.js b/client/__tests__/e2e/puppeteerUtils.js index 099b6065..8d3a497f 100644 --- a/client/__tests__/e2e/puppeteerUtils.js +++ b/client/__tests__/e2e/puppeteerUtils.js @@ -12,7 +12,7 @@ export async function waitByID(testId, props = {}) { } export async function waitByClass(testClass, props = {}) { - await page.waitForSelector(`[data-testclass='${testClass}']`, props); + return page.waitForSelector(`[data-testclass='${testClass}']`, props); } export async function waitForAllByIds(testIds) { diff --git a/client/src/components/brushableHistogram/index.js b/client/src/components/brushableHistogram/index.js index 89773fa8..f56faed1 100644 --- a/client/src/components/brushableHistogram/index.js +++ b/client/src/components/brushableHistogram/index.js @@ -366,6 +366,10 @@ class HistogramBrush extends React.PureComponent { const fieldForId = field.replace(/\s/g, "_"); const showScatterPlot = isUserDefined; + let testClass = "histogram-continuous-metadata"; + if (isUserDefined) testClass = "histogram-user-gene"; + else if (isGeneSetSummary) testClass = "histogram-gene-set-summary"; + return ( { */ return (
{ .attr("y", 2) .attr("x", 0 - legendHeight / 2) .attr("dy", "1em") + .attr("data-testid", "continuous_legend_color_by_label") + .attr("aria-label", colorAccessor) .style("text-anchor", "middle") .style("fill", "white") .text(colorAccessor); diff --git a/client/src/components/geneExpression/gene.js b/client/src/components/geneExpression/gene.js index 7d0834eb..47efc6cd 100644 --- a/client/src/components/geneExpression/gene.js +++ b/client/src/components/geneExpression/gene.js @@ -135,7 +135,7 @@ class Gene extends React.Component {