genoverse 3.2.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.
Files changed (148) hide show
  1. package/.eslintrc.js +197 -0
  2. package/.github/workflows/test.yml +24 -0
  3. package/LICENSE.TXT +24 -0
  4. package/README.md +11 -0
  5. package/css/controlPanel.css +200 -0
  6. package/css/fileDrop.css +22 -0
  7. package/css/font-awesome.css +3 -0
  8. package/css/fullscreen.css +19 -0
  9. package/css/genoverse.css +466 -0
  10. package/css/karyotype.css +85 -0
  11. package/css/resizer.css +36 -0
  12. package/css/tooltips.css +26 -0
  13. package/css/trackControls.css +111 -0
  14. package/expanded.html +120 -0
  15. package/fontawesome/css/fontawesome.min.css +5 -0
  16. package/fontawesome/css/regular.min.css +5 -0
  17. package/fontawesome/css/solid.min.css +5 -0
  18. package/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  19. package/fontawesome/webfonts/fa-brands-400.woff +0 -0
  20. package/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  21. package/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  22. package/fontawesome/webfonts/fa-regular-400.woff +0 -0
  23. package/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  24. package/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  25. package/fontawesome/webfonts/fa-solid-900.woff +0 -0
  26. package/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  27. package/help.pdf +0 -0
  28. package/i/sort_handle.png +0 -0
  29. package/index.html +68 -0
  30. package/index.js +83 -0
  31. package/jest.config.js +4 -0
  32. package/js/Genoverse.js +1681 -0
  33. package/js/Track/Controller/Sequence.js +17 -0
  34. package/js/Track/Controller/Stranded.js +73 -0
  35. package/js/Track/Controller.js +620 -0
  36. package/js/Track/Model/File/BAM.js +44 -0
  37. package/js/Track/Model/File/BED.js +116 -0
  38. package/js/Track/Model/File/GFF.js +40 -0
  39. package/js/Track/Model/File/VCF.js +101 -0
  40. package/js/Track/Model/File/WIG.js +67 -0
  41. package/js/Track/Model/File.js +36 -0
  42. package/js/Track/Model/Gene/Ensembl.js +22 -0
  43. package/js/Track/Model/Gene.js +5 -0
  44. package/js/Track/Model/Sequence/Ensembl.js +4 -0
  45. package/js/Track/Model/Sequence/Fasta.js +60 -0
  46. package/js/Track/Model/Sequence.js +50 -0
  47. package/js/Track/Model/SequenceVariation.js +41 -0
  48. package/js/Track/Model/Stranded.js +28 -0
  49. package/js/Track/Model/Transcript/Ensembl.js +67 -0
  50. package/js/Track/Model/Transcript.js +5 -0
  51. package/js/Track/Model.js +303 -0
  52. package/js/Track/View/Gene/Ensembl.js +46 -0
  53. package/js/Track/View/Gene.js +6 -0
  54. package/js/Track/View/Sequence/Variation.js +115 -0
  55. package/js/Track/View/Sequence.js +63 -0
  56. package/js/Track/View/Transcript/Ensembl.js +12 -0
  57. package/js/Track/View/Transcript.js +28 -0
  58. package/js/Track/View.js +566 -0
  59. package/js/Track/library/Chromosome.js +145 -0
  60. package/js/Track/library/File/BAM.js +30 -0
  61. package/js/Track/library/File/BED.js +24 -0
  62. package/js/Track/library/File/BIGBED.js +47 -0
  63. package/js/Track/library/File/BIGWIG.js +52 -0
  64. package/js/Track/library/File/GFF.js +9 -0
  65. package/js/Track/library/File/VCF.js +71 -0
  66. package/js/Track/library/File/WIG.js +5 -0
  67. package/js/Track/library/File.js +10 -0
  68. package/js/Track/library/Gene.js +37 -0
  69. package/js/Track/library/Graph/Bar.js +235 -0
  70. package/js/Track/library/Graph/Line.js +296 -0
  71. package/js/Track/library/Graph.js +355 -0
  72. package/js/Track/library/HighlightRegion.js +292 -0
  73. package/js/Track/library/Legend.js +224 -0
  74. package/js/Track/library/Scalebar.js +227 -0
  75. package/js/Track/library/Scaleline.js +91 -0
  76. package/js/Track/library/Static.js +78 -0
  77. package/js/Track/library/dbSNP.js +142 -0
  78. package/js/Track.js +632 -0
  79. package/js/genomes/grch37.js +990 -0
  80. package/js/genomes/grch38.js +990 -0
  81. package/js/genoverse.min.js +2 -0
  82. package/js/genoverse.min.js.map +1 -0
  83. package/js/lib/BWReader.js +578 -0
  84. package/js/lib/Base.js +145 -0
  85. package/js/lib/VCFReader.js +286 -0
  86. package/js/lib/dalliance/js/bam.js +494 -0
  87. package/js/lib/dalliance/js/bin.js +185 -0
  88. package/js/lib/dalliance/js/das.js +749 -0
  89. package/js/lib/dalliance/js/utils.js +370 -0
  90. package/js/lib/dalliance-lib.js +3594 -0
  91. package/js/lib/dalliance-lib.min.js +68 -0
  92. package/js/lib/jDataView.js +2 -0
  93. package/js/lib/jParser.js +192 -0
  94. package/js/lib/jquery-ui.js +8 -0
  95. package/js/lib/jquery.js +2 -0
  96. package/js/lib/jquery.mousehold.js +53 -0
  97. package/js/lib/jquery.mousewheel.js +84 -0
  98. package/js/lib/jquery.tipsy.js +258 -0
  99. package/js/lib/rtree.js +1 -0
  100. package/js/plugins/controlPanel.js +395 -0
  101. package/js/plugins/fileDrop.js +62 -0
  102. package/js/plugins/focusRegion.js +12 -0
  103. package/js/plugins/fullscreen.js +77 -0
  104. package/js/plugins/karyotype.js +210 -0
  105. package/js/plugins/resizer.js +45 -0
  106. package/js/plugins/tooltips.js +94 -0
  107. package/js/plugins/trackControls.js +143 -0
  108. package/package.json +43 -0
  109. package/test/View/__snapshots__/render-bar-graph.test.js.snap +111 -0
  110. package/test/View/__snapshots__/render-blocks.test.js.snap +105 -0
  111. package/test/View/__snapshots__/render-chromosome.test.js.snap +5 -0
  112. package/test/View/__snapshots__/render-highlights.test.js.snap +73 -0
  113. package/test/View/__snapshots__/render-insert-variants.test.js.snap +9 -0
  114. package/test/View/__snapshots__/render-labels.test.js.snap +241 -0
  115. package/test/View/__snapshots__/render-legends.test.js.snap +13 -0
  116. package/test/View/__snapshots__/render-line-graph.test.js.snap +349 -0
  117. package/test/View/__snapshots__/render-scalebar.test.js.snap +49 -0
  118. package/test/View/__snapshots__/render-scaleline.test.js.snap +31 -0
  119. package/test/View/__snapshots__/render-sequence.test.js.snap +23 -0
  120. package/test/View/__snapshots__/render-stranded.test.js.snap +5 -0
  121. package/test/View/__snapshots__/render-transcripts.test.js.snap +193 -0
  122. package/test/View/render-bar-graph.test.js +87 -0
  123. package/test/View/render-blocks.test.js +171 -0
  124. package/test/View/render-chromosome.test.js +40 -0
  125. package/test/View/render-highlights.test.js +67 -0
  126. package/test/View/render-insert-variants.test.js +11 -0
  127. package/test/View/render-labels.test.js +266 -0
  128. package/test/View/render-legends.test.js +31 -0
  129. package/test/View/render-line-graph.test.js +169 -0
  130. package/test/View/render-scalebar.test.js +36 -0
  131. package/test/View/render-scaleline.test.js +28 -0
  132. package/test/View/render-sequence.test.js +49 -0
  133. package/test/View/render-stranded.test.js +10 -0
  134. package/test/View/render-transcripts.test.js +165 -0
  135. package/test/create-and-destroy.test.js +63 -0
  136. package/test/track-ordering.test.js +514 -0
  137. package/test/track_config/__snapshots__/config-settings.test.js.snap +23 -0
  138. package/test/track_config/config-settings.test.js +321 -0
  139. package/test/track_config/zoom-level-settings.test.js +98 -0
  140. package/test/utils.js +80 -0
  141. package/utils/createGenome.js +52 -0
  142. package/utils/devServer.js +36 -0
  143. package/utils/expandedTemplate.html +46 -0
  144. package/utils/git-hooks/post-commit +9 -0
  145. package/utils/git-hooks/pre-commit +7 -0
  146. package/utils/git-hooks/setup +6 -0
  147. package/utils/makeExpanded.js +19 -0
  148. package/webpack.config.js +39 -0
