Skip to content

Commit 57c82c0

Browse files
committed
Add tests for preprocessed dot plots
1 parent 060c438 commit 57c82c0

File tree

3 files changed

+543
-0
lines changed

3 files changed

+543
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/**
2+
* Integration tests for DotPlot component with precomputed data
3+
*/
4+
5+
import '@testing-library/jest-dom/extend-expect'
6+
import * as ScpApi from 'lib/scp-api'
7+
8+
import {
9+
PRECOMPUTED_DOT_PLOT_DATA,
10+
FEATURE_FLAGS_ENABLED,
11+
FEATURE_FLAGS_DISABLED
12+
} from './dot-plot-precompute.test-data'
13+
14+
describe('DotPlot Integration with Feature Flag', () => {
15+
let fetchMorpheusJsonSpy
16+
17+
beforeEach(() => {
18+
jest.clearAllMocks()
19+
fetchMorpheusJsonSpy = jest.spyOn(ScpApi, 'fetchMorpheusJson')
20+
})
21+
22+
afterEach(() => {
23+
jest.restoreAllMocks()
24+
})
25+
26+
describe('fetchMorpheusJson endpoint selection', () => {
27+
it('uses dotplot endpoint when feature flag is enabled', async () => {
28+
fetchMorpheusJsonSpy.mockResolvedValue([PRECOMPUTED_DOT_PLOT_DATA, {}])
29+
30+
await ScpApi.fetchMorpheusJson(
31+
'SCP1234',
32+
['CD3D', 'CD79A'],
33+
'cluster_1',
34+
'cell_type',
35+
'group',
36+
'study',
37+
'all',
38+
false, // mock
39+
true // isPrecomputed
40+
)
41+
42+
// Verify the API was called with correct parameters
43+
expect(fetchMorpheusJsonSpy).toHaveBeenCalledWith(
44+
'SCP1234',
45+
['CD3D', 'CD79A'],
46+
'cluster_1',
47+
'cell_type',
48+
'group',
49+
'study',
50+
'all',
51+
false,
52+
true
53+
)
54+
})
55+
56+
it('uses morpheus endpoint when feature flag is disabled', async () => {
57+
fetchMorpheusJsonSpy.mockResolvedValue([{}, {}])
58+
59+
await ScpApi.fetchMorpheusJson(
60+
'SCP1234',
61+
['CD3D', 'CD79A'],
62+
'cluster_1',
63+
'cell_type',
64+
'group',
65+
'study',
66+
'all',
67+
false, // mock
68+
false // isPrecomputed
69+
)
70+
71+
expect(fetchMorpheusJsonSpy).toHaveBeenCalledWith(
72+
'SCP1234',
73+
['CD3D', 'CD79A'],
74+
'cluster_1',
75+
'cell_type',
76+
'group',
77+
'study',
78+
'all',
79+
false,
80+
false
81+
)
82+
})
83+
})
84+
85+
describe('Data format detection', () => {
86+
it('detects precomputed data format correctly', () => {
87+
const data = PRECOMPUTED_DOT_PLOT_DATA
88+
89+
// Check if data matches precomputed format
90+
const isPrecomputed = !!(data.annotation_name && data.values && data.genes)
91+
expect(isPrecomputed).toBe(true)
92+
})
93+
94+
it('does not detect standard Morpheus format as precomputed', () => {
95+
const standardData = {
96+
rows: ['Gene1', 'Gene2'],
97+
columns: ['Cell1', 'Cell2'],
98+
data: [[1, 2], [3, 4]]
99+
}
100+
101+
const isPrecomputed = !!(standardData.annotation_name && standardData.values && standardData.genes)
102+
expect(isPrecomputed).toBe(false)
103+
})
104+
})
105+
106+
describe('Endpoint URL construction', () => {
107+
it('constructs dotplot endpoint URL correctly', () => {
108+
const studyAccession = 'SCP1234'
109+
const isPrecomputed = true
110+
111+
// Test the endpoint selection logic
112+
const endpoint = isPrecomputed ? 'dotplot' : 'morpheus'
113+
expect(endpoint).toBe('dotplot')
114+
115+
const expectedUrl = `/studies/${studyAccession}/expression/${endpoint}`
116+
expect(expectedUrl).toContain('dotplot')
117+
expect(expectedUrl).not.toContain('morpheus')
118+
})
119+
120+
it('constructs morpheus endpoint URL correctly when flag is off', () => {
121+
const studyAccession = 'SCP1234'
122+
const isPrecomputed = false
123+
const endpoint = isPrecomputed ? 'dotplot' : 'morpheus'
124+
125+
expect(endpoint).toBe('morpheus')
126+
127+
const expectedUrl = `/studies/${studyAccession}/expression/${endpoint}`
128+
expect(expectedUrl).toContain('morpheus')
129+
expect(expectedUrl).not.toContain('dotplot')
130+
})
131+
})
132+
133+
describe('Feature flag integration', () => {
134+
it('uses feature flag value to determine endpoint', () => {
135+
// When flag is true
136+
let usePrecomputed = FEATURE_FLAGS_ENABLED.dot_plot_preprocessing_frontend
137+
expect(usePrecomputed).toBe(true)
138+
139+
// When flag is false
140+
usePrecomputed = FEATURE_FLAGS_DISABLED.dot_plot_preprocessing_frontend
141+
expect(usePrecomputed).toBe(false)
142+
})
143+
144+
it('defaults to false when flag is undefined', () => {
145+
const flags = {}
146+
const usePrecomputed = flags?.dot_plot_preprocessing_frontend || false
147+
expect(usePrecomputed).toBe(false)
148+
})
149+
})
150+
151+
describe('Color scheme configuration', () => {
152+
it('uses relative scaling for raw expression values', () => {
153+
const colorScheme = {
154+
colors: ['#0000BB', '#CC0088', '#FF0000'],
155+
values: [0, 0.5, 1],
156+
scalingMode: 'relative'
157+
}
158+
159+
expect(colorScheme.scalingMode).toBe('relative')
160+
expect(colorScheme.colors).toHaveLength(3)
161+
expect(colorScheme.values).toEqual([0, 0.5, 1])
162+
})
163+
164+
it('uses fixed color values for blue-purple-red gradient', () => {
165+
const colorScheme = {
166+
colors: ['#0000BB', '#CC0088', '#FF0000'],
167+
values: [0, 0.5, 1],
168+
scalingMode: 'relative'
169+
}
170+
171+
// Blue at 0
172+
expect(colorScheme.colors[0]).toBe('#0000BB')
173+
// Purple at 0.5
174+
expect(colorScheme.colors[1]).toBe('#CC0088')
175+
// Red at 1
176+
expect(colorScheme.colors[2]).toBe('#FF0000')
177+
})
178+
})
179+
180+
describe('Size configuration', () => {
181+
it('configures sizeBy for percent expressing', () => {
182+
const sizeByConfig = {
183+
seriesName: 'percent',
184+
min: 0,
185+
max: 75
186+
}
187+
188+
expect(sizeByConfig.seriesName).toBe('percent')
189+
expect(sizeByConfig.min).toBe(0)
190+
expect(sizeByConfig.max).toBe(75)
191+
})
192+
})
193+
})
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Test data for dot plot precompute patch tests
3+
*/
4+
5+
// Mock pre-computed dot plot data from backend
6+
export const PRECOMPUTED_DOT_PLOT_DATA = {
7+
annotation_name: 'cell_type',
8+
values: ['T cells', 'B cells', 'NK cells', 'Monocytes'],
9+
genes: {
10+
'CD3D': [
11+
[2.5, 0.95], // T cells: [mean_expression, percent_expressing]
12+
[0.1, 0.05], // B cells
13+
[0.3, 0.15], // NK cells
14+
[0.0, 0.0] // Monocytes
15+
],
16+
'CD79A': [
17+
[0.2, 0.1], // T cells
18+
[3.1, 0.98], // B cells
19+
[0.1, 0.05], // NK cells
20+
[0.0, 0.0] // Monocytes
21+
],
22+
'NKG7': [
23+
[1.2, 0.65], // T cells
24+
[0.3, 0.15], // B cells
25+
[2.8, 0.92], // NK cells
26+
[0.5, 0.25] // Monocytes
27+
],
28+
'UBC': [
29+
[1.926, 0.9237], // T cells
30+
[2.081, 0.969], // B cells
31+
[2.012, 0.7749], // NK cells
32+
[3.394, 0.95] // Monocytes (highest)
33+
]
34+
}
35+
}
36+
37+
// Mock pre-computed data with all zeros for a gene
38+
export const PRECOMPUTED_WITH_ZEROS = {
39+
annotation_name: 'tissue',
40+
values: ['Brain', 'Liver', 'Heart'],
41+
genes: {
42+
'GENE1': [
43+
[0, 0],
44+
[0, 0],
45+
[0, 0]
46+
],
47+
'GENE2': [
48+
[1.5, 0.8],
49+
[2.3, 0.9],
50+
[0.8, 0.4]
51+
]
52+
}
53+
}
54+
55+
// Mock pre-computed data with single cell type
56+
export const PRECOMPUTED_SINGLE_CELL_TYPE = {
57+
annotation_name: 'cell_type',
58+
values: ['Neurons'],
59+
genes: {
60+
'GENE1': [[2.5, 0.95]],
61+
'GENE2': [[1.8, 0.75]]
62+
}
63+
}
64+
65+
// Expected Morpheus dataset structure after conversion
66+
export const EXPECTED_MORPHEUS_STRUCTURE = {
67+
seriesCount: 2,
68+
series0Name: 'Mean Expression',
69+
series1Name: 'percent',
70+
rowCount: 4, // 4 genes in PRECOMPUTED_DOT_PLOT_DATA
71+
columnCount: 4 // 4 cell types
72+
}
73+
74+
// Mock feature flags
75+
export const FEATURE_FLAGS_ENABLED = {
76+
dot_plot_preprocessing_frontend: true
77+
}
78+
79+
export const FEATURE_FLAGS_DISABLED = {
80+
dot_plot_preprocessing_frontend: false
81+
}

0 commit comments

Comments
 (0)