mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-15 20:57:56 +08:00
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 <sbadajoz@chanzuckerberg.com>
* 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 743f551d55.
* remove import
* eol
* revert changes to csv re: gene tests
* global name
Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com>
Co-authored-by: bkmartinjr <bruce@chanzuckerberg.com>
Co-authored-by: Arathi Mani <arathi.mani@chanzuckerberg.com>
Co-authored-by: maniarathi <mani.arathi@gmail.com>
This commit is contained in:
9
backend/test/fixtures/pbmc3k-genesets.csv
vendored
9
backend/test/fixtures/pbmc3k-genesets.csv
vendored
@@ -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,
|
||||
|
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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");
|
||||
|
||||
|
||||
105
client/__tests__/e2e/diffexpGeneSets.js
Normal file
105
client/__tests__/e2e/diffexpGeneSets.js
Normal file
@@ -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",
|
||||
];
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 (
|
||||
<Async
|
||||
watchFn={HistogramBrush.watchAsync}
|
||||
@@ -386,11 +390,7 @@ class HistogramBrush extends React.PureComponent {
|
||||
<div
|
||||
id={`histogram_${fieldForId}`}
|
||||
data-testid={`histogram-${field}`}
|
||||
data-testclass={
|
||||
isUserDefined
|
||||
? "histogram-user-gene"
|
||||
: "histogram-continuous-metadata"
|
||||
}
|
||||
data-testclass={testClass}
|
||||
style={{
|
||||
padding: mini ? 0 : globals.leftSidebarSectionPadding,
|
||||
backgroundColor: zebra ? globals.lightestGrey : "white",
|
||||
|
||||
@@ -9,6 +9,7 @@ const StillLoading = ({ zebra, displayName }) => {
|
||||
*/
|
||||
return (
|
||||
<div
|
||||
data-testclass="gene-loading-spinner"
|
||||
style={{
|
||||
padding: globals.leftSidebarSectionPadding,
|
||||
backgroundColor: zebra ? globals.lightestGrey : "white",
|
||||
|
||||
@@ -98,6 +98,8 @@ const continuous = (selectorId, colorScale, colorAccessor) => {
|
||||
.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);
|
||||
|
||||
@@ -135,7 +135,7 @@ class Gene extends React.Component {
|
||||
<Button
|
||||
minimal
|
||||
small
|
||||
data-testid={`delete-from-geneset-${gene}`}
|
||||
data-testid={`delete-from-geneset:${gene}`}
|
||||
onClick={
|
||||
quickGene ? removeGene(gene) : this.handleDeleteGeneFromSet
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import GenesetMenus from "./menus/genesetMenus";
|
||||
import EditGenesetNameDialogue from "./menus/editGenesetNameDialogue";
|
||||
import HistogramBrush from "../brushableHistogram";
|
||||
|
||||
import { diffexpPopNamePrefix1, diffexpPopNamePrefix2 } from "../../globals";
|
||||
|
||||
@connect((state, ownProps) => {
|
||||
return {
|
||||
world: state.world,
|
||||
@@ -81,18 +83,22 @@ class GeneSet extends React.Component {
|
||||
renderGenes() {
|
||||
const { setName, setGenes, setGenesWithDescriptions } = this.props;
|
||||
|
||||
return setGenes.map((gene) => {
|
||||
const { geneDescription } = setGenesWithDescriptions.get(gene);
|
||||
return (
|
||||
<div data-testclass="gene-set-genes">
|
||||
{setGenes.map((gene) => {
|
||||
const { geneDescription } = setGenesWithDescriptions.get(gene);
|
||||
|
||||
return (
|
||||
<Gene
|
||||
key={gene}
|
||||
gene={gene}
|
||||
geneDescription={geneDescription}
|
||||
geneset={setName}
|
||||
/>
|
||||
);
|
||||
});
|
||||
return (
|
||||
<Gene
|
||||
key={gene}
|
||||
gene={gene}
|
||||
geneDescription={geneDescription}
|
||||
geneset={setName}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -100,6 +106,12 @@ class GeneSet extends React.Component {
|
||||
const { isOpen } = this.state;
|
||||
const genesetNameLengthVisible = 150; /* this magic number determines how much of a long geneset name we see */
|
||||
const genesetIsEmpty = setGenes.length === 0;
|
||||
let testClass = "geneset-expand";
|
||||
|
||||
if (setName.includes(diffexpPopNamePrefix1))
|
||||
testClass = "pop-1-geneset-expand";
|
||||
else if (setName.includes(diffexpPopNamePrefix2))
|
||||
testClass = "pop-2-geneset-expand";
|
||||
|
||||
return (
|
||||
<div style={{ marginBottom: 3 }}>
|
||||
@@ -113,7 +125,7 @@ class GeneSet extends React.Component {
|
||||
<span
|
||||
role="menuitem"
|
||||
tabIndex="0"
|
||||
data-testclass="geneset-expand"
|
||||
data-testclass={testClass}
|
||||
data-testid={`${setName}:geneset-expand`}
|
||||
onKeyPress={
|
||||
/* TODO(colinmegill): #2101: click handler on span */ () => {}
|
||||
@@ -133,7 +145,7 @@ class GeneSet extends React.Component {
|
||||
style={{
|
||||
maxWidth: globals.leftSidebarWidth - genesetNameLengthVisible,
|
||||
}}
|
||||
data-testid={`${setName}:geneset-label`}
|
||||
data-testid={`${setName}:geneset-name`}
|
||||
>
|
||||
{setName}
|
||||
</span>
|
||||
|
||||
@@ -69,7 +69,7 @@ class GeneExpression extends React.Component {
|
||||
<H4
|
||||
role="menuitem"
|
||||
tabIndex="0"
|
||||
data-testclass="category-expand"
|
||||
data-testclass="geneset-heading-expand"
|
||||
onKeyPress={this.handleExpandGeneSets}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
|
||||
@@ -58,7 +58,7 @@ class AddGeneToGenesetDialogue extends React.PureComponent {
|
||||
isActive={genesetsUI.isAddingGenesToGeneset === geneset}
|
||||
inputProps={{ "data-testid": `${geneset}:create-label-dialog` }}
|
||||
primaryButtonProps={{
|
||||
"data-testid": `${geneset}:submit-label`,
|
||||
"data-testid": `${geneset}:submit-gene`,
|
||||
}}
|
||||
title="Add genes to gene set"
|
||||
instruction={`Add genes to ${geneset}`}
|
||||
|
||||
@@ -128,8 +128,8 @@ class CreateGenesetDialogue extends React.PureComponent {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { genesetName, nameErrorMessage } = this.state;
|
||||
const { metadataField, genesetsUI, genesets } = this.props;
|
||||
const { genesetName, nameErrorMessage} = this.state;
|
||||
const { genesetsUI, genesets } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -150,7 +150,7 @@ class CreateGenesetDialogue extends React.PureComponent {
|
||||
<LabelInput
|
||||
onChange={this.handleChange}
|
||||
inputProps={{
|
||||
"data-testid": "create-geneset-modal",
|
||||
"data-testid": "create-geneset-input",
|
||||
leftIcon: "manually-entered-data",
|
||||
intent: "none",
|
||||
autoFocus: true,
|
||||
@@ -205,7 +205,7 @@ class CreateGenesetDialogue extends React.PureComponent {
|
||||
</Button>
|
||||
</Tooltip2>
|
||||
<Button
|
||||
data-testid={`${metadataField}:submit-geneset`}
|
||||
data-testid="submit-geneset"
|
||||
onClick={this.createGeneset}
|
||||
disabled={nameErrorMessage !== ""}
|
||||
intent="primary"
|
||||
|
||||
@@ -55,7 +55,7 @@ class GenesetMenus extends React.PureComponent {
|
||||
});
|
||||
};
|
||||
|
||||
handleDeleteCategory = () => {
|
||||
handleDeleteGeneset = () => {
|
||||
const { dispatch, geneset } = this.props;
|
||||
dispatch(actions.genesetDelete(geneset));
|
||||
};
|
||||
@@ -76,8 +76,8 @@ class GenesetMenus extends React.PureComponent {
|
||||
>
|
||||
<Button
|
||||
style={{ marginLeft: 0, marginRight: 2 }}
|
||||
data-testclass="handleAddNewLabelToCategory"
|
||||
data-testid={`${geneset}:add-new-label-to-category`}
|
||||
data-testclass="handleAddNewGeneToGeneset"
|
||||
data-testid={`${geneset}:add-new-gene-to-geneset`}
|
||||
icon={<Icon icon="plus" iconSize={10} />}
|
||||
onClick={this.activateAddGeneToGenesetMode}
|
||||
small
|
||||
@@ -101,9 +101,9 @@ class GenesetMenus extends React.PureComponent {
|
||||
<MenuItem
|
||||
icon="trash"
|
||||
intent="danger"
|
||||
data-testclass="handleDeleteCategory"
|
||||
data-testid={`${geneset}:delete-category`}
|
||||
onClick={this.handleDeleteCategory}
|
||||
data-testclass="handleDeleteGeneset"
|
||||
data-testid={`${geneset}:delete-geneset`}
|
||||
onClick={this.handleDeleteGeneset}
|
||||
text="Delete this gene set (destructive, will remove set and collection of genes)"
|
||||
/>
|
||||
</Menu>
|
||||
|
||||
@@ -122,7 +122,7 @@ function QuickGene() {
|
||||
<H4
|
||||
role="menuitem"
|
||||
tabIndex="0"
|
||||
data-testclass="category-expand"
|
||||
data-testclass="quickgene-heading-expand"
|
||||
onKeyPress={handleExpand}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
|
||||
@@ -79,6 +79,9 @@ export const categoryDisplayStringMaxLength = 33;
|
||||
export const maxUserDefinedGenes = 25;
|
||||
export const maxGenes = 100;
|
||||
|
||||
export const diffexpPopNamePrefix1 = "Pop1 high";
|
||||
export const diffexpPopNamePrefix2 = "Pop2 high";
|
||||
|
||||
/* various timing-related behaviors */
|
||||
export const tooltipHoverOpenDelay = 1000; /* ms delay before a tooltip displays */
|
||||
export const tooltipHoverOpenDelayQuick = 500;
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* routes. Do not rely on it to enforce geneset integrity - eg, no duplicate
|
||||
* genes in a geneset.
|
||||
*/
|
||||
import { diffexpPopNamePrefix1, diffexpPopNamePrefix2 } from "../globals";
|
||||
|
||||
const GeneSets = (
|
||||
state = {
|
||||
initialized: false,
|
||||
@@ -365,8 +367,8 @@ const GeneSets = (
|
||||
const dateString = new Date().toLocaleString();
|
||||
|
||||
const genesetNames = {
|
||||
positive: `Pop1 high (${dateString})`,
|
||||
negative: `Pop2 high (${dateString})`,
|
||||
positive: `${diffexpPopNamePrefix1} (${dateString})`,
|
||||
negative: `${diffexpPopNamePrefix2} (${dateString})`,
|
||||
};
|
||||
|
||||
const diffExpGeneSets = [];
|
||||
|
||||
Reference in New Issue
Block a user