@@ -0,0 +1,169 @@
1
+ const { afterTest, testTrackRenderStatic } = require('../utils');
2
+
3
+ describe('Correctly render line graph where:', () => {
4
+ afterEach(afterTest);
5
+
6
+ const track = { _testClass: Genoverse.Track.Graph.Line, height: 100, margin: 0, resizable: false, rescaleableY: false };
7
+ const data = [
8
+ [ 10, 60, 20, 100, 40, 50, 0, 90, 70, 30 ],
9
+ [ 40, 30, 20, 50, 90, 10, 10, 80, 60, 70 ],
10
+ ];
11
+
12
+ const getTrackConf = test => ({ ...track, ...test.conf });
13
+
14
+ [{
15
+ why : 'scale > 1',
16
+ conf : { width: 100, start: 1, end: 10 },
17
+ }, {
18
+ why : 'scale = 1',
19
+ conf : { width: 100, start: 1, end: 100 },
20
+ }, {
21
+ why : 'scale < 1, all bins of equal size',
22
+ conf : { width: 100, start: 1, end: 200 },
23
+ }, {
24
+ why : 'scale < 1, final bin size = 1',
25
+ conf : { width: 100, start: 1, end: 300 },
26
+ }, {
27
+ why : 'scale < 1, final bin is small',
28
+ conf : { width: 100, start: 1, end: 400 },
29
+ }, {
30
+ why : 'scale < 1, final bin is made of 2 bins',
31
+ conf : { width: 100, start: 1, end: 250 },
32
+ }, {
33
+ why : 'scale < 1, middle bin is made of 2 bins',
34
+ conf : { width: 100, start: 1, end: 297 },
35
+ }].forEach((testSet) => {
36
+ describe(testSet.why, () => {
37
+ const features = [{ start: 1, end: 10, coords: data[0] }];
38
+ const tests = [
39
+ { why: 'no margin', conf: { margin: 0 } },
40
+ { why: 'margin', conf: { margin: 10 } },
41
+ { why: 'margin top and bottom, inverted', conf: { margin: { top: 5, bottom: 20 }, invert: true } },
42
+ { why: 'margin top and bottom, not inverted', conf: { margin: { top: 5, bottom: 20 }, invert: false } },
43
+ { why: 'lineWidth', conf: { margin: 0, lineWidth: 2 } },
44
+ { why: 'colored', conf: { margin: 0, color: 'red' } },
45
+ ];
46
+
47
+ describe('the graph has no fill', () => {
48
+ tests.forEach(test => it(test.why, () => testTrackRenderStatic(features, getTrackConf(test), testSet.conf)));
49
+ });
50
+
51
+ describe('the graph has fill', () => {
52
+ tests.map(t => ({ why: t.why, conf: { fill: true, ...t.conf } })).concat(
53
+ { why: 'globalAlpha', conf: { fill: true, margin: 0, globalAlpha: 0.5 } }
54
+ ).forEach((test) => {
55
+ it(test.why, () => testTrackRenderStatic(features, getTrackConf(test), testSet.conf));
56
+ });
57
+ });
58
+
59
+ describe('the graph has two datasets', () => {
60
+ [
61
+ { why: 'coloured red and blue', conf: { margin: 0, datasets: [{ name: 1, color: 'red' }, { name: 2, color: 'blue' }] } },
62
+ { why: 'one filled, one not', conf: { margin: 0, datasets: [{ name: 1, color: 'red', fill: true }, { name: 2, color: 'blue' }] } },
63
+ { why: 'one with lineWidth set', conf: { margin: 0, datasets: [{ name: 1, color: 'red', lineWidth: 2 }, { name: 2, color: 'blue', fill: true }] } },
64
+ { why: 'one with globalAlpha set', conf: { margin: 0, datasets: [{ name: 1, color: 'red', fill: true }, { name: 2, color: 'blue', fill: true, globalAlpha: 0.5 }] } },
65
+ ].forEach((test) => {
66
+ it(test.why, () => testTrackRenderStatic([
67
+ { start: 1, end: 10, coords: data[0], dataset: 1 },
68
+ { start: 1, end: 10, coords: data[1], dataset: 2 },
69
+ ], getTrackConf(test), testSet.conf));
70
+ });
71
+ });
72
+ });
73
+ });
74
+
75
+ describe('data is not continuous', () => {
76
+ const genoverseConf = { width: 100, start: 101, end: 200 };
77
+
78
+ [
79
+ { why: 'the graph has no fill', conf: { margin: 0, fill: false } },
80
+ { why: 'the graph has fill', conf: { margin: 0, fill: true } },
81
+ ].forEach((test) => {
82
+ describe(test.why, () => {
83
+ const coords = data[0].slice(0, 5);
84
+
85
+ it('each data block is inside the image', () => testTrackRenderStatic([
86
+ { start: 110, end: 114, coords: coords.map((d, i) => [ i + 110, d ]) },
87
+ { start: 130, end: 134, coords: coords.map((d, i) => [ i + 130, d ]) },
88
+ { start: 150, end: 154, coords: coords.map((d, i) => [ i + 150, d ]) },
89
+ ], getTrackConf(test), genoverseConf));
90
+
91
+ it('data blocks extend beyond the image', () => testTrackRenderStatic([
92
+ { start: 98, end: 102, coords: coords.map((d, i) => [ i + 98, d ]) },
93
+ { start: 150, end: 154, coords: coords.map((d, i) => [ i + 150, d ]) },
94
+ { start: 198, end: 202, coords: coords.map((d, i) => [ i + 198, d ]) },
95
+ ], getTrackConf(test), genoverseConf));
96
+ });
97
+ });
98
+ });
99
+
100
+ describe('data is spaced at > 1', () => {
101
+ const features = [{ start: 1, end: 100, coords: data[0].slice(0, 9).map((d, i) => [ i + 1, d ]).filter((d, i) => i % 2) }];
102
+
103
+ [
104
+ { why: 'scale > 1', width: 200, coords: [[ 3, 60 ], [ 7, 100 ], [ 11, 50 ], [ 15, 90 ]] },
105
+ { why: 'scale = 1', width: 100, coords: [[ 1, 60 ], [ 3, 100 ], [ 5, 50 ], [ 7, 90 ]] },
106
+ { why: 'scale < 1', width: 25, coords: [[ 1, 80 ], [ 2, 70 ]] },
107
+ ].forEach((testSet) => {
108
+ describe(testSet.why, () => {
109
+ [
110
+ { why: 'the graph has no fill', conf: { margin: 0, fill: false }, coords: testSet.coords },
111
+ { why: 'the graph has fill', conf: { margin: 0, fill: true }, coords: [[ testSet.coords[0][0], 0 ]].concat(testSet.coords).concat([[ testSet.coords[testSet.coords.length - 1][0], 0 ]]) },
112
+ ].forEach(test => it(test.why, () => testTrackRenderStatic(features, getTrackConf(test), { width: testSet.width, start: 1, end: 100 })));
113
+ });
114
+ });
115
+ });
116
+
117
+ describe('features are defined with', () => {
118
+ const genoverseConf = { width: 100, start: 1, end: 100 };
119
+ const trackConf = { margin: 0, fill: true };
120
+
121
+ [
122
+ { why: 'x, y', conf: trackConf, features: [ 10, 11, 12, 20, 21, 22 ].map(n => ({ y: n, x: n })) },
123
+ { why: 'start == end, y', conf: trackConf, features: [ 10, 11, 12, 20, 21, 22 ].map(n => ({ y: n, start: n, end: n })) },
124
+ { why: 'start != end, y', conf: trackConf, features: [ 10, 20, 30 ].map(n => ({ y: n, start: n, end: n + 5 })) },
125
+ { why: 'no y', conf: trackConf, features: [ 10, 11, 12, 20, 21, 22 ].map(n => ({ start: n, end: n })) },
126
+ ].forEach(
127
+ test => it(test.why, () => testTrackRenderStatic(test.features, getTrackConf(test), genoverseConf))
128
+ );
129
+ });
130
+
131
+ describe('features have the wrong coords', () => {
132
+ const genoverseConf = { width: 100, start: 1, end: 100 };
133
+ const trackConf = { margin: 0 };
134
+ const makeFeatures = coords => [{ start: 10, end: 12, coords: coords.map((n, i) => [ i + 10, n ]) }];
135
+
136
+ [
137
+ { why: 'too few coords', conf: trackConf, features: makeFeatures([ 10, 20 ]), coords: [[ 9, 10 ], [ 10, 20 ]] },
138
+ { why: 'too many coords', conf: trackConf, features: makeFeatures([ 10, 20, 30, 20, 10 ]), coords: [[ 9, 10 ], [ 10, 20 ], [ 11, 30 ]] },
139
+ { why: 'coords outside of start/end', conf: trackConf, features: [{ start: 10, end: 12, coords: [[ 1, 1 ], [ 2, 5 ], [ 3, 7 ], [ 20, 10 ], [ 21, 3 ]] }], coords: [] },
140
+ ].forEach(
141
+ test => it(test.why, () => testTrackRenderStatic(test.features, getTrackConf(test), genoverseConf))
142
+ );
143
+ });
144
+
145
+ describe('yRange is set', () => {
146
+ const coords = [ 1, -8, 5, -5, 0, 7, -2 ];
147
+ const genoverseConf = { width: 100, start: 1, end: 100 };
148
+ const features = [{ start: 1, end: 7, coords: coords }];
149
+
150
+ [
151
+ { why: 'with no margin', conf: { margin: 0 } },
152
+ { why: 'with margin', conf: { margin: 1 } },
153
+ ].forEach((testSet) => {
154
+ const m = testSet.conf.margin;
155
+
156
+ describe(testSet.why, () => {
157
+ [
158
+ { why: 'yRange = [ -5, 5 ]', conf: { yRange: [ -5, 5 ], height: 10, ...testSet.conf }, coords: [[ 0, 6 + m ], [ 1, -3 + m ], [ 2, 10 + m ], [ 3, 0 + m ], [ 4, 5 + m ], [ 5, 12 + m ], [ 6, 3 + m ]] },
159
+ { why: 'yRange = [ -1, 5 ]', conf: { yRange: [ -1, 5 ], height: 12, ...testSet.conf }, coords: [[ 0, 4 + m ], [ 1, -14 + m ], [ 2, 12 + m ], [ 3, -8 + m ], [ 4, 2 + m ], [ 5, 16 + m ], [ 6, -2 + m ]] },
160
+ { why: 'yRange = [ 0, 1 ]', conf: { yRange: [ 0, 1 ], height: 10, ...testSet.conf }, coords: [[ 0, 10 + m ], [ 1, -80 + m ], [ 2, 50 + m ], [ 3, -50 + m ], [ 4, 0 + m ], [ 5, 70 + m ], [ 6, -20 + m ]] },
161
+ { why: 'yRange = [ -1, 0 ]', conf: { yRange: [ -1, 0 ], height: 10, ...testSet.conf }, coords: [[ 0, 20 + m ], [ 1, -70 + m ], [ 2, 60 + m ], [ 3, -40 + m ], [ 4, 10 + m ], [ 5, 80 + m ], [ 6, -10 + m ]] },
162
+ { why: 'yRange = [ 0.5, 7.5 ]', conf: { yRange: [ 0.5, 7.5 ], height: 70, ...testSet.conf }, coords: [[ 0, 5 + m ], [ 1, -85 + m ], [ 2, 45 + m ], [ 3, -55 + m ], [ 4, -5 + m ], [ 5, 65 + m ], [ 6, -25 + m ]] },
163
+ ].forEach(
164
+ test => it(test.why, () => testTrackRenderStatic(features, getTrackConf(test), genoverseConf))
165
+ );
166
+ });
167
+ });
168
+ });
169
+ });
@@ -0,0 +1,36 @@
1
+ const { afterTest, testTrackRender, testTrackRenderStatic } = require('../utils');
2
+
3
+ describe('Correctly render scalebar:', () => {
4
+ afterEach(afterTest);
5
+
6
+ const track = { _testClass: Genoverse.Track.Scalebar };
7
+ const width = 1000;
8
+
9
+ const doTest = end => testTrackRenderStatic(undefined, track, { end: end, chromosomeSize: end, width: width });
10
+
11
+ describe('at different scales', () => {
12
+ it('in bytes, scale = 1', () => doTest(1000));
13
+ it('in bytes, scale < 1', () => doTest(1e4));
14
+ it('in bytes, scale > 1', () => doTest(100));
15
+ it('in kb', () => doTest(1e5));
16
+ it('in Mb', () => doTest(1e7));
17
+ it('in Gb', () => doTest(1e10));
18
+ it('in Tb', () => doTest(1e13));
19
+ });
20
+
21
+ describe('spanning two images', () => {
22
+ it('split on a boundary', () => {
23
+ const end = 1e7;
24
+
25
+ return testTrackRender(undefined, track, { end: end / 2, chromosomeSize: end, width: width });
26
+ });
27
+
28
+ it('split mid section', () => {
29
+ const end = 25e4;
30
+
31
+ return testTrackRender(undefined, track, { end: end / 2, chromosomeSize: end, width: width });
32
+ });
33
+ });
34
+
35
+ it('backgrounds', () => testTrackRenderStatic(undefined, track, { end: width, chromosomeSize: width, width: width }));
36
+ });
@@ -0,0 +1,28 @@
1
+ const { afterTest, testTrackRender } = require('../utils');
2
+
3
+ describe('Correctly render scale line:', () => {
4
+ afterEach(afterTest);
5
+
6
+ const width = 1000;
7
+
8
+ const doTest = (size, strand) => {
9
+ const forward = strand === 'Forward';
10
+ const noStrand = strand === 'No';
11
+
12
+ return testTrackRender(
13
+ undefined,
14
+ { _testClass: Genoverse.Track.Scaleline, strand: noStrand ? false : forward ? 1 : -1 },
15
+ { end: size, chromosomeSize: size, width: width }
16
+ );
17
+ };
18
+
19
+ [ 'Forward', 'Reverse', 'No' ].forEach((strand) => {
20
+ describe(`${strand} strand`, () => {
21
+ it('in bytes', () => doTest(10, strand));
22
+ it('in kb', () => doTest(1e5, strand));
23
+ it('in Mb', () => doTest(1e7, strand));
24
+ it('in Gb', () => doTest(1e10, strand));
25
+ it('in Tb', () => doTest(1e13, strand));
26
+ });
27
+ });
28
+ });
@@ -0,0 +1,49 @@
1
+ const { afterTest, testTrackRenderStatic } = require('../utils');
2
+
3
+ describe('Correctly render sequence:', () => {
4
+ afterEach(afterTest);
5
+
6
+ const track = {
7
+ model : Genoverse.Track.Model.Sequence,
8
+ view : Genoverse.Track.View.Sequence,
9
+ resizable : 'auto',
10
+ };
11
+
12
+ describe('ATCGN', () => {
13
+ const sequence = 'ATCGN';
14
+
15
+ it('without labels', () => testTrackRenderStatic(sequence, track));
16
+ it('with labels', () => testTrackRenderStatic(sequence, track, { start: 1, end: 5 }));
17
+ it('with lower case labels', () => testTrackRenderStatic(sequence.toLowerCase(), { lowerCase: true, ...track }, { start: 1, end: 5 }));
18
+ });
19
+ });
20
+
21
+ describe('Correctly render sequence variation:', () => {
22
+ afterEach(afterTest);
23
+
24
+ const track = {
25
+ model : Genoverse.Track.Model.SequenceVariation.extend({ seqModel: Genoverse.Track.Model.Sequence.extend({ data: 'ATCGN' }) }),
26
+ view : Genoverse.Track.View.SequenceVariation,
27
+ resizable : 'auto',
28
+ };
29
+
30
+ describe('T/C', () => {
31
+ it('without labels', () => testTrackRenderStatic([{ start: 2, end: 2, ref_allele: 'T', alt_allele: 'C' }], track));
32
+ it('with labels', () => testTrackRenderStatic([{ start: 2, end: 2, ref_allele: 'T', alt_allele: 'C' }], track, { start: 1, end: 5 }));
33
+ });
34
+
35
+ describe('TC/-', () => {
36
+ it('without labels', () => testTrackRenderStatic([{ start: 2, end: 3, ref_allele: 'TC', alt_allele: '-' }], track));
37
+ it('with labels', () => testTrackRenderStatic([{ start: 2, end: 3, ref_allele: 'TC', alt_allele: '-' }], track, { start: 1, end: 5 }));
38
+ });
39
+
40
+ describe('T/AGA', () => {
41
+ it('without labels', () => testTrackRenderStatic([{ start: 2, end: 2, ref_allele: 'T', alt_allele: 'AGA' }], track));
42
+ it('with labels', () => testTrackRenderStatic([{ start: 2, end: 3, ref_allele: 'T', alt_allele: 'AGA' }], track, { start: 1, end: 5 }));
43
+ });
44
+
45
+ describe('bumped variants', () => {
46
+ it('without labels', () => testTrackRenderStatic([{ start: 2, end: 3, ref_allele: 'TC', alt_allele: 'AGA' }, { start: 3, end: 4, ref_allele: 'CG', alt_allele: 'A' }], track));
47
+ it('with labels', () => testTrackRenderStatic([{ start: 2, end: 3, ref_allele: 'TC', alt_allele: 'AGA' }, { start: 3, end: 4, ref_allele: 'CG', alt_allele: 'A' }], track, { start: 1, end: 5 }));
48
+ });
49
+ });
@@ -0,0 +1,10 @@
1
+ const { afterTest, testTrackRenderStatic } = require('../utils');
2
+
3
+ describe('Correctly render stranded track:', () => {
4
+ afterEach(afterTest);
5
+
6
+ it('features are split between forward and reverse strand tracks', () => testTrackRenderStatic(
7
+ [{ start: 1, end: 5, strand: 1, color: 'blue' }, { start: 11, end: 15, strand: -1, color: 'red' }],
8
+ { stranded: true, margin: 0, featureHeight: 10, featureMargin: {} }
9
+ ));
10
+ });
@@ -0,0 +1,165 @@
1
+ const { afterTest, testTrackRender, testTrackRenderStatic } = require('../utils');
2
+
3
+ describe('Correctly render transcripts where:', () => {
4
+ afterEach(afterTest);
5
+
6
+ const doTests = (subFeatureJoinStyle, feature, genoverseConfig, func = testTrackRender) => {
7
+ const track = {
8
+ margin : 0,
9
+ featureMargin : {},
10
+ view : Genoverse.Track.View.Transcript.extend({ subFeatureJoinStyle: subFeatureJoinStyle }),
11
+ };
12
+
13
+ describe(`track.subFeatureJoinStyle = "${subFeatureJoinStyle}"`, () => {
14
+ [
15
+ { why: 'forward strand', strand: 1 },
16
+ { why: 'reverse strand', strand: -1 },
17
+ ].forEach(
18
+ test => it(test.why, () => func([{ strand: test.strand, ...feature }], track, { start: 1, end: 1000, chromosomeSize: 1e9, width: 1000, ...genoverseConfig }))
19
+ );
20
+ });
21
+ };
22
+
23
+ describe('there is one transcript on a single image', () => {
24
+ describe('exons without cds', () => {
25
+ const feature = {
26
+ start : 1,
27
+ end : 1000,
28
+ subFeatures : [
29
+ { start: 1, end: 100, height: 7, color: false, borderColor: 'black' },
30
+ { start: 200, end: 300, height: 7, color: false, borderColor: 'black' },
31
+ { start: 500, end: 700, height: 7, color: false, borderColor: 'black' },
32
+ { start: 750, end: 760, height: 7, color: false, borderColor: 'black' },
33
+ { start: 950, end: 1000, height: 7, color: false, borderColor: 'black' },
34
+ ],
35
+ };
36
+
37
+ doTests('curve', feature, undefined, testTrackRenderStatic);
38
+ doTests('peak', feature, undefined, testTrackRenderStatic);
39
+ doTests('line', feature, undefined, testTrackRenderStatic);
40
+ });
41
+
42
+ describe('exons with cds', () => {
43
+ const feature = {
44
+ start : 1,
45
+ end : 1000,
46
+ subFeatures : [
47
+ { start: 1, end: 100, height: 7, color: false, borderColor: 'black' },
48
+ { start: 200, end: 250, height: 7, color: false, borderColor: 'black' },
49
+ { start: 250, end: 300, height: 10 },
50
+ { start: 500, end: 700, height: 10 },
51
+ { start: 750, end: 755, height: 10 },
52
+ { start: 755, end: 760, height: 7, color: false, borderColor: 'black' },
53
+ { start: 950, end: 1000, height: 7, color: false, borderColor: 'black' },
54
+ ],
55
+ };
56
+
57
+ doTests('curve', feature, undefined, testTrackRenderStatic);
58
+ doTests('peak', feature, undefined, testTrackRenderStatic);
59
+ doTests('line', feature, undefined, testTrackRenderStatic);
60
+ });
61
+ });
62
+
63
+ describe('a transcript spans two images, with intron peak on the first image', () => {
64
+ describe('exons without cds', () => {
65
+ // These numbers have been chosen to avoid false negatives due to floating point errors
66
+ const feature = {
67
+ start : 1,
68
+ end : 1500,
69
+ subFeatures : [{ start: 1, end: 100, height: 7, color: false, borderColor: 'black' }, { start: 1301, end: 1500, height: 7, color: false, borderColor: 'black' }],
70
+ };
71
+
72
+ doTests('curve', feature);
73
+ doTests('peak', feature);
74
+ doTests('line', feature);
75
+ });
76
+
77
+ describe('exons with cds', () => {
78
+ // These numbers have been chosen to avoid false negatives due to floating point errors
79
+ const feature = {
80
+ start : 1,
81
+ end : 1500,
82
+ subFeatures : [
83
+ { start: 1, end: 101, height: 7, color: false, borderColor: 'black' },
84
+ { start: 101, end: 300, height: 10 },
85
+ { start: 1301, end: 1400, height: 10 },
86
+ { start: 1400, end: 1500, height: 7, color: false, borderColor: 'black' },
87
+ ],
88
+ };
89
+
90
+ doTests('curve', feature);
91
+ doTests('peak', feature);
92
+ doTests('line', feature);
93
+ });
94
+ });
95
+
96
+ describe('a transcript spans two images, with intron peak on the second image', () => {
97
+ describe('exons without cds', () => {
98
+ // These numbers have been chosen to avoid false negatives due to floating point errors
99
+ const feature = {
100
+ start : 1,
101
+ end : 2000,
102
+ subFeatures : [{ start: 1, end: 900, height: 7, color: false, borderColor: 'black' }, { start: 1901, end: 2000, height: 7, color: false, borderColor: 'black' }],
103
+ };
104
+
105
+ doTests('curve', feature);
106
+ doTests('peak', feature);
107
+ doTests('line', feature);
108
+ });
109
+
110
+ describe('exons with cds', () => {
111
+ // These numbers have been chosen to avoid false negatives due to floating point errors
112
+ const feature = {
113
+ start : 1,
114
+ end : 2000,
115
+ subFeatures : [
116
+ { start: 1, end: 801, height: 7, color: false, borderColor: 'black' },
117
+ { start: 801, end: 900, height: 10 },
118
+ { start: 1901, end: 1950, height: 10 },
119
+ { start: 1950, end: 2000, height: 7, color: false, borderColor: 'black' },
120
+ ],
121
+ };
122
+
123
+ doTests('curve', feature);
124
+ doTests('peak', feature);
125
+ doTests('line', feature);
126
+ });
127
+ });
128
+
129
+ describe('a transcript spans three images, with intron peak on the second image', () => {
130
+ describe('exons without cds', () => {
131
+ const genoverseConfig = { start: 1001, end: 2000 };
132
+
133
+ // These numbers have been chosen to avoid false negatives due to floating point errors
134
+ const feature = {
135
+ start : 1,
136
+ end : 3000,
137
+ subFeatures : [{ start: 1, end: 500, height: 7, color: false, borderColor: 'black' }, { start: 2501, end: 3000, height: 7, color: false, borderColor: 'black' }],
138
+ };
139
+
140
+ doTests('curve', feature, genoverseConfig);
141
+ doTests('peak', feature, genoverseConfig);
142
+ doTests('line', feature, genoverseConfig);
143
+ });
144
+
145
+ describe('exons with cds', () => {
146
+ const genoverseConfig = { start: 1001, end: 2000 };
147
+
148
+ // These numbers have been chosen to avoid false negatives due to floating point errors
149
+ const feature = {
150
+ start : 1,
151
+ end : 3000,
152
+ subFeatures : [
153
+ { start: 1, end: 401, height: 7, color: false, borderColor: 'black' },
154
+ { start: 401, end: 500, height: 10 },
155
+ { start: 2501, end: 2600, height: 10 },
156
+ { start: 2600, end: 3000, height: 7, color: false, borderColor: 'black' },
157
+ ],
158
+ };
159
+
160
+ doTests('curve', feature, genoverseConfig);
161
+ doTests('peak', feature, genoverseConfig);
162
+ doTests('line', feature, genoverseConfig);
163
+ });
164
+ });
165
+ });
@@ -0,0 +1,63 @@
1
+ const css = require('fs').readFileSync('css/genoverse.css', 'utf8');
2
+ const { Genoverse, afterTest } = require('./utils');
3
+
4
+ const html = `<style>${css}</style><div id="genoverse-test-1"></div><div id="genoverse-test-2"></div><div id="genoverse-test-3"></div>`;
5
+
6
+ const doTests = (cfg) => {
7
+ const config = { ...cfg };
8
+ const containerExists = config.container ? !!$(config.container).length : false;
9
+ const elCount = $('*').length;
10
+ const deferred = $.Deferred();
11
+
12
+ new Genoverse({ // eslint-disable-line no-new
13
+ ...cfg,
14
+ afterInit: function () {
15
+ const container = this.container;
16
+
17
+ expect(container.length).toBe(1);
18
+ expect(container.hasClass('genoverse')).toBe(true);
19
+
20
+ if (cfg) {
21
+ if (config.container) {
22
+ if (containerExists) {
23
+ expect(container.attr('id')).toBe($(config.container)[0].id.replace('#', ''));
24
+ } else {
25
+ expect(container.attr('id')).toBeUndefined();
26
+ }
27
+ }
28
+
29
+ if (config.width) {
30
+ expect(container.width()).toBe(config.width);
31
+ expect(this.width).toBe(config.width - this.labelWidth);
32
+ }
33
+ }
34
+
35
+ this.destroy();
36
+
37
+ expect(Object.keys(this).length).toBe(0);
38
+ expect(container.parents('body').length).toBe(1);
39
+ expect(container.children().length).toBe(0);
40
+ expect($('*').length).toBe(elCount + (containerExists ? 0 : 1)); // + 1 because container is left behind when Genoverse is destroyed
41
+
42
+ container.remove();
43
+
44
+ deferred.resolve();
45
+ },
46
+ });
47
+
48
+ return deferred;
49
+ };
50
+
51
+ describe('Genoverse', () => {
52
+ beforeEach(() => { $('body').html(html); });
53
+ afterEach(afterTest);
54
+
55
+ describe('Creation and destruction', () => {
56
+ it('when config is undefined', () => doTests(undefined));
57
+ it('when config is empty hash', () => doTests({}));
58
+ it('when has container id and width', () => doTests({ container: '#genoverse-test-1', width: 2000 }));
59
+ it('when has container DOM element', () => doTests({ container: document.getElementById('genoverse-test-2') }));
60
+ it('when has container jQuery element', () => doTests({ container: $('#genoverse-test-3') }));
61
+ it("when has container id that doesn't exist", () => doTests({ container: '#genoverse-test-0' }));
62
+ });
63
+ });