@complat/react-spectra-editor 1.7.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/LICENSE +21 -662
- package/README.md +5 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp.js +2329 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_2.js +2874 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_mz_chemstation.js +3242 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_tic_chemstation.js +854 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_tic_neg.js +1233 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_tic_pos.js +1233 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_uvvis.js +48908 -0
- package/dist/__tests__/fixtures/lc_ms_jcamp_uvvis_chemstation.js +15424 -0
- package/dist/__tests__/units/components/cmd_bar/r05_submit_btn.test.js +158 -3
- package/dist/__tests__/units/components/d3_line_rect.test.js +85 -0
- package/dist/__tests__/units/components/d3_multi/multi_focus.test.js +43 -0
- package/dist/__tests__/units/components/hplc_viewer.test.js +123 -0
- package/dist/__tests__/units/components/panel/info.test.js +55 -15
- package/dist/__tests__/units/features/lc-ms/parsing/lcmsCategory.test.js +73 -0
- package/dist/__tests__/units/features/lc-ms/submit/peaks.test.js +310 -0
- package/dist/actions/curve.js +5 -2
- package/dist/actions/hplc_ms.js +66 -0
- package/dist/actions/integration.js +17 -2
- package/dist/actions/ui.js +39 -11
- package/dist/app.js +21 -8
- package/dist/components/cmd_bar/01_viewer.js +15 -11
- package/dist/components/cmd_bar/03_peak.js +25 -16
- package/dist/components/cmd_bar/04_integration.js +116 -17
- package/dist/components/cmd_bar/08_peak_group.js +83 -0
- package/dist/components/cmd_bar/collapsible_toolbar_group.js +101 -0
- package/dist/components/cmd_bar/common.js +4 -3
- package/dist/components/cmd_bar/index.js +76 -18
- package/dist/components/cmd_bar/r01_layout.js +6 -0
- package/dist/components/cmd_bar/r02_scan.js +15 -11
- package/dist/components/cmd_bar/r03_threshold.js +19 -3
- package/dist/components/cmd_bar/r04_submit.js +61 -6
- package/dist/components/cmd_bar/r05_submit_btn.js +60 -13
- package/dist/components/cmd_bar/r06_predict_btn.js +4 -4
- package/dist/components/cmd_bar/r07_wavelength_btn.js +10 -9
- package/dist/components/cmd_bar/r09_detector.js +2 -2
- package/dist/components/cmd_bar/tri_btn.js +4 -1
- package/dist/components/common/draw.js +6 -5
- package/dist/components/d3_line/index.js +70 -15
- package/dist/components/d3_line/line_focus.js +104 -67
- package/dist/components/d3_line_rect/index.js +836 -0
- package/dist/components/d3_line_rect/line_focus.js +526 -0
- package/dist/components/d3_line_rect/multi_focus.js +433 -0
- package/dist/components/d3_line_rect/rect_focus.js +247 -0
- package/dist/components/d3_multi/index.js +154 -163
- package/dist/components/d3_multi/multi_focus.js +117 -68
- package/dist/components/d3_rect/index.js +6 -0
- package/dist/components/d3_rect/rect_focus.js +17 -5
- package/dist/components/hplc_viewer.js +169 -0
- package/dist/components/lc_ms_uv_tools_bar.js +175 -0
- package/dist/components/multi_jcamps_viewer.js +17 -5
- package/dist/components/panel/compare.js +84 -62
- package/dist/components/panel/cyclic_voltamery_data.js +15 -14
- package/dist/components/panel/graph_selection.js +32 -30
- package/dist/components/panel/index.js +28 -22
- package/dist/components/panel/info.js +75 -26
- package/dist/constants/action_type.js +23 -2
- package/dist/constants/list_graph.js +16 -0
- package/dist/constants/list_layout.js +2 -1
- package/dist/constants/list_ui.js +5 -2
- package/dist/features/lc-ms/entities/extractEntityLCMS.js +187 -0
- package/dist/features/lc-ms/parsing/chemstation.js +108 -0
- package/dist/features/lc-ms/parsing/index.js +46 -0
- package/dist/features/lc-ms/parsing/lcmsCategory.js +44 -0
- package/dist/features/lc-ms/parsing/lcmsJcampInfo.js +18 -0
- package/dist/features/lc-ms/parsing/lcmsMsPage.js +241 -0
- package/dist/features/lc-ms/parsing/pageValue.js +27 -0
- package/dist/features/lc-ms/submit/index.js +24 -0
- package/dist/features/lc-ms/submit/peaks.js +66 -0
- package/dist/features/lc-ms/ui/wavelengthSelect.js +54 -0
- package/dist/fn.js +4 -1
- package/dist/helpers/brush.js +74 -19
- package/dist/helpers/calc.js +4 -2
- package/dist/helpers/cfg.js +5 -4
- package/dist/helpers/chem.js +449 -71
- package/dist/helpers/compass.js +181 -17
- package/dist/helpers/extractEntityLCMS.js +24 -0
- package/dist/helpers/extractParams.js +118 -33
- package/dist/helpers/extractPeaksEdit.js +29 -9
- package/dist/helpers/format.js +189 -4
- package/dist/helpers/init.js +25 -5
- package/dist/helpers/integration.js +130 -17
- package/dist/helpers/integration_draft.js +43 -0
- package/dist/helpers/integration_focus.js +155 -0
- package/dist/helpers/integration_jcamp.js +68 -0
- package/dist/helpers/integration_split.js +202 -0
- package/dist/helpers/mount.js +8 -1
- package/dist/helpers/sweep.js +39 -0
- package/dist/index.js +284 -26
- package/dist/layer_content.js +17 -3
- package/dist/layer_init.js +124 -14
- package/dist/layer_prism.js +31 -5
- package/dist/reducers/index.js +3 -1
- package/dist/reducers/reducer_curve.js +54 -36
- package/dist/reducers/reducer_hplc_ms/hydrate.js +289 -0
- package/dist/reducers/reducer_hplc_ms/index.js +122 -0
- package/dist/reducers/reducer_hplc_ms/persistence.js +74 -0
- package/dist/reducers/reducer_hplc_ms/tic.js +70 -0
- package/dist/reducers/reducer_hplc_ms/utils.js +70 -0
- package/dist/reducers/reducer_hplc_ms/uvvis.js +377 -0
- package/dist/reducers/reducer_integration.js +265 -7
- package/dist/reducers/reducer_layout.js +1 -1
- package/dist/reducers/reducer_submit.js +2 -1
- package/dist/reducers/reducer_ui.js +149 -13
- package/dist/reducers/undo_redo_config.js +2 -2
- package/dist/sagas/saga_lcms_ui.js +85 -0
- package/dist/sagas/saga_ui.js +177 -74
- package/dist/setupTests.js +5 -5
- package/package.json +10 -7
|
@@ -5,13 +5,24 @@ var _reduxMockStore = _interopRequireDefault(require("redux-mock-store"));
|
|
|
5
5
|
var _reactRedux = require("react-redux");
|
|
6
6
|
var _react = require("@testing-library/react");
|
|
7
7
|
require("@testing-library/jest-dom");
|
|
8
|
-
var _r05_submit_btn =
|
|
8
|
+
var _r05_submit_btn = _interopRequireWildcard(require("../../../../components/cmd_bar/r05_submit_btn"));
|
|
9
|
+
var _format = _interopRequireDefault(require("../../../../helpers/format"));
|
|
9
10
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
10
12
|
jest.mock('../../../../helpers/extractPeaksEdit', () => ({
|
|
11
|
-
extractPeaksEdit:
|
|
13
|
+
extractPeaksEdit: () => [{
|
|
12
14
|
x: 1,
|
|
13
15
|
y: 2
|
|
14
|
-
}]
|
|
16
|
+
}],
|
|
17
|
+
formatLcmsPeaksForBackend: () => [{
|
|
18
|
+
peakMock: true
|
|
19
|
+
}],
|
|
20
|
+
formatLcmsIntegralsForBackend: () => [{
|
|
21
|
+
integralMock: true
|
|
22
|
+
}],
|
|
23
|
+
getLcmsMzPageData: () => ({
|
|
24
|
+
mzPageDataMock: true
|
|
25
|
+
})
|
|
15
26
|
}));
|
|
16
27
|
const mockStore = (0, _reduxMockStore.default)([]);
|
|
17
28
|
const buildBaseState = (overrides = {}) => ({
|
|
@@ -83,6 +94,7 @@ const buildBaseState = (overrides = {}) => ({
|
|
|
83
94
|
meta: {
|
|
84
95
|
dscMetaData: {}
|
|
85
96
|
},
|
|
97
|
+
hplcMs: {},
|
|
86
98
|
...overrides
|
|
87
99
|
});
|
|
88
100
|
const renderBtnSubmit = (state, operationValue) => {
|
|
@@ -214,4 +226,147 @@ describe('<BtnSubmit payload contract />', () => {
|
|
|
214
226
|
expect(noFlagsPayload.spectra_list[0]).not.toHaveProperty('keepPred');
|
|
215
227
|
expect(noFlagsPayload.spectra_list[0]).not.toHaveProperty('simulatenmr');
|
|
216
228
|
});
|
|
229
|
+
describe('layout LC/MS', () => {
|
|
230
|
+
const uvvisFeature = {
|
|
231
|
+
xUnit: 'min',
|
|
232
|
+
yUnit: 'mAU',
|
|
233
|
+
scanAutoTarget: 1,
|
|
234
|
+
thresRef: 3
|
|
235
|
+
};
|
|
236
|
+
let formatedLcmsSpy;
|
|
237
|
+
beforeEach(() => {
|
|
238
|
+
formatedLcmsSpy = jest.spyOn(_format.default, 'formatedLCMS').mockReturnValue('lcms_head_text');
|
|
239
|
+
});
|
|
240
|
+
afterEach(() => {
|
|
241
|
+
formatedLcmsSpy.mockRestore();
|
|
242
|
+
});
|
|
243
|
+
it('replicates lcms_* onto each UVVIS entry in spectra_list', () => {
|
|
244
|
+
const operationValue = jest.fn();
|
|
245
|
+
const state = buildBaseState({
|
|
246
|
+
layout: 'LC/MS',
|
|
247
|
+
curve: {
|
|
248
|
+
curveIdx: 0,
|
|
249
|
+
listCurves: [{
|
|
250
|
+
lcmsKind: 'uvvis',
|
|
251
|
+
feature: {
|
|
252
|
+
...uvvisFeature,
|
|
253
|
+
scanAutoTarget: 1
|
|
254
|
+
}
|
|
255
|
+
}, {
|
|
256
|
+
lcmsKind: 'uvvis',
|
|
257
|
+
feature: {
|
|
258
|
+
...uvvisFeature,
|
|
259
|
+
scanAutoTarget: 2
|
|
260
|
+
}
|
|
261
|
+
}]
|
|
262
|
+
},
|
|
263
|
+
hplcMs: {
|
|
264
|
+
uvvis: {
|
|
265
|
+
selectedWaveLength: 220
|
|
266
|
+
},
|
|
267
|
+
tic: {
|
|
268
|
+
currentPageValue: 1.25
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
renderBtnSubmit(state, operationValue);
|
|
273
|
+
const payload = operationValue.mock.calls[0][0];
|
|
274
|
+
expect(payload.spectra_list).toHaveLength(2);
|
|
275
|
+
payload.spectra_list.forEach(entry => {
|
|
276
|
+
expect(entry.lcms_peaks).toEqual([{
|
|
277
|
+
peakMock: true
|
|
278
|
+
}]);
|
|
279
|
+
expect(entry.lcms_integrals).toEqual([{
|
|
280
|
+
integralMock: true
|
|
281
|
+
}]);
|
|
282
|
+
expect(entry.lcms_integrations_export).toBe('percent');
|
|
283
|
+
expect(entry.lcms_peaks_text).toBe('lcms_head_text');
|
|
284
|
+
expect(entry.lcms_uvvis_wavelength).toBe(220);
|
|
285
|
+
expect(entry.lcms_mz_page).toBe(1.25);
|
|
286
|
+
expect(entry.lcms_mz_page_data).toEqual({
|
|
287
|
+
mzPageDataMock: true
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
expect(payload.lcms_peaks).toEqual([{
|
|
291
|
+
peakMock: true
|
|
292
|
+
}]);
|
|
293
|
+
expect(formatedLcmsSpy).toHaveBeenCalled();
|
|
294
|
+
});
|
|
295
|
+
it('with no UVVIS in listCurves (fallback to feature), no lcms_* on the spectrum item', () => {
|
|
296
|
+
const operationValue = jest.fn();
|
|
297
|
+
const state = buildBaseState({
|
|
298
|
+
layout: 'LC/MS',
|
|
299
|
+
curve: {
|
|
300
|
+
curveIdx: 0,
|
|
301
|
+
listCurves: [{
|
|
302
|
+
lcmsKind: 'tic',
|
|
303
|
+
feature: uvvisFeature
|
|
304
|
+
}]
|
|
305
|
+
},
|
|
306
|
+
hplcMs: {
|
|
307
|
+
uvvis: {
|
|
308
|
+
selectedWaveLength: 210
|
|
309
|
+
},
|
|
310
|
+
tic: {
|
|
311
|
+
currentPageValue: 0.5
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
renderBtnSubmit(state, operationValue);
|
|
316
|
+
const payload = operationValue.mock.calls[0][0];
|
|
317
|
+
expect(payload.spectra_list).toHaveLength(1);
|
|
318
|
+
const entry = payload.spectra_list[0];
|
|
319
|
+
expect(entry).not.toHaveProperty('lcms_peaks');
|
|
320
|
+
expect(entry).not.toHaveProperty('lcms_integrals');
|
|
321
|
+
expect(entry).not.toHaveProperty('lcms_peaks_text');
|
|
322
|
+
expect(payload.lcms_peaks).toEqual([{
|
|
323
|
+
peakMock: true
|
|
324
|
+
}]);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Regression for review finding RR-1 (B5 remainder): the CV current-density factor
|
|
329
|
+
// used on submit/export must match the chart (multi_focus.computeYTransformFactor)
|
|
330
|
+
// and panel — i.e. one conversion to A/cm², not a double /100 for mm².
|
|
331
|
+
describe('computeCvYScaleFactor — CV current-density factor (RR-1 / B5)', () => {
|
|
332
|
+
const feature = {
|
|
333
|
+
yUnit: 'A'
|
|
334
|
+
};
|
|
335
|
+
it('returns 1.0 when current density is off', () => {
|
|
336
|
+
expect((0, _r05_submit_btn.computeCvYScaleFactor)(feature, {
|
|
337
|
+
useCurrentDensity: false
|
|
338
|
+
})).toEqual(1.0);
|
|
339
|
+
});
|
|
340
|
+
it('treats 100 mm² the same as 1 cm² (no double /100)', () => {
|
|
341
|
+
const fMm2 = (0, _r05_submit_btn.computeCvYScaleFactor)(feature, {
|
|
342
|
+
useCurrentDensity: true,
|
|
343
|
+
areaValue: 100,
|
|
344
|
+
areaUnit: 'mm²'
|
|
345
|
+
});
|
|
346
|
+
const fCm2 = (0, _r05_submit_btn.computeCvYScaleFactor)(feature, {
|
|
347
|
+
useCurrentDensity: true,
|
|
348
|
+
areaValue: 1,
|
|
349
|
+
areaUnit: 'cm²'
|
|
350
|
+
});
|
|
351
|
+
expect(fMm2).toBeCloseTo(fCm2);
|
|
352
|
+
expect(fMm2).toBeCloseTo(1.0); // pre-fix this was 0.01 (100x too small)
|
|
353
|
+
});
|
|
354
|
+
it('gives A/cm² for a mm² area (factor = 100 / area_mm²)', () => {
|
|
355
|
+
// 50 mm² == 0.5 cm² → factor 1/0.5 = 2
|
|
356
|
+
expect((0, _r05_submit_btn.computeCvYScaleFactor)(feature, {
|
|
357
|
+
useCurrentDensity: true,
|
|
358
|
+
areaValue: 50,
|
|
359
|
+
areaUnit: 'mm²'
|
|
360
|
+
})).toBeCloseTo(2.0);
|
|
361
|
+
});
|
|
362
|
+
it('scales by 1000 for mA while keeping the area conversion', () => {
|
|
363
|
+
expect((0, _r05_submit_btn.computeCvYScaleFactor)({
|
|
364
|
+
yUnit: 'mA'
|
|
365
|
+
}, {
|
|
366
|
+
useCurrentDensity: true,
|
|
367
|
+
areaValue: 100,
|
|
368
|
+
areaUnit: 'mm²'
|
|
369
|
+
})).toBeCloseTo(1000.0);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
217
372
|
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _index = require("../../../components/d3_line_rect/index");
|
|
5
|
+
var _multi_focus = require("../../../components/d3_line_rect/multi_focus");
|
|
6
|
+
var _rect_focus = _interopRequireDefault(require("../../../components/d3_line_rect/rect_focus"));
|
|
7
|
+
describe('isLcmsMsPageLoading', () => {
|
|
8
|
+
const buildMzEntity = (polarity, pageValues) => ({
|
|
9
|
+
layout: 'LC/MS',
|
|
10
|
+
lcmsKind: 'mz',
|
|
11
|
+
lcmsPolarity: polarity,
|
|
12
|
+
features: pageValues.map(pageValue => ({
|
|
13
|
+
pageValue,
|
|
14
|
+
data: [{
|
|
15
|
+
x: [100, 101],
|
|
16
|
+
y: [10, 5]
|
|
17
|
+
}]
|
|
18
|
+
}))
|
|
19
|
+
});
|
|
20
|
+
it('returns true when the requested RT is not available yet', () => {
|
|
21
|
+
const state = {
|
|
22
|
+
tic: {
|
|
23
|
+
polarity: 'positive',
|
|
24
|
+
currentPageValue: 2.5
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
expect((0, _index.isLcmsMsPageLoading)([buildMzEntity('positive', [1.2])], state)).toEqual(true);
|
|
28
|
+
});
|
|
29
|
+
it('returns false when the requested RT is already present', () => {
|
|
30
|
+
const state = {
|
|
31
|
+
tic: {
|
|
32
|
+
polarity: 'negative',
|
|
33
|
+
currentPageValue: 2.5
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
expect((0, _index.isLcmsMsPageLoading)([buildMzEntity('positive', [1.2]), buildMzEntity('negative', [2.5])], state)).toEqual(false);
|
|
37
|
+
});
|
|
38
|
+
it('prefers persisted polarity over default curveIdx when reopening the editor', () => {
|
|
39
|
+
const ticEntities = [{
|
|
40
|
+
lcmsPolarity: 'positive'
|
|
41
|
+
}, {
|
|
42
|
+
lcmsPolarity: 'negative'
|
|
43
|
+
}];
|
|
44
|
+
expect((0, _multi_focus.pickTicIndex)(ticEntities, 0, 'negative')).toEqual(1);
|
|
45
|
+
});
|
|
46
|
+
it('falls back to curveIdx when polarity is unavailable', () => {
|
|
47
|
+
const ticEntities = [{
|
|
48
|
+
lcmsPolarity: 'positive'
|
|
49
|
+
}, {
|
|
50
|
+
lcmsPolarity: 'negative'
|
|
51
|
+
}];
|
|
52
|
+
expect((0, _multi_focus.pickTicIndex)(ticEntities, 1, null)).toEqual(1);
|
|
53
|
+
});
|
|
54
|
+
it('returns true when no MS page has been received yet', () => {
|
|
55
|
+
const state = {
|
|
56
|
+
tic: {
|
|
57
|
+
polarity: 'positive',
|
|
58
|
+
currentPageValue: 2.5
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
expect((0, _index.isLcmsMsPageLoading)([], state)).toEqual(true);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Review finding B7 (#232): drawBar reads tTrEndPts[0].y. Clearing the
|
|
66
|
+
// threshold makes convertThresEndPts return [] (see chem.test.tsx) while the
|
|
67
|
+
// MS bars are still present, so drawBar must guard the empty endpoint list
|
|
68
|
+
// instead of crashing.
|
|
69
|
+
describe('RectFocus.drawBar with an empty threshold-endpoint list (B7)', () => {
|
|
70
|
+
it('does not crash when tTrEndPts is empty but bars exist', () => {
|
|
71
|
+
const rf = Object.create(_rect_focus.default.prototype);
|
|
72
|
+
rf.bars = {}; // truthy → passes the `if (!this.bars)` guard
|
|
73
|
+
rf.scales = {
|
|
74
|
+
x: v => v,
|
|
75
|
+
y: v => v
|
|
76
|
+
}; // TfRescale reads focus.scales.{x,y}
|
|
77
|
+
rf.updatePathCall = () => {}; // stub out the d3 path update
|
|
78
|
+
rf.data = [{
|
|
79
|
+
x: 1,
|
|
80
|
+
y: 2
|
|
81
|
+
}]; // bars present
|
|
82
|
+
rf.tTrEndPts = []; // cleared threshold → empty endpoints
|
|
83
|
+
expect(() => rf.drawBar()).not.toThrow();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _multi_focus = _interopRequireDefault(require("../../../../components/d3_multi/multi_focus"));
|
|
5
|
+
var _list_layout = require("../../../../constants/list_layout");
|
|
6
|
+
// Review finding B5 (#232): the CV current-density factor on the chart
|
|
7
|
+
// (computeYTransformFactor) must convert the electrode area to cm² exactly
|
|
8
|
+
// once. Physically 100 mm² == 1 cm², so the factor for the two must match —
|
|
9
|
+
// double-dividing by 100 for mm² made it 100x too small.
|
|
10
|
+
// (computeYTransformFactor is pure — it ignores `this` — so it is called via
|
|
11
|
+
// the prototype.)
|
|
12
|
+
describe('MultiFocus.computeYTransformFactor — CV current density (B5)', () => {
|
|
13
|
+
const compute = cvSt => _multi_focus.default.prototype.computeYTransformFactor.call({}, _list_layout.LIST_LAYOUT.CYCLIC_VOLTAMMETRY, cvSt, {
|
|
14
|
+
yUnit: 'A'
|
|
15
|
+
});
|
|
16
|
+
it('treats 100 mm² the same as 1 cm²', () => {
|
|
17
|
+
const fMm2 = compute({
|
|
18
|
+
useCurrentDensity: true,
|
|
19
|
+
areaValue: 100,
|
|
20
|
+
areaUnit: 'mm²'
|
|
21
|
+
});
|
|
22
|
+
const fCm2 = compute({
|
|
23
|
+
useCurrentDensity: true,
|
|
24
|
+
areaValue: 1,
|
|
25
|
+
areaUnit: 'cm²'
|
|
26
|
+
});
|
|
27
|
+
expect(fMm2).toBeCloseTo(fCm2);
|
|
28
|
+
expect(fMm2).toBeCloseTo(1.0); // double /100 for mm² gives 0.01
|
|
29
|
+
});
|
|
30
|
+
it('gives A/cm² for a mm² area (factor = 100 / area_mm²)', () => {
|
|
31
|
+
// 50 mm² == 0.5 cm² → factor 1 / 0.5 = 2
|
|
32
|
+
expect(compute({
|
|
33
|
+
useCurrentDensity: true,
|
|
34
|
+
areaValue: 50,
|
|
35
|
+
areaUnit: 'mm²'
|
|
36
|
+
})).toBeCloseTo(2.0);
|
|
37
|
+
});
|
|
38
|
+
it('returns 1.0 when current density is off', () => {
|
|
39
|
+
expect(compute({
|
|
40
|
+
useCurrentDensity: false
|
|
41
|
+
})).toBeCloseTo(1.0);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _react = _interopRequireDefault(require("react"));
|
|
5
|
+
var _react2 = require("@testing-library/react");
|
|
6
|
+
require("@testing-library/jest-dom");
|
|
7
|
+
var _reduxMockStore = _interopRequireDefault(require("redux-mock-store"));
|
|
8
|
+
var _reactRedux = require("react-redux");
|
|
9
|
+
var _material = require("@mui/material");
|
|
10
|
+
var _styles = require("@mui/styles");
|
|
11
|
+
var _hplc_viewer = _interopRequireDefault(require("../../../components/hplc_viewer"));
|
|
12
|
+
var _list_layout = require("../../../constants/list_layout");
|
|
13
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
+
jest.mock('../../../components/cmd_bar/index', () => props => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
15
|
+
"data-testid": "cmd-bar",
|
|
16
|
+
children: [props.editorOnly ? 'editorOnly' : 'editable', "-", props.hideThreshold ? 'hideThreshold' : 'showThreshold']
|
|
17
|
+
}));
|
|
18
|
+
jest.mock('../../../components/d3_line_rect/index', () => props => /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
19
|
+
"data-testid": "viewer-line-rect",
|
|
20
|
+
children: ["tic:", props.ticEntities?.length || 0, "-uvvis:", props.uvvisEntities?.length || 0, "-mz:", props.mzEntities?.length || 0]
|
|
21
|
+
}));
|
|
22
|
+
jest.mock('../../../components/panel/index', () => props => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
23
|
+
"data-testid": "panel-viewer",
|
|
24
|
+
children: props.integration ? 'hasIntegration' : 'noIntegration'
|
|
25
|
+
}));
|
|
26
|
+
const mockStore = (0, _reduxMockStore.default)([]);
|
|
27
|
+
const theme = (0, _material.createTheme)();
|
|
28
|
+
const renderWithStore = (state, extraProps = {}) => {
|
|
29
|
+
const store = mockStore(state);
|
|
30
|
+
return (0, _react2.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactRedux.Provider, {
|
|
31
|
+
store: store,
|
|
32
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.ThemeProvider, {
|
|
33
|
+
theme: theme,
|
|
34
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_hplc_viewer.default, {
|
|
35
|
+
operations: [],
|
|
36
|
+
entityFileNames: [],
|
|
37
|
+
userManualLink: {},
|
|
38
|
+
molSvg: "",
|
|
39
|
+
theoryMass: "",
|
|
40
|
+
descriptions: [],
|
|
41
|
+
canChangeDescription: false,
|
|
42
|
+
onDescriptionChanged: () => {},
|
|
43
|
+
editorOnly: true,
|
|
44
|
+
...extraProps
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
}));
|
|
48
|
+
};
|
|
49
|
+
describe('<HPLCViewer />', () => {
|
|
50
|
+
it('renders empty view when there are no entities', () => {
|
|
51
|
+
renderWithStore({
|
|
52
|
+
curve: {
|
|
53
|
+
listCurves: [],
|
|
54
|
+
curveIdx: 0
|
|
55
|
+
},
|
|
56
|
+
layout: _list_layout.LIST_LAYOUT.LC_MS,
|
|
57
|
+
integration: {
|
|
58
|
+
present: {
|
|
59
|
+
integrations: []
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
hplcMs: {}
|
|
63
|
+
});
|
|
64
|
+
expect(_react2.screen.queryByTestId('cmd-bar')).not.toBeInTheDocument();
|
|
65
|
+
expect(_react2.screen.queryByTestId('viewer-line-rect')).not.toBeInTheDocument();
|
|
66
|
+
expect(_react2.screen.queryByTestId('panel-viewer')).not.toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
it('renders LCMS blocks with split entities and selected integration', () => {
|
|
69
|
+
const entities = [{
|
|
70
|
+
csCategory: ['tic', 'positive'],
|
|
71
|
+
feature: {
|
|
72
|
+
xUnit: 'min',
|
|
73
|
+
yUnit: 'intensity'
|
|
74
|
+
},
|
|
75
|
+
topic: {
|
|
76
|
+
x: [1, 2],
|
|
77
|
+
y: [10, 20]
|
|
78
|
+
}
|
|
79
|
+
}, {
|
|
80
|
+
csCategory: ['uvvis'],
|
|
81
|
+
feature: {
|
|
82
|
+
xUnit: 'nm',
|
|
83
|
+
yUnit: 'AU'
|
|
84
|
+
},
|
|
85
|
+
topic: {
|
|
86
|
+
x: [210],
|
|
87
|
+
y: [0.4]
|
|
88
|
+
}
|
|
89
|
+
}, {
|
|
90
|
+
csCategory: ['mz', 'negative'],
|
|
91
|
+
feature: {
|
|
92
|
+
xUnit: 'm/z',
|
|
93
|
+
yUnit: 'counts'
|
|
94
|
+
},
|
|
95
|
+
topic: {
|
|
96
|
+
x: [100],
|
|
97
|
+
y: [5]
|
|
98
|
+
}
|
|
99
|
+
}];
|
|
100
|
+
renderWithStore({
|
|
101
|
+
curve: {
|
|
102
|
+
listCurves: entities,
|
|
103
|
+
curveIdx: 1
|
|
104
|
+
},
|
|
105
|
+
layout: _list_layout.LIST_LAYOUT.LC_MS,
|
|
106
|
+
integration: {
|
|
107
|
+
present: {
|
|
108
|
+
integrations: [null, {
|
|
109
|
+
id: 'int-2'
|
|
110
|
+
}, null]
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
hplcMs: {
|
|
114
|
+
tic: {
|
|
115
|
+
polarity: 'positive'
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
expect(_react2.screen.getByTestId('cmd-bar')).toHaveTextContent('editorOnly-hideThreshold');
|
|
120
|
+
expect(_react2.screen.getByTestId('viewer-line-rect')).toHaveTextContent('tic:1-uvvis:1-mz:1');
|
|
121
|
+
expect(_react2.screen.getByTestId('panel-viewer')).toHaveTextContent('hasIntegration');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -23,7 +23,9 @@ const store = mockStore({
|
|
|
23
23
|
shift: {
|
|
24
24
|
shifts: []
|
|
25
25
|
},
|
|
26
|
-
simulation: {
|
|
26
|
+
simulation: {
|
|
27
|
+
nmrSimPeaks: []
|
|
28
|
+
},
|
|
27
29
|
detector: {
|
|
28
30
|
curves: [{
|
|
29
31
|
curveIdx: 0,
|
|
@@ -33,9 +35,16 @@ const store = mockStore({
|
|
|
33
35
|
}
|
|
34
36
|
}]
|
|
35
37
|
},
|
|
36
|
-
meta: {
|
|
38
|
+
meta: {
|
|
39
|
+
dscMetaData: {}
|
|
40
|
+
},
|
|
41
|
+
hplcMs: {
|
|
42
|
+
uvvis: {
|
|
43
|
+
spectraList: [],
|
|
44
|
+
listWaveLength: []
|
|
45
|
+
}
|
|
46
|
+
}
|
|
37
47
|
});
|
|
38
|
-
const failedStore = mockStore({});
|
|
39
48
|
const dispatchMock = () => Promise.resolve({});
|
|
40
49
|
store.dispatch = jest.fn(dispatchMock);
|
|
41
50
|
const theme = (0, _material.createTheme)({
|
|
@@ -44,6 +53,14 @@ const theme = (0, _material.createTheme)({
|
|
|
44
53
|
}
|
|
45
54
|
});
|
|
46
55
|
const feature = {};
|
|
56
|
+
const baseProps = {
|
|
57
|
+
feature,
|
|
58
|
+
integration: {},
|
|
59
|
+
editorOnly: false,
|
|
60
|
+
molSvg: '',
|
|
61
|
+
descriptions: '',
|
|
62
|
+
canChangeDescription: false
|
|
63
|
+
};
|
|
47
64
|
describe("<InfoPanel />", () => {
|
|
48
65
|
let AppWrapper;
|
|
49
66
|
beforeEach(() => {
|
|
@@ -57,37 +74,60 @@ describe("<InfoPanel />", () => {
|
|
|
57
74
|
});
|
|
58
75
|
};
|
|
59
76
|
});
|
|
60
|
-
test('
|
|
77
|
+
test('Render info panel', () => {
|
|
61
78
|
const renderer = /*#__PURE__*/(0, _jsxRuntime.jsx)(AppWrapper, {
|
|
62
79
|
store: store,
|
|
63
80
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.ThemeProvider, {
|
|
64
81
|
theme: theme,
|
|
65
82
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_info.default, {
|
|
66
83
|
expand: false,
|
|
67
|
-
|
|
84
|
+
onExpand: () => {},
|
|
85
|
+
...baseProps
|
|
68
86
|
})
|
|
69
87
|
})
|
|
70
88
|
});
|
|
71
89
|
const {
|
|
72
90
|
queryByTestId
|
|
73
91
|
} = (0, _react2.render)(renderer);
|
|
74
|
-
expect(queryByTestId('PanelInfo')).
|
|
92
|
+
expect(queryByTestId('PanelInfo')).toBeInTheDocument();
|
|
75
93
|
});
|
|
76
|
-
test('Render
|
|
94
|
+
test('Render M+ exact mass for MS layout', () => {
|
|
95
|
+
const msStore = mockStore({
|
|
96
|
+
curve: {
|
|
97
|
+
listCurves: [{
|
|
98
|
+
feature: {}
|
|
99
|
+
}],
|
|
100
|
+
curveIdx: 0
|
|
101
|
+
},
|
|
102
|
+
layout: _list_layout.LIST_LAYOUT.MS,
|
|
103
|
+
shift: {
|
|
104
|
+
shifts: []
|
|
105
|
+
},
|
|
106
|
+
simulation: [],
|
|
107
|
+
detector: {
|
|
108
|
+
curves: [{
|
|
109
|
+
curveIdx: 0,
|
|
110
|
+
selectedDetector: {
|
|
111
|
+
name: 'Refractive index',
|
|
112
|
+
label: 'RI'
|
|
113
|
+
}
|
|
114
|
+
}]
|
|
115
|
+
},
|
|
116
|
+
meta: {}
|
|
117
|
+
});
|
|
77
118
|
const renderer = /*#__PURE__*/(0, _jsxRuntime.jsx)(AppWrapper, {
|
|
78
|
-
store:
|
|
119
|
+
store: msStore,
|
|
79
120
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.ThemeProvider, {
|
|
80
121
|
theme: theme,
|
|
81
122
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_info.default, {
|
|
82
|
-
expand:
|
|
83
|
-
|
|
84
|
-
feature: feature
|
|
123
|
+
expand: true,
|
|
124
|
+
onExpand: () => {},
|
|
125
|
+
feature: feature,
|
|
126
|
+
exactMass: "121.0653"
|
|
85
127
|
})
|
|
86
128
|
})
|
|
87
129
|
});
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
} = (0, _react2.render)(renderer);
|
|
91
|
-
expect(queryByTestId('PanelInfo')).toBeInTheDocument();
|
|
130
|
+
(0, _react2.render)(renderer);
|
|
131
|
+
expect(_react2.screen.getByText('121.064751 g/mol')).toBeInTheDocument();
|
|
92
132
|
});
|
|
93
133
|
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _lcmsCategory = require("../../../../../features/lc-ms/parsing/lcmsCategory");
|
|
4
|
+
describe('lc-ms/parsing lcmsCategory', () => {
|
|
5
|
+
describe('normalizeLcMsMode', () => {
|
|
6
|
+
it('maps vendor strings to NEGATIVE / POSITIVE / NEUTRAL', () => {
|
|
7
|
+
expect((0, _lcmsCategory.normalizeLcMsMode)('Positive Mode')).toBe('POSITIVE');
|
|
8
|
+
expect((0, _lcmsCategory.normalizeLcMsMode)('NEGATIV')).toBe('NEGATIVE');
|
|
9
|
+
expect((0, _lcmsCategory.normalizeLcMsMode)('neutral scan')).toBe('NEUTRAL');
|
|
10
|
+
});
|
|
11
|
+
it('returns NEUTRAL for empty or unknown', () => {
|
|
12
|
+
expect((0, _lcmsCategory.normalizeLcMsMode)('')).toBe('NEUTRAL');
|
|
13
|
+
expect((0, _lcmsCategory.normalizeLcMsMode)(null)).toBe('NEUTRAL');
|
|
14
|
+
expect((0, _lcmsCategory.normalizeLcMsMode)('unknown')).toBe('NEUTRAL');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe('inferLcMsKind', () => {
|
|
18
|
+
it('detects TIC from MASS TIC or CHROMATOGRAM', () => {
|
|
19
|
+
expect((0, _lcmsCategory.inferLcMsKind)({
|
|
20
|
+
dataType: 'MASS TIC'
|
|
21
|
+
}, {})).toBe('TIC');
|
|
22
|
+
expect((0, _lcmsCategory.inferLcMsKind)({}, {
|
|
23
|
+
dataType: 'mass tic'
|
|
24
|
+
})).toBe('TIC');
|
|
25
|
+
expect((0, _lcmsCategory.inferLcMsKind)({}, {
|
|
26
|
+
info: {
|
|
27
|
+
TYPE: 'CHROMATOGRAM'
|
|
28
|
+
}
|
|
29
|
+
})).toBe('TIC');
|
|
30
|
+
});
|
|
31
|
+
it('detects MZ from MASS SPECTRUM', () => {
|
|
32
|
+
expect((0, _lcmsCategory.inferLcMsKind)({
|
|
33
|
+
dataType: 'MASS SPECTRUM'
|
|
34
|
+
}, {})).toBe('MZ');
|
|
35
|
+
});
|
|
36
|
+
it('uses time + intensity units as TIC', () => {
|
|
37
|
+
expect((0, _lcmsCategory.inferLcMsKind)({
|
|
38
|
+
xUnit: 'Minutes',
|
|
39
|
+
yUnit: 'Intensity'
|
|
40
|
+
}, {})).toBe('TIC');
|
|
41
|
+
});
|
|
42
|
+
it('uses m/z axis as MZ', () => {
|
|
43
|
+
expect((0, _lcmsCategory.inferLcMsKind)({
|
|
44
|
+
xUnit: 'm/z'
|
|
45
|
+
}, {})).toBe('MZ');
|
|
46
|
+
});
|
|
47
|
+
it('defaults to SPECTRUM when nothing matches', () => {
|
|
48
|
+
expect((0, _lcmsCategory.inferLcMsKind)({}, {})).toBe('SPECTRUM');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('inferLcMsCategory', () => {
|
|
52
|
+
it('returns existing csCategory when present', () => {
|
|
53
|
+
expect((0, _lcmsCategory.inferLcMsCategory)({
|
|
54
|
+
csCategory: 'CUSTOM LABEL'
|
|
55
|
+
}, {})).toBe('CUSTOM LABEL');
|
|
56
|
+
});
|
|
57
|
+
it('builds TIC / MZ + mode + SPECTRUM when not preset', () => {
|
|
58
|
+
const jcamp = {
|
|
59
|
+
info: {
|
|
60
|
+
SCAN_MODE: 'Positive'
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const ticKind = {
|
|
64
|
+
dataType: 'MASS TIC'
|
|
65
|
+
};
|
|
66
|
+
expect((0, _lcmsCategory.inferLcMsCategory)(ticKind, jcamp)).toBe('TIC POSITIVE SPECTRUM');
|
|
67
|
+
const mzKind = {
|
|
68
|
+
dataType: 'MASS SPECTRUM'
|
|
69
|
+
};
|
|
70
|
+
expect((0, _lcmsCategory.inferLcMsCategory)(mzKind, jcamp)).toBe('MZ POSITIVE SPECTRUM');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|