jbrowse-plugin-msaview 3.4.1 → 3.6.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/README.md +7 -0
- package/dist/AddHighlightModel/index.js +3 -3
- package/dist/BgzipFastaMsaAdapter/BgzipFastaMsaAdapter.d.ts +8 -2
- package/dist/BgzipFastaMsaAdapter/configSchema.d.ts +3 -3
- package/dist/BgzipFastaMsaAdapter/configSchema.js +1 -1
- package/dist/LaunchMsaView/codingFeature.d.ts +14 -0
- package/dist/LaunchMsaView/codingFeature.js +38 -0
- package/dist/LaunchMsaView/codingFeature.test.js +75 -0
- package/dist/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.d.ts +3 -1
- package/dist/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.js +29 -26
- package/dist/LaunchMsaView/components/BlastQuery/BlastManualPanel.d.ts +3 -1
- package/dist/LaunchMsaView/components/BlastQuery/BlastManualPanel.js +7 -2
- package/dist/LaunchMsaView/components/BlastQuery/BlastPanel.d.ts +7 -3
- package/dist/LaunchMsaView/components/BlastQuery/BlastPanel.js +8 -7
- package/dist/LaunchMsaView/components/BlastQuery/BlastSettingsDialog.js +2 -2
- package/dist/LaunchMsaView/components/BlastQuery/MsaAlgorithmSelect.js +5 -3
- package/dist/LaunchMsaView/components/BlastQuery/consts.d.ts +26 -4
- package/dist/LaunchMsaView/components/BlastQuery/consts.js +68 -2
- package/dist/LaunchMsaView/components/BlastQuery/searchChoiceStorage.d.ts +1 -1
- package/dist/LaunchMsaView/components/HelpButton.d.ts +2 -0
- package/dist/LaunchMsaView/components/HelpButton.js +17 -0
- package/dist/LaunchMsaView/components/HelpDialog.d.ts +4 -0
- package/dist/LaunchMsaView/components/HelpDialog.js +18 -0
- package/dist/LaunchMsaView/components/LaunchMsaViewDialog.d.ts +3 -1
- package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +21 -16
- package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.d.ts +3 -1
- package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +10 -4
- package/dist/LaunchMsaView/components/ManualMSALoader/launchView.d.ts +3 -1
- package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js +2 -1
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologPanel.d.ts +3 -1
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologPanel.js +21 -7
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.js +4 -1
- package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.d.ts +3 -1
- package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +33 -15
- package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.d.ts +3 -1
- package/dist/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.js +2 -1
- package/dist/LaunchMsaView/components/QueryRowSelector.js +21 -5
- package/dist/LaunchMsaView/components/SequenceStatus.d.ts +14 -0
- package/dist/LaunchMsaView/components/SequenceStatus.js +15 -0
- package/dist/LaunchMsaView/components/SubmitCancelActions.d.ts +3 -1
- package/dist/LaunchMsaView/components/SubmitCancelActions.js +25 -13
- package/dist/LaunchMsaView/components/SubmitCancelActions.test.js +33 -3
- package/dist/LaunchMsaView/components/TabPanel.js +15 -3
- package/dist/LaunchMsaView/components/TabPanel.test.d.ts +1 -0
- package/dist/LaunchMsaView/components/TabPanel.test.js +36 -0
- package/dist/LaunchMsaView/components/TranscriptSelector.d.ts +3 -1
- package/dist/LaunchMsaView/components/TranscriptSelector.js +4 -2
- package/dist/LaunchMsaView/components/calculateProteinSequence.d.ts +4 -1
- package/dist/LaunchMsaView/components/calculateProteinSequence.js +20 -10
- package/dist/LaunchMsaView/components/fetchSeq.d.ts +4 -1
- package/dist/LaunchMsaView/components/fetchSeq.js +14 -4
- package/dist/LaunchMsaView/components/launchPlacement.d.ts +8 -0
- package/dist/LaunchMsaView/components/launchPlacement.js +25 -0
- package/dist/LaunchMsaView/components/useFeatureSequence.d.ts +2 -0
- package/dist/LaunchMsaView/components/useFeatureSequence.js +14 -11
- package/dist/LaunchMsaView/components/useTranscriptSelection.d.ts +10 -1
- package/dist/LaunchMsaView/components/useTranscriptSelection.js +21 -3
- package/dist/LaunchMsaView/components/useTranscriptSelection.test.d.ts +1 -0
- package/dist/LaunchMsaView/components/useTranscriptSelection.test.js +57 -0
- package/dist/LaunchMsaView/detectQueryRow.d.ts +11 -0
- package/dist/LaunchMsaView/detectQueryRow.js +11 -4
- package/dist/LaunchMsaView/detectQueryRow.test.js +30 -0
- package/dist/LaunchMsaView/index.js +28 -9
- package/dist/LaunchMsaView/launchTarget.d.ts +36 -8
- package/dist/LaunchMsaView/launchTarget.js +23 -13
- package/dist/LaunchMsaView/launchTarget.test.js +80 -15
- package/dist/LaunchMsaView/useQueryRowName.d.ts +13 -0
- package/dist/LaunchMsaView/useQueryRowName.js +16 -1
- package/dist/LaunchMsaView/useQueryRowName.test.d.ts +1 -0
- package/dist/LaunchMsaView/useQueryRowName.test.js +40 -0
- package/dist/LaunchMsaView/util.js +5 -2
- package/dist/LaunchMsaViewExtensionPoint/index.js +8 -6
- package/dist/LaunchMsaViewExtensionPoint/index.test.js +21 -0
- package/dist/MsaViewPanel/afterCreateAutoruns.d.ts +9 -6
- package/dist/MsaViewPanel/afterCreateAutoruns.js +72 -28
- package/dist/MsaViewPanel/components/LaunchProgress.d.ts +4 -3
- package/dist/MsaViewPanel/components/LaunchProgress.js +22 -10
- package/dist/MsaViewPanel/components/MsaViewPanel.js +10 -2
- package/dist/MsaViewPanel/components/MsaViewPanel.test.js +47 -2
- package/dist/MsaViewPanel/doLaunchBlast.d.ts +8 -0
- package/dist/MsaViewPanel/doLaunchBlast.js +78 -93
- package/dist/MsaViewPanel/doLaunchBlast.test.d.ts +1 -0
- package/dist/MsaViewPanel/doLaunchBlast.test.js +158 -0
- package/dist/MsaViewPanel/doLaunchOrthologs.js +40 -5
- package/dist/MsaViewPanel/doLaunchOrthologs.test.js +10 -0
- package/dist/MsaViewPanel/genomeToMSA.js +25 -7
- package/dist/MsaViewPanel/genomeToMSA.test.js +214 -19
- package/dist/MsaViewPanel/loadProteinDomains.d.ts +8 -2
- package/dist/MsaViewPanel/loadProteinDomains.js +18 -9
- package/dist/MsaViewPanel/loadProteinDomains.test.d.ts +1 -0
- package/dist/MsaViewPanel/loadProteinDomains.test.js +41 -0
- package/dist/MsaViewPanel/model.d.ts +265 -103
- package/dist/MsaViewPanel/model.js +174 -48
- package/dist/MsaViewPanel/model.test.d.ts +1 -0
- package/dist/MsaViewPanel/model.test.js +166 -0
- package/dist/MsaViewPanel/msaCoordToGenomeCoord.d.ts +12 -1
- package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +8 -8
- package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js +133 -32
- package/dist/MsaViewPanel/msaDataStore.d.ts +2 -0
- package/dist/MsaViewPanel/msaDataStore.js +10 -0
- package/dist/MsaViewPanel/observeProteinHighlights.test.js +20 -3
- package/dist/MsaViewPanel/processInit.test.d.ts +1 -0
- package/dist/MsaViewPanel/processInit.test.js +72 -0
- package/dist/MsaViewPanel/resolveConnectedTranscript.d.ts +9 -0
- package/dist/MsaViewPanel/resolveConnectedTranscript.js +128 -0
- package/dist/MsaViewPanel/runLaunch.d.ts +1 -0
- package/dist/MsaViewPanel/runLaunch.js +35 -0
- package/dist/MsaViewPanel/runLaunch.test.js +46 -0
- package/dist/MsaViewPanel/storedData.test.js +20 -0
- package/dist/MsaViewPanel/structureConnection.d.ts +0 -4
- package/dist/MsaViewPanel/structureConnection.js +0 -19
- package/dist/MsaViewPanel/syncGenomeHoverToMsaColumn.test.js +12 -5
- package/dist/MsaViewPanel/util.d.ts +39 -0
- package/dist/MsaViewPanel/util.js +44 -0
- package/dist/index.d.ts +11 -11
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +56 -68
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/utils/browserAlign.d.ts +42 -0
- package/dist/utils/browserAlign.js +297 -0
- package/dist/utils/browserAlign.test.d.ts +1 -0
- package/dist/utils/browserAlign.test.js +85 -0
- package/dist/utils/ebiBlast.d.ts +10 -1
- package/dist/utils/ebiBlast.js +27 -1
- package/dist/utils/homologSearch.d.ts +31 -0
- package/dist/utils/homologSearch.js +6 -0
- package/dist/utils/msa.d.ts +3 -11
- package/dist/utils/msa.js +14 -29
- package/dist/utils/msaRows.d.ts +11 -8
- package/dist/utils/msaRows.js +14 -12
- package/dist/utils/phmmer.d.ts +11 -1
- package/dist/utils/phmmer.js +49 -12
- package/dist/utils/unirefHomologs.d.ts +94 -0
- package/dist/utils/unirefHomologs.js +193 -0
- package/dist/utils/unirefHomologs.test.d.ts +1 -0
- package/dist/utils/unirefHomologs.test.js +118 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +23 -22
- package/src/AddHighlightModel/index.tsx +1 -1
- package/src/BgzipFastaMsaAdapter/configSchema.ts +1 -1
- package/src/LaunchMsaView/codingFeature.test.ts +96 -0
- package/src/LaunchMsaView/codingFeature.ts +49 -0
- package/src/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.tsx +52 -26
- package/src/LaunchMsaView/components/BlastQuery/BlastManualPanel.tsx +9 -1
- package/src/LaunchMsaView/components/BlastQuery/BlastPanel.tsx +24 -11
- package/src/LaunchMsaView/components/BlastQuery/BlastSettingsDialog.tsx +4 -4
- package/src/LaunchMsaView/components/BlastQuery/MsaAlgorithmSelect.tsx +7 -2
- package/src/LaunchMsaView/components/BlastQuery/consts.ts +77 -2
- package/src/LaunchMsaView/components/HelpButton.tsx +33 -0
- package/src/LaunchMsaView/components/HelpDialog.tsx +78 -0
- package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +54 -34
- package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +13 -2
- package/src/LaunchMsaView/components/ManualMSALoader/launchView.ts +4 -0
- package/src/LaunchMsaView/components/OrthologQuery/OrthologPanel.tsx +28 -5
- package/src/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.tsx +4 -1
- package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +63 -13
- package/src/LaunchMsaView/components/PreLoadedMSA/preCalculatedLaunchView.ts +4 -0
- package/src/LaunchMsaView/components/QueryRowSelector.tsx +35 -7
- package/src/LaunchMsaView/components/SequenceStatus.tsx +29 -0
- package/src/LaunchMsaView/components/SubmitCancelActions.test.tsx +62 -3
- package/src/LaunchMsaView/components/SubmitCancelActions.tsx +37 -15
- package/src/LaunchMsaView/components/TabPanel.test.tsx +51 -0
- package/src/LaunchMsaView/components/TabPanel.tsx +16 -4
- package/src/LaunchMsaView/components/TranscriptSelector.tsx +6 -1
- package/src/LaunchMsaView/components/calculateProteinSequence.ts +29 -10
- package/src/LaunchMsaView/components/fetchSeq.ts +25 -5
- package/src/LaunchMsaView/components/launchPlacement.tsx +41 -0
- package/src/LaunchMsaView/components/useFeatureSequence.ts +18 -11
- package/src/LaunchMsaView/components/useTranscriptSelection.test.tsx +66 -0
- package/src/LaunchMsaView/components/useTranscriptSelection.ts +41 -2
- package/src/LaunchMsaView/detectQueryRow.test.ts +34 -0
- package/src/LaunchMsaView/detectQueryRow.ts +22 -4
- package/src/LaunchMsaView/index.ts +32 -13
- package/src/LaunchMsaView/launchTarget.test.ts +88 -15
- package/src/LaunchMsaView/launchTarget.ts +49 -14
- package/src/LaunchMsaView/useQueryRowName.test.ts +54 -0
- package/src/LaunchMsaView/useQueryRowName.ts +22 -1
- package/src/LaunchMsaView/util.ts +8 -4
- package/src/LaunchMsaViewExtensionPoint/index.test.ts +23 -0
- package/src/LaunchMsaViewExtensionPoint/index.ts +32 -6
- package/src/MsaViewPanel/afterCreateAutoruns.ts +85 -27
- package/src/MsaViewPanel/components/LaunchProgress.tsx +38 -7
- package/src/MsaViewPanel/components/MsaViewPanel.test.tsx +50 -2
- package/src/MsaViewPanel/components/MsaViewPanel.tsx +10 -2
- package/src/MsaViewPanel/doLaunchBlast.test.ts +207 -0
- package/src/MsaViewPanel/doLaunchBlast.ts +92 -142
- package/src/MsaViewPanel/doLaunchOrthologs.test.ts +13 -0
- package/src/MsaViewPanel/doLaunchOrthologs.ts +55 -5
- package/src/MsaViewPanel/genomeToMSA.test.ts +251 -31
- package/src/MsaViewPanel/genomeToMSA.ts +35 -7
- package/src/MsaViewPanel/loadProteinDomains.test.ts +52 -0
- package/src/MsaViewPanel/loadProteinDomains.ts +24 -11
- package/src/MsaViewPanel/model.test.ts +196 -0
- package/src/MsaViewPanel/model.ts +204 -55
- package/src/MsaViewPanel/msaCoordToGenomeCoord.test.ts +152 -32
- package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +21 -11
- package/src/MsaViewPanel/msaDataStore.ts +10 -0
- package/src/MsaViewPanel/observeProteinHighlights.test.ts +27 -3
- package/src/MsaViewPanel/processInit.test.ts +84 -0
- package/src/MsaViewPanel/resolveConnectedTranscript.ts +160 -0
- package/src/MsaViewPanel/runLaunch.test.ts +54 -0
- package/src/MsaViewPanel/runLaunch.ts +39 -0
- package/src/MsaViewPanel/storedData.test.ts +26 -0
- package/src/MsaViewPanel/structureConnection.ts +0 -26
- package/src/MsaViewPanel/syncGenomeHoverToMsaColumn.test.ts +14 -5
- package/src/MsaViewPanel/util.ts +75 -0
- package/src/utils/browserAlign.test.ts +102 -0
- package/src/utils/browserAlign.ts +352 -0
- package/src/utils/ebiBlast.ts +34 -0
- package/src/utils/homologSearch.ts +51 -0
- package/src/utils/msa.ts +19 -41
- package/src/utils/msaRows.ts +20 -16
- package/src/utils/phmmer.ts +57 -11
- package/src/utils/unirefHomologs.test.ts +149 -0
- package/src/utils/unirefHomologs.ts +323 -0
- package/src/version.ts +1 -1
- package/dist/LaunchMsaView/components/geneticCodes.d.ts +0 -15
- package/dist/LaunchMsaView/components/geneticCodes.js +0 -227
- package/dist/MsaViewPanel/structureConnection.test.js +0 -53
- package/src/LaunchMsaView/components/geneticCodes.ts +0 -298
- package/src/MsaViewPanel/structureConnection.test.ts +0 -62
- /package/dist/{MsaViewPanel/structureConnection.test.d.ts → LaunchMsaView/codingFeature.test.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getSession } from '@jbrowse/core/util';
|
|
2
|
-
import { hasHoverPosition, hasQueryRow } from './util';
|
|
2
|
+
import { hasHoverPosition, hasQueryRow, transcriptPosToVisibleCol, } from './util';
|
|
3
3
|
export function genomeToMSA({ model }) {
|
|
4
|
-
const { hovered } = getSession(model);
|
|
4
|
+
const { assemblyManager, hovered } = getSession(model);
|
|
5
5
|
const { querySeqName, transcriptToMsaMap, connectedView, mafRegion } = model;
|
|
6
6
|
if (!connectedView?.initialized ||
|
|
7
7
|
!hasHoverPosition(hovered) ||
|
|
@@ -12,8 +12,25 @@ export function genomeToMSA({ model }) {
|
|
|
12
12
|
// hoverPosition.coord is a 1-based display coordinate (core's pxToBp adds the
|
|
13
13
|
// +1), while g2p and mafRegion are keyed by 0-based genome position
|
|
14
14
|
const genomePos = coord - 1;
|
|
15
|
+
// The two sides name the chromosome differently. A hover carries the
|
|
16
|
+
// assembly's canonical name -- `1` on jbrowse.org's hg38 -- while mafRegion
|
|
17
|
+
// and the transcript's g2p map carry the feature's, straight out of the
|
|
18
|
+
// annotation file, which is `chr1` in GENCODE. Compared raw they agree only
|
|
19
|
+
// where a config happens to pair files that agree, and everywhere else
|
|
20
|
+
// hovering a codon lit nothing at all, with no throw and no console line.
|
|
21
|
+
//
|
|
22
|
+
// `initialized` is the gate rather than a try/catch: getCanonicalRefName
|
|
23
|
+
// throws until the assembly's aliases load, and this runs from a hover
|
|
24
|
+
// autorun over an assembly nothing here waited for -- mafRegion names its own
|
|
25
|
+
// on a frozen spec, which need not be one the connected view loaded. Until
|
|
26
|
+
// the aliases arrive the raw name is the whole answer, and the hover lights
|
|
27
|
+
// nothing for those frames rather than throwing out of the autorun.
|
|
28
|
+
const assembly = assemblyManager.get(mafRegion?.assemblyName ?? connectedView.assemblyNames[0] ?? '');
|
|
29
|
+
const canonical = (name) => (assembly?.initialized ? assembly.getCanonicalRefName(name) : undefined) ??
|
|
30
|
+
name;
|
|
31
|
+
const hoveredRefName = canonical(refName);
|
|
15
32
|
if (mafRegion) {
|
|
16
|
-
if (
|
|
33
|
+
if (hoveredRefName !== canonical(mafRegion.refName) ||
|
|
17
34
|
!connectedView.assemblyNames.includes(mafRegion.assemblyName) ||
|
|
18
35
|
genomePos < mafRegion.start ||
|
|
19
36
|
genomePos >= mafRegion.end) {
|
|
@@ -25,10 +42,11 @@ export function genomeToMSA({ model }) {
|
|
|
25
42
|
// was last over, on any assembly -- so the refName gate is load bearing:
|
|
26
43
|
// without it the same numeric coordinate on an unrelated chromosome matches a
|
|
27
44
|
// g2p key and lights up a column for a different locus
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
if (transcriptToMsaMap &&
|
|
46
|
+
hoveredRefName === canonical(transcriptToMsaMap.refName)) {
|
|
47
|
+
const proteinPos = transcriptToMsaMap.g2p[genomePos];
|
|
48
|
+
if (proteinPos !== undefined) {
|
|
49
|
+
return transcriptPosToVisibleCol(model, proteinPos);
|
|
32
50
|
}
|
|
33
51
|
}
|
|
34
52
|
return undefined;
|
|
@@ -6,12 +6,40 @@ vi.mock('@jbrowse/core/util', () => ({
|
|
|
6
6
|
getSession: vi.fn(),
|
|
7
7
|
}));
|
|
8
8
|
const mockGetSession = vi.mocked(getSession);
|
|
9
|
+
// What the assembly calls each chromosome. Empty means every name is already
|
|
10
|
+
// canonical, which is the config where the raw comparison this replaced
|
|
11
|
+
// happened to work.
|
|
12
|
+
let aliases = {};
|
|
13
|
+
// core's assembly throws from getCanonicalRefName until its aliases load, and
|
|
14
|
+
// answers `initialized` false until then -- so the stand-in throws too, or the
|
|
15
|
+
// guard is asserted against a method that never had the failure mode
|
|
16
|
+
let assemblyInitialized = true;
|
|
17
|
+
function mockSession(session) {
|
|
18
|
+
mockGetSession.mockReturnValue({
|
|
19
|
+
assemblyManager: {
|
|
20
|
+
get: () => ({
|
|
21
|
+
get initialized() {
|
|
22
|
+
return assemblyInitialized;
|
|
23
|
+
},
|
|
24
|
+
getCanonicalRefName: (refName) => {
|
|
25
|
+
if (!assemblyInitialized) {
|
|
26
|
+
throw new Error('aliases not loaded');
|
|
27
|
+
}
|
|
28
|
+
return aliases[refName] ?? refName;
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
...session,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
9
35
|
describe('genomeToMSA', () => {
|
|
10
36
|
beforeEach(() => {
|
|
11
37
|
vi.clearAllMocks();
|
|
38
|
+
aliases = {};
|
|
39
|
+
assemblyInitialized = true;
|
|
12
40
|
});
|
|
13
41
|
test('returns undefined when connectedView is not initialized', () => {
|
|
14
|
-
|
|
42
|
+
mockSession({
|
|
15
43
|
hovered: {
|
|
16
44
|
hoverFeature: {},
|
|
17
45
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -27,14 +55,14 @@ describe('genomeToMSA', () => {
|
|
|
27
55
|
end: 1010,
|
|
28
56
|
assemblyName: 'hg38',
|
|
29
57
|
},
|
|
30
|
-
connectedView: { initialized: false },
|
|
58
|
+
connectedView: { initialized: false, assemblyNames: ['hg38'] },
|
|
31
59
|
seqPosToVisibleCol: vi.fn(),
|
|
32
60
|
};
|
|
33
61
|
const result = genomeToMSA({ model });
|
|
34
62
|
expect(result).toBeUndefined();
|
|
35
63
|
});
|
|
36
64
|
test('returns undefined when hovered is not valid', () => {
|
|
37
|
-
|
|
65
|
+
mockSession({
|
|
38
66
|
hovered: null,
|
|
39
67
|
});
|
|
40
68
|
const model = {
|
|
@@ -47,7 +75,7 @@ describe('genomeToMSA', () => {
|
|
|
47
75
|
end: 1010,
|
|
48
76
|
assemblyName: 'hg38',
|
|
49
77
|
},
|
|
50
|
-
connectedView: { initialized: true },
|
|
78
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
51
79
|
seqPosToVisibleCol: vi.fn(),
|
|
52
80
|
};
|
|
53
81
|
const result = genomeToMSA({ model });
|
|
@@ -55,7 +83,7 @@ describe('genomeToMSA', () => {
|
|
|
55
83
|
});
|
|
56
84
|
describe('mafRegion mapping', () => {
|
|
57
85
|
test('returns visible column for valid hover within mafRegion', () => {
|
|
58
|
-
|
|
86
|
+
mockSession({
|
|
59
87
|
hovered: {
|
|
60
88
|
hoverFeature: {},
|
|
61
89
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -85,7 +113,7 @@ describe('genomeToMSA', () => {
|
|
|
85
113
|
expect(result).toBe(5);
|
|
86
114
|
});
|
|
87
115
|
test('returns undefined when hover refName does not match mafRegion', () => {
|
|
88
|
-
|
|
116
|
+
mockSession({
|
|
89
117
|
hovered: {
|
|
90
118
|
hoverFeature: {},
|
|
91
119
|
hoverPosition: { coord: 1005, refName: 'chr2' },
|
|
@@ -112,7 +140,7 @@ describe('genomeToMSA', () => {
|
|
|
112
140
|
});
|
|
113
141
|
test('returns undefined when hover coord is before mafRegion start', () => {
|
|
114
142
|
// 1-based coord 1000 is the 0-based base 999, one before the region
|
|
115
|
-
|
|
143
|
+
mockSession({
|
|
116
144
|
hovered: {
|
|
117
145
|
hoverFeature: {},
|
|
118
146
|
hoverPosition: { coord: 1000, refName: 'chr1' },
|
|
@@ -139,7 +167,7 @@ describe('genomeToMSA', () => {
|
|
|
139
167
|
});
|
|
140
168
|
test('returns undefined when hover coord is at or after mafRegion end', () => {
|
|
141
169
|
// 1-based coord 1011 is the 0-based base 1010, one past the region
|
|
142
|
-
|
|
170
|
+
mockSession({
|
|
143
171
|
hovered: {
|
|
144
172
|
hoverFeature: {},
|
|
145
173
|
hoverPosition: { coord: 1011, refName: 'chr1' },
|
|
@@ -165,7 +193,7 @@ describe('genomeToMSA', () => {
|
|
|
165
193
|
expect(result).toBeUndefined();
|
|
166
194
|
});
|
|
167
195
|
test('returns undefined when assembly does not match', () => {
|
|
168
|
-
|
|
196
|
+
mockSession({
|
|
169
197
|
hovered: {
|
|
170
198
|
hoverFeature: {},
|
|
171
199
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -193,7 +221,7 @@ describe('genomeToMSA', () => {
|
|
|
193
221
|
});
|
|
194
222
|
describe('transcriptToMsaMap mapping (original behavior)', () => {
|
|
195
223
|
test('returns visible column using g2p mapping', () => {
|
|
196
|
-
|
|
224
|
+
mockSession({
|
|
197
225
|
hovered: {
|
|
198
226
|
hoverFeature: {},
|
|
199
227
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -202,6 +230,7 @@ describe('genomeToMSA', () => {
|
|
|
202
230
|
const mockSeqPosToVisibleCol = vi.fn().mockReturnValue(10);
|
|
203
231
|
const model = {
|
|
204
232
|
querySeqName: 'QUERY',
|
|
233
|
+
querySeqOffset: 0,
|
|
205
234
|
rows: [['QUERY', 'MKVLTAEEK']],
|
|
206
235
|
transcriptToMsaMap: {
|
|
207
236
|
refName: 'chr1',
|
|
@@ -209,8 +238,9 @@ describe('genomeToMSA', () => {
|
|
|
209
238
|
g2p: { 1004: 10 },
|
|
210
239
|
},
|
|
211
240
|
mafRegion: undefined,
|
|
212
|
-
connectedView: { initialized: true },
|
|
241
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
213
242
|
seqPosToVisibleCol: mockSeqPosToVisibleCol,
|
|
243
|
+
visibleColToSeqPos: (_name, col) => col,
|
|
214
244
|
};
|
|
215
245
|
const result = genomeToMSA({ model });
|
|
216
246
|
expect(mockSeqPosToVisibleCol).toHaveBeenCalledWith('QUERY', 10);
|
|
@@ -219,7 +249,7 @@ describe('genomeToMSA', () => {
|
|
|
219
249
|
test('returns undefined when the hover is on another refName', () => {
|
|
220
250
|
// session.hovered is global, so a hover on an unrelated chromosome can
|
|
221
251
|
// carry a coordinate that happens to be a g2p key
|
|
222
|
-
|
|
252
|
+
mockSession({
|
|
223
253
|
hovered: {
|
|
224
254
|
hoverFeature: {},
|
|
225
255
|
hoverPosition: { coord: 1005, refName: 'chr2' },
|
|
@@ -234,14 +264,79 @@ describe('genomeToMSA', () => {
|
|
|
234
264
|
g2p: { 1004: 10 },
|
|
235
265
|
},
|
|
236
266
|
mafRegion: undefined,
|
|
237
|
-
connectedView: { initialized: true },
|
|
267
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
238
268
|
seqPosToVisibleCol: mockSeqPosToVisibleCol,
|
|
239
269
|
};
|
|
240
270
|
expect(genomeToMSA({ model })).toBeUndefined();
|
|
241
271
|
expect(mockSeqPosToVisibleCol).not.toHaveBeenCalled();
|
|
242
272
|
});
|
|
273
|
+
// a pasted alignment often carries only the region BLAST aligned, and
|
|
274
|
+
// querySeqOffset says how much of the protein comes before it
|
|
275
|
+
test('shifts a trimmed query row by querySeqOffset', () => {
|
|
276
|
+
mockSession({
|
|
277
|
+
hovered: {
|
|
278
|
+
hoverFeature: {},
|
|
279
|
+
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
const seqPosToVisibleCol = vi.fn((_name, pos) => pos);
|
|
283
|
+
const model = {
|
|
284
|
+
querySeqName: 'QUERY',
|
|
285
|
+
querySeqOffset: 4,
|
|
286
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
287
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 10 } },
|
|
288
|
+
mafRegion: undefined,
|
|
289
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
290
|
+
seqPosToVisibleCol,
|
|
291
|
+
visibleColToSeqPos: (_name, col) => col,
|
|
292
|
+
};
|
|
293
|
+
expect(genomeToMSA({ model })).toBe(6);
|
|
294
|
+
expect(seqPosToVisibleCol).toHaveBeenCalledWith('QUERY', 6);
|
|
295
|
+
});
|
|
296
|
+
test('maps nothing for a residue before the trimmed row starts', () => {
|
|
297
|
+
mockSession({
|
|
298
|
+
hovered: {
|
|
299
|
+
hoverFeature: {},
|
|
300
|
+
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
const seqPosToVisibleCol = vi.fn((_name, pos) => pos);
|
|
304
|
+
const model = {
|
|
305
|
+
querySeqName: 'QUERY',
|
|
306
|
+
querySeqOffset: 20,
|
|
307
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
308
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 10 } },
|
|
309
|
+
mafRegion: undefined,
|
|
310
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
311
|
+
seqPosToVisibleCol,
|
|
312
|
+
visibleColToSeqPos: (_name, col) => col,
|
|
313
|
+
};
|
|
314
|
+
expect(genomeToMSA({ model })).toBeUndefined();
|
|
315
|
+
expect(seqPosToVisibleCol).not.toHaveBeenCalled();
|
|
316
|
+
});
|
|
317
|
+
// react-msaview answers one column past the end for a residue the row does
|
|
318
|
+
// not have, which would light the last column for everything beyond it
|
|
319
|
+
test('maps nothing for a residue the row stops short of', () => {
|
|
320
|
+
mockSession({
|
|
321
|
+
hovered: {
|
|
322
|
+
hoverFeature: {},
|
|
323
|
+
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
const model = {
|
|
327
|
+
querySeqName: 'QUERY',
|
|
328
|
+
querySeqOffset: 0,
|
|
329
|
+
rows: [['QUERY', 'MKV']],
|
|
330
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 10 } },
|
|
331
|
+
mafRegion: undefined,
|
|
332
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
333
|
+
seqPosToVisibleCol: () => 3,
|
|
334
|
+
visibleColToSeqPos: () => undefined,
|
|
335
|
+
};
|
|
336
|
+
expect(genomeToMSA({ model })).toBeUndefined();
|
|
337
|
+
});
|
|
243
338
|
test('returns undefined when g2p has no mapping for coord', () => {
|
|
244
|
-
|
|
339
|
+
mockSession({
|
|
245
340
|
hovered: {
|
|
246
341
|
hoverFeature: {},
|
|
247
342
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -255,7 +350,7 @@ describe('genomeToMSA', () => {
|
|
|
255
350
|
g2p: { 1000: 0 }, // No entry for 1004
|
|
256
351
|
},
|
|
257
352
|
mafRegion: undefined,
|
|
258
|
-
connectedView: { initialized: true },
|
|
353
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
259
354
|
seqPosToVisibleCol: vi.fn(),
|
|
260
355
|
};
|
|
261
356
|
const result = genomeToMSA({ model });
|
|
@@ -263,7 +358,7 @@ describe('genomeToMSA', () => {
|
|
|
263
358
|
});
|
|
264
359
|
});
|
|
265
360
|
test('returns undefined when neither mafRegion nor transcriptToMsaMap is set', () => {
|
|
266
|
-
|
|
361
|
+
mockSession({
|
|
267
362
|
hovered: {
|
|
268
363
|
hoverFeature: {},
|
|
269
364
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -274,7 +369,7 @@ describe('genomeToMSA', () => {
|
|
|
274
369
|
rows: [['QUERY', 'MKVLTAEEK']],
|
|
275
370
|
transcriptToMsaMap: undefined,
|
|
276
371
|
mafRegion: undefined,
|
|
277
|
-
connectedView: { initialized: true },
|
|
372
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
278
373
|
seqPosToVisibleCol: vi.fn(),
|
|
279
374
|
};
|
|
280
375
|
const result = genomeToMSA({ model });
|
|
@@ -285,7 +380,7 @@ describe('genomeToMSA', () => {
|
|
|
285
380
|
// uploaded file, or the empty name the manual panel leaves when it matches
|
|
286
381
|
// nothing -- lights column 0 on every genome hover
|
|
287
382
|
test('returns undefined when querySeqName names no row here', () => {
|
|
288
|
-
|
|
383
|
+
mockSession({
|
|
289
384
|
hovered: {
|
|
290
385
|
hoverFeature: {},
|
|
291
386
|
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
@@ -297,10 +392,110 @@ describe('genomeToMSA', () => {
|
|
|
297
392
|
rows: [['some_other_row', 'MKVLTAEEK']],
|
|
298
393
|
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 3 } },
|
|
299
394
|
mafRegion: undefined,
|
|
300
|
-
connectedView: { initialized: true },
|
|
395
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
301
396
|
seqPosToVisibleCol,
|
|
302
397
|
};
|
|
303
398
|
expect(genomeToMSA({ model })).toBeUndefined();
|
|
304
399
|
expect(seqPosToVisibleCol).not.toHaveBeenCalled();
|
|
305
400
|
});
|
|
401
|
+
// A hover names the chromosome the assembly's way and the transcript names it
|
|
402
|
+
// the annotation file's way, so on GENCODE-on-hg38 -- jbrowse.org's own
|
|
403
|
+
// config -- the two are '1' and 'chr1' and pointing at a codon lit nothing.
|
|
404
|
+
describe('a config whose assembly and annotation spell the refName apart', () => {
|
|
405
|
+
beforeEach(() => {
|
|
406
|
+
aliases = { chr1: '1', chr2: '2' };
|
|
407
|
+
});
|
|
408
|
+
test('maps a hover named 1 onto a transcript named chr1', () => {
|
|
409
|
+
mockSession({
|
|
410
|
+
hovered: {
|
|
411
|
+
hoverFeature: {},
|
|
412
|
+
hoverPosition: { coord: 1005, refName: '1' },
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
const seqPosToVisibleCol = vi.fn().mockReturnValue(10);
|
|
416
|
+
const model = {
|
|
417
|
+
querySeqName: 'QUERY',
|
|
418
|
+
querySeqOffset: 0,
|
|
419
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
420
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 10 } },
|
|
421
|
+
mafRegion: undefined,
|
|
422
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
423
|
+
seqPosToVisibleCol,
|
|
424
|
+
visibleColToSeqPos: (_name, col) => col,
|
|
425
|
+
};
|
|
426
|
+
expect(genomeToMSA({ model })).toBe(10);
|
|
427
|
+
expect(seqPosToVisibleCol).toHaveBeenCalledWith('QUERY', 10);
|
|
428
|
+
});
|
|
429
|
+
// the gate still has to reject another chromosome, which is the whole
|
|
430
|
+
// reason it is there
|
|
431
|
+
test('still rejects a hover on another chromosome', () => {
|
|
432
|
+
mockSession({
|
|
433
|
+
hovered: {
|
|
434
|
+
hoverFeature: {},
|
|
435
|
+
hoverPosition: { coord: 1005, refName: '2' },
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
const seqPosToVisibleCol = vi.fn();
|
|
439
|
+
const model = {
|
|
440
|
+
querySeqName: 'QUERY',
|
|
441
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
442
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 10 } },
|
|
443
|
+
mafRegion: undefined,
|
|
444
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
445
|
+
seqPosToVisibleCol,
|
|
446
|
+
};
|
|
447
|
+
expect(genomeToMSA({ model })).toBeUndefined();
|
|
448
|
+
expect(seqPosToVisibleCol).not.toHaveBeenCalled();
|
|
449
|
+
});
|
|
450
|
+
// this runs from a hover autorun, and mafRegion names an assembly off a
|
|
451
|
+
// frozen spec that nothing here waited for -- so the aliases may not be
|
|
452
|
+
// loaded, and asking for them throws
|
|
453
|
+
test('falls back to the raw name while the aliases are still loading', () => {
|
|
454
|
+
assemblyInitialized = false;
|
|
455
|
+
mockSession({
|
|
456
|
+
hovered: {
|
|
457
|
+
hoverFeature: {},
|
|
458
|
+
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
const seqPosToVisibleCol = vi.fn().mockReturnValue(10);
|
|
462
|
+
const model = {
|
|
463
|
+
querySeqName: 'QUERY',
|
|
464
|
+
querySeqOffset: 0,
|
|
465
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
466
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 10 } },
|
|
467
|
+
mafRegion: undefined,
|
|
468
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
469
|
+
seqPosToVisibleCol,
|
|
470
|
+
visibleColToSeqPos: (_name, col) => col,
|
|
471
|
+
};
|
|
472
|
+
expect(() => genomeToMSA({ model })).not.toThrow();
|
|
473
|
+
// both sides spell it 'chr1' here, so the raw comparison still answers
|
|
474
|
+
expect(genomeToMSA({ model })).toBe(10);
|
|
475
|
+
});
|
|
476
|
+
test('maps a hover named 1 into a mafRegion named chr1', () => {
|
|
477
|
+
mockSession({
|
|
478
|
+
hovered: {
|
|
479
|
+
hoverFeature: {},
|
|
480
|
+
hoverPosition: { coord: 1005, refName: '1' },
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
const seqPosToVisibleCol = vi.fn().mockReturnValue(5);
|
|
484
|
+
const model = {
|
|
485
|
+
querySeqName: 'hg38.chr1',
|
|
486
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
487
|
+
transcriptToMsaMap: undefined,
|
|
488
|
+
mafRegion: {
|
|
489
|
+
refName: 'chr1',
|
|
490
|
+
start: 1000,
|
|
491
|
+
end: 1010,
|
|
492
|
+
assemblyName: 'hg38',
|
|
493
|
+
},
|
|
494
|
+
connectedView: { initialized: true, assemblyNames: ['hg38'] },
|
|
495
|
+
seqPosToVisibleCol,
|
|
496
|
+
};
|
|
497
|
+
expect(genomeToMSA({ model })).toBe(5);
|
|
498
|
+
expect(seqPosToVisibleCol).toHaveBeenCalledWith('hg38.chr1', 4);
|
|
499
|
+
});
|
|
500
|
+
});
|
|
306
501
|
});
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Annotation } from 'react-msaview';
|
|
2
2
|
interface DomainModel {
|
|
3
3
|
data: {
|
|
4
4
|
treeMetadata?: string;
|
|
5
5
|
};
|
|
6
6
|
setProgress: (arg: string) => void;
|
|
7
|
-
|
|
7
|
+
setAnnotations: (annotations: Annotation[]) => void;
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* Overlay protein domains on the alignment using NCBI's pre-computed CDD
|
|
11
11
|
* annotations. The BLAST workflow stores each hit's accession in treeMetadata,
|
|
12
12
|
* so we look those up via efetch and key the results by MSA row name (which is
|
|
13
13
|
* what react-msaview matches domains against).
|
|
14
|
+
*
|
|
15
|
+
* The overlay is handed over as `Annotation[]`, the shape every source flattens
|
|
16
|
+
* to. It used to be dressed up as an InterProScan response — an `xref` invented
|
|
17
|
+
* to carry the row name — so that `setDomains` could unwrap it again; that entry
|
|
18
|
+
* point exists for plugins holding the actual EBI wire format, which this is
|
|
19
|
+
* not.
|
|
14
20
|
*/
|
|
15
21
|
export declare function loadProteinDomains(self: DomainModel): Promise<void>;
|
|
16
22
|
export {};
|
|
@@ -4,6 +4,12 @@ import { fetchProteinDomains } from '../utils/ncbiDomains';
|
|
|
4
4
|
* annotations. The BLAST workflow stores each hit's accession in treeMetadata,
|
|
5
5
|
* so we look those up via efetch and key the results by MSA row name (which is
|
|
6
6
|
* what react-msaview matches domains against).
|
|
7
|
+
*
|
|
8
|
+
* The overlay is handed over as `Annotation[]`, the shape every source flattens
|
|
9
|
+
* to. It used to be dressed up as an InterProScan response — an `xref` invented
|
|
10
|
+
* to carry the row name — so that `setDomains` could unwrap it again; that entry
|
|
11
|
+
* point exists for plugins holding the actual EBI wire format, which this is
|
|
12
|
+
* not.
|
|
7
13
|
*/
|
|
8
14
|
export async function loadProteinDomains(self) {
|
|
9
15
|
const metadataJson = self.data.treeMetadata;
|
|
@@ -19,15 +25,18 @@ export async function loadProteinDomains(self) {
|
|
|
19
25
|
}
|
|
20
26
|
self.setProgress(`Fetching protein domains from NCBI for ${rowAccessions.length} sequences...`);
|
|
21
27
|
const byAccession = await fetchProteinDomains(rowAccessions.map(r => r.accession));
|
|
22
|
-
const annotations = {}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const annotations = rowAccessions.flatMap(({ rowName, accession }) => (byAccession.get(accession) ?? []).flatMap(({ signature, locations }) => signature.entry
|
|
29
|
+
? locations.map(({ start, end }) => ({
|
|
30
|
+
id: rowName,
|
|
31
|
+
accession: signature.entry.accession,
|
|
32
|
+
name: signature.entry.name,
|
|
33
|
+
description: signature.entry.description,
|
|
34
|
+
start,
|
|
35
|
+
end,
|
|
36
|
+
}))
|
|
37
|
+
: []));
|
|
38
|
+
if (annotations.length === 0) {
|
|
30
39
|
throw new Error('No CDD domain annotations found for these proteins');
|
|
31
40
|
}
|
|
32
|
-
self.
|
|
41
|
+
self.setAnnotations(annotations);
|
|
33
42
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { expect, test, vi } from 'vitest';
|
|
2
|
+
import { fetchProteinDomains } from '../utils/ncbiDomains';
|
|
3
|
+
import { loadProteinDomains } from './loadProteinDomains';
|
|
4
|
+
vi.mock('../utils/ncbiDomains', () => ({ fetchProteinDomains: vi.fn() }));
|
|
5
|
+
const MATCH = {
|
|
6
|
+
signature: {
|
|
7
|
+
entry: { accession: 'cd00093', name: 'HTH_XRE', description: 'a domain' },
|
|
8
|
+
},
|
|
9
|
+
locations: [{ start: 5, end: 40 }],
|
|
10
|
+
};
|
|
11
|
+
function model(treeMetadata) {
|
|
12
|
+
return {
|
|
13
|
+
data: { treeMetadata: JSON.stringify(treeMetadata) },
|
|
14
|
+
setProgress: vi.fn(),
|
|
15
|
+
setAnnotations: vi.fn(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
test('an accession row becomes one annotation per location, keyed by row name', async () => {
|
|
19
|
+
vi.mocked(fetchProteinDomains).mockResolvedValue(new Map([['NP_1', [MATCH]]]));
|
|
20
|
+
const self = model({
|
|
21
|
+
QUERY: { Accession: 'NP_1' },
|
|
22
|
+
other: { 'Scientific name': 'Mus musculus' },
|
|
23
|
+
});
|
|
24
|
+
await loadProteinDomains(self);
|
|
25
|
+
expect(self.setAnnotations).toHaveBeenCalledWith([
|
|
26
|
+
{
|
|
27
|
+
id: 'QUERY',
|
|
28
|
+
accession: 'cd00093',
|
|
29
|
+
name: 'HTH_XRE',
|
|
30
|
+
description: 'a domain',
|
|
31
|
+
start: 5,
|
|
32
|
+
end: 40,
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
test('says so rather than clearing the overlay when NCBI has nothing', async () => {
|
|
37
|
+
vi.mocked(fetchProteinDomains).mockResolvedValue(new Map());
|
|
38
|
+
const self = model({ QUERY: { Accession: 'NP_1' } });
|
|
39
|
+
await expect(loadProteinDomains(self)).rejects.toThrow('No CDD domain annotations found');
|
|
40
|
+
expect(self.setAnnotations).not.toHaveBeenCalled();
|
|
41
|
+
});
|