@datagrok/bio 1.5.8 → 1.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.
@@ -3,9 +3,9 @@ import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
3
3
 
4
4
  /** enum type to simplify setting "user-friendly" notation if necessary */
5
5
  export const enum NOTATION {
6
- FASTA = 'fasta',
7
- SEPARATOR = 'separator',
8
- HELM = 'helm'
6
+ FASTA = 'FASTA',
7
+ SEPARATOR = 'SEPARATOR',
8
+ HELM = 'HELM'
9
9
  }
10
10
 
11
11
  /** Class for handling conversion of notation systems in Macromolecule columns */
@@ -32,14 +32,15 @@ export class NotationConverter {
32
32
 
33
33
  public toHelm(targetNotation: NOTATION): boolean { return targetNotation === NOTATION.HELM; }
34
34
 
35
- // TODO: isRna
36
- public isRna(): boolean { return this.sourceUnits.toLowerCase().endsWith('nt'); }
35
+ public isRna(): boolean { return this.sourceUnits.toLowerCase().endsWith('rna'); }
36
+
37
+ public isDna(): boolean { return this.sourceUnits.toLowerCase().endsWith('dna'); }
37
38
 
38
39
  public isPeptide(): boolean { return this.sourceUnits.toLowerCase().endsWith('pt'); }
39
40
 
40
41
  /** Associate notation types with the corresponding units */
41
42
  /**
42
- * @return {NOTATION} notation associated with the units type
43
+ * @return {NOTATION} Notation associated with the units type
43
44
  */
44
45
  private determineSourceNotation(): NOTATION {
45
46
  if (this.sourceUnits.toLowerCase().startsWith('fasta'))
@@ -51,7 +52,33 @@ export class NotationConverter {
51
52
  return NOTATION.HELM;
52
53
  }
53
54
 
54
- // TODO: write doc
55
+ /**
56
+ * Determine the separator used in SEPARATOR column
57
+ *
58
+ * @return {string} The detected separator
59
+ */
60
+ private determineSeparator(): string {
61
+ // TODO: figure out how to determine the separator efficiently
62
+ const col = this.sourceColumn;
63
+ let i = 0;
64
+ const re = /[^a-z]/;
65
+ while (i < col.length) {
66
+ const molecule = col.get(i);
67
+ const foundSeparator = molecule.toLowerCase().match(re);
68
+ if (foundSeparator)
69
+ return foundSeparator[0];
70
+ i++;
71
+ }
72
+ throw new Error('No separators found');
73
+ }
74
+
75
+ /**
76
+ * Create a new empty column of the specified notation type and the same
77
+ * length as sourceColumn
78
+ *
79
+ * @param {NOTATION} targetNotation
80
+ * @return {DG.Column}
81
+ */
55
82
  private getNewColumn(targetNotation: NOTATION): DG.Column {
56
83
  const col = this.sourceColumn;
57
84
  const len = col.length;
@@ -60,74 +87,199 @@ export class NotationConverter {
60
87
  // dummy code
61
88
  const newColumn = DG.Column.fromList('string', newColName, new Array(len).fill(''));
62
89
  newColumn.semType = 'Macromolecule';
63
- const newUnits = this.sourceUnits.replace(this.sourceNotation.toString(), targetNotation.toString());
64
- newColumn.setTag(DG.TAGS.UNITS, newUnits);
65
- // TODO: determine all the qualifiers (units, ...), perhaps, using detectors
90
+ newColumn.setTag(
91
+ DG.TAGS.UNITS,
92
+ this.sourceUnits.replace(
93
+ this.sourceNotation.toLowerCase().toString(),
94
+ targetNotation.toLowerCase().toString()
95
+ )
96
+ );
97
+ // TODO: specify cell renderers for all cases
98
+ if (this.toFasta(targetNotation)) {
99
+ newColumn.setTag(
100
+ DG.TAGS.CELL_RENDERER,
101
+ 'Macromolecule');
102
+ }
66
103
  return newColumn;
67
104
  }
68
105
 
69
- // TODO: write doc
70
- private convertFastaToSeparator(separator: string): DG.Column {
71
- // TODO: implementation
72
- // * specify separator
73
- // * fasta gap symbol should NOT be considered '-' only, but set as a parameter
74
- // * in fasta every position is a monomer (no multi-char monomers), call splitToMonomers() method
75
- // * in the resulting jagged array, every gap symbol is to be replaced by
76
- // the empty string, while the monomers, to be separated by the separator
77
- // (specified as a parameter)
78
- // On splitToMonomers(): /libraries/bio/src/viewers/WebLogo --> getSplitter
79
-
80
- const gapSymbol = '-'; // to be specified as an argument
106
+ /**
107
+ * Convert a Macromolecule column from FASTA to SEPARATOR notation
108
+ *
109
+ * @param {string} separator A specific separator to be used
110
+ * @param {string} gapSymbol Gap symbol in FASTA, '-' by default
111
+ * @return {DG.Column} A new column in SEPARATOR notation
112
+ */
113
+ private convertFastaToSeparator(separator: string, gapSymbol: string = '-'): DG.Column {
114
+ // a function splitting FASTA sequence into an array of monomers:
81
115
  const splitterAsFasta = WebLogo.splitterAsFasta;
116
+
82
117
  const newColumn = this.getNewColumn(NOTATION.SEPARATOR);
118
+ // assign the values to the newly created empty column
83
119
  newColumn.init((idx: number) => {
84
- const sourcePolymer = this.sourceColumn.get(idx);
85
- const monomersArray = splitterAsFasta(sourcePolymer);
86
- for (let i = 0; i < monomersArray.length; i++) {
87
- if (monomersArray[i] === gapSymbol)
88
- monomersArray[i] = '';
120
+ const fastaPolymer = this.sourceColumn.get(idx);
121
+ const fastaMonomersArray = splitterAsFasta(fastaPolymer);
122
+ for (let i = 0; i < fastaMonomersArray.length; i++) {
123
+ if (fastaMonomersArray[i] === gapSymbol)
124
+ fastaMonomersArray[i] = '';
89
125
  }
90
- return monomersArray.join(separator);
126
+ return fastaMonomersArray.join(separator);
91
127
  });
92
128
  return newColumn;
93
129
  }
94
130
 
95
- private wrapRnaNucleotideToHelm(monomer: string) {
131
+ /**
132
+ * Convert a Macromolecule column from FASTA to HELM
133
+ *
134
+ * @param {string} fastaGapSymbol Optional fasta gap symbol
135
+ * @param {string} helmGapSymbol Optional helm gap symbol
136
+ * @return {DG.Column} A new column in HELM notation
137
+ */
138
+ private convertFastaToHelm(
139
+ fastaGapSymbol: string = '-',
140
+ helmGapSymbol: string = '*'
141
+ ): DG.Column {
142
+ // a function splitting FASTA sequence into an array of monomers
143
+ const splitterAsFasta = WebLogo.splitterAsFasta;
96
144
 
97
- }
145
+ const prefix = (this.isDna()) ? 'DNA1{' :
146
+ (this.isRna()) ? 'RNA1{' :
147
+ (this.isPeptide()) ? 'PEPTIDE1{' :
148
+ 'Unknown'; // this case should be handled as exceptional
149
+
150
+ if (prefix === 'Unknown')
151
+ throw new Error('Neither peptide, nor nucleotide');
152
+
153
+ const postfix = '}$$$';
154
+ const leftWrapper = (this.isDna()) ? 'D(' :
155
+ (this.isRna()) ? 'R(' : ''; // no wrapper for peptides
156
+ const rightWrapper = (this.isDna() || this.isRna()) ? ')P' : ''; // no wrapper for peptides
98
157
 
99
- private convertFastaToHelm(): DG.Column {
100
- const gapSymbol = '-'; // to be specified as an argument
101
- const splitterAsFasta = WebLogo.splitterAsFasta;
102
158
  const newColumn = this.getNewColumn(NOTATION.HELM);
159
+ // assign the values to the empty column
103
160
  newColumn.init((idx: number) => {
104
- const sourcePolymer = this.sourceColumn.get(idx);
105
- const monomersArray = splitterAsFasta(sourcePolymer);
106
- for (let i = 0; i < monomersArray.length; i++) {
107
- // // TODO: handle gap symbols -- replace by asterisk
108
- // if (monomersArray[i] === gapSymbol)
109
- // monomersArray[i] = '*';
110
- // else
161
+ const fastaPolymer = this.sourceColumn.get(idx);
162
+ const fastaMonomersArray = splitterAsFasta(fastaPolymer);
163
+ const helmArray = [prefix];
164
+ let firstIteration = true;
165
+ for (let i = 0; i < fastaMonomersArray.length; i++) {
166
+ if (fastaMonomersArray[i] === fastaGapSymbol) {
167
+ // TODO: verify the correctness of gap symbols handling
168
+ helmArray.push(helmGapSymbol);
169
+ } else {
170
+ const dot = firstIteration ? '' : '.';
171
+ const item = [dot, leftWrapper, fastaMonomersArray[i], rightWrapper];
172
+ helmArray.push(item.join(''));
173
+ }
174
+ firstIteration = false;
111
175
  }
112
- // TODO: determine conditionally (if isDna(), or isRna(), or isPeptide()) the template
113
- return monomersArray.join('');
176
+ helmArray.push(postfix);
177
+ return helmArray.join('');
114
178
  });
115
179
  return newColumn;
116
180
  }
117
181
 
118
- private convertSeparatorToFasta(): DG.Column {
182
+ private handleSeparatorItemForFasta(
183
+ idx: number,
184
+ separatorItemsArray: string[],
185
+ separator: string,
186
+ gapSymbol: string,
187
+ fastaMonomersArray: string[]
188
+ ): void {
189
+ const item = separatorItemsArray[idx];
190
+ if (item.length > 1) {
191
+ // the case of a multi-character monomer
192
+ const monomer = '[' + item + ']';
193
+ fastaMonomersArray.push(monomer);
194
+ }
195
+ if (item === separator) {
196
+ if (idx !== 0 && separatorItemsArray[idx - 1] === separator)
197
+ fastaMonomersArray.push(gapSymbol);
198
+ }
199
+ }
200
+
201
+ private convertSeparatorToFasta(
202
+ separator: string | null = null,
203
+ gapSymbol: string = '-'
204
+ ): DG.Column {
119
205
  // TODO: implementation
120
206
  // * similarly to fasta2separator, divide string into monomers
121
207
  // * adjacent separators is a gap (symbol to be specified)
122
208
  // * the monomers MUST be single-character onles, otherwise forbid
209
+ // * NO, they can be multi-characters
123
210
  // conversion
124
- //getSplitterWithSeparator
125
- return this.getNewColumn(NOTATION.FASTA);
211
+ // * consider automatic determining the separator
212
+
213
+ // if (separator === null)
214
+ // separator = this.determineSeparator();
215
+
216
+ // a function splitting FASTA sequence into an array of monomers
217
+ //const splitterAsSeparator = WebLogo.getSplitterWithSeparator(separator);
218
+ const splitter = WebLogo.getSplitterForColumn(this._sourceColumn);
219
+
220
+ const newColumn = this.getNewColumn(NOTATION.FASTA);
221
+ // assign the values to the empty column
222
+ newColumn.init((idx: number) => {
223
+ const separatorPolymer = this.sourceColumn.get(idx);
224
+ // items can be monomers or separators
225
+ const separatorItemsArray = splitter(separatorPolymer);
226
+ const fastaMonomersArray: string[] = [];
227
+ for (let i = 0; i < separatorItemsArray.length; i++) {
228
+ const item = separatorItemsArray[i];
229
+ if (item.length === 0) {
230
+ fastaMonomersArray.push(gapSymbol);
231
+ } else if (item.length > 1) {
232
+ // the case of a multi-character monomer
233
+ const monomer = '[' + item + ']';
234
+ fastaMonomersArray.push(monomer);
235
+ } else {
236
+ fastaMonomersArray.push(item);
237
+ }
238
+ }
239
+ return fastaMonomersArray.join('');
240
+ });
241
+ return newColumn;
126
242
  }
127
243
 
128
- private convertSeparatorToHelm(): DG.Column {
129
- // TODO: implementation
130
- return this.getNewColumn(NOTATION.HELM);
244
+ private convertSeparatorToHelm(fastaGapSymbol: string = '-', helmGapSymbol: string = '*'): DG.Column {
245
+ // a function splitting FASTA sequence into an array of monomers
246
+ const splitter = WebLogo.getSplitterForColumn(this._sourceColumn);
247
+
248
+ const prefix = (this.isDna()) ? 'DNA1{' :
249
+ (this.isRna()) ? 'RNA1{' :
250
+ (this.isPeptide()) ? 'PEPTIDE1{' :
251
+ 'Unknown'; // this case should be handled as exceptional
252
+
253
+ if (prefix === 'Unknown')
254
+ throw new Error('Neither peptide, nor nucleotide');
255
+
256
+ const postfix = '}$$$';
257
+ const leftWrapper = (this.isDna()) ? 'D(' :
258
+ (this.isRna()) ? 'R(' : ''; // no wrapper for peptides
259
+ const rightWrapper = (this.isDna() || this.isRna()) ? ')P' : ''; // no wrapper for peptides
260
+
261
+ const newColumn = this.getNewColumn(NOTATION.HELM);
262
+ // assign the values to the empty column
263
+ newColumn.init((idx: number) => {
264
+ const fastaPolymer = this.sourceColumn.get(idx);
265
+ const fastaMonomersArray = splitter(fastaPolymer);
266
+ const helmArray = [prefix];
267
+ let firstIteration = true;
268
+ for (let i = 0; i < fastaMonomersArray.length; i++) {
269
+ if (fastaMonomersArray[i] === fastaGapSymbol) {
270
+ // TODO: verify the correctness of gap symbols handling
271
+ helmArray.push(helmGapSymbol);
272
+ } else {
273
+ const dot = firstIteration ? '' : '.';
274
+ const item = [dot, leftWrapper, fastaMonomersArray[i], rightWrapper];
275
+ helmArray.push(item.join(''));
276
+ }
277
+ firstIteration = false;
278
+ }
279
+ helmArray.push(postfix);
280
+ return helmArray.join('');
281
+ });
282
+ return newColumn;
131
283
  }
132
284
 
133
285
  private convertHelmToFasta(): DG.Column {
@@ -140,17 +292,25 @@ export class NotationConverter {
140
292
  return this.getNewColumn(NOTATION.SEPARATOR);
141
293
  }
142
294
 
143
- /** Dispatcher method for notation conversion */
144
- // TODO: write the bodies of converter methods
145
- public convert(targetNotation: NOTATION, separator: string | null): DG.Column {
295
+ /** Dispatcher method for notation conversion
296
+ *
297
+ * @param {NOTATION} targetNotation Notation we want to convert to
298
+ * @param {string | null} tgtSeparator Possible separator
299
+ * @return {DG.Column} Converted column
300
+ */
301
+ public convert(targetNotation: NOTATION, tgtSeparator: string | null = null): DG.Column {
302
+ // possible exceptions
146
303
  if (this.sourceNotation === targetNotation)
147
- throw new Error('Target notation is not specified');
148
- if (this.isFasta() && this.toSeparator(targetNotation))
149
- return this.convertFastaToSeparator(separator!); // there is the only place where a separator is needed
304
+ throw new Error('Target notation is invalid');
305
+ if (this.toSeparator(targetNotation) && tgtSeparator === null)
306
+ throw new Error('Target separator is not specified');
307
+
308
+ if (this.isFasta() && this.toSeparator(targetNotation) && tgtSeparator !== null)
309
+ return this.convertFastaToSeparator(tgtSeparator);
150
310
  else if (this.isFasta() && this.toHelm(targetNotation))
151
311
  return this.convertFastaToHelm();
152
312
  else if (this.isSeparator() && this.toFasta(targetNotation))
153
- return this.convertSeparatorToFasta();
313
+ return this.convertSeparatorToFasta(tgtSeparator!);
154
314
  else if (this.isSeparator() && this.toHelm(targetNotation))
155
315
  return this.convertSeparatorToHelm();
156
316
  else if (this.isHelm() && this.toFasta(targetNotation))
@@ -1,4 +1,4 @@
1
- <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit c4c5a3dc.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 95c6fae9.</title><style type="text/css">html,
2
2
  body {
3
3
  font-family: Arial, Helvetica, sans-serif;
4
4
  font-size: 1rem;
@@ -229,14 +229,21 @@ header {
229
229
  font-size: 1rem;
230
230
  padding: 0 0.5rem;
231
231
  }
232
- </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit c4c5a3dc.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-11 10:13:14</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">94.078s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">84.418s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: expect(received).toBe(expected) // Object.is equality
233
-
234
- Expected: false
235
- Received: true
236
- at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:49:20
237
- at Generator.next (&lt;anonymous&gt;)
238
- at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
239
- at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:63:11)
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=34f75e5127b8. Commit 95c6fae9.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-07-12 11:55:44</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">112.789s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">100.002s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: thrown: "Exceeded timeout of 100000 ms for a test.
233
+ Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
234
+ at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:22:1)
235
+ at Runtime._execModule (/home/runner/work/public/public/packages/Bio/node_modules/jest-runtime/build/index.js:1646:24)
236
+ at Runtime._loadModule (/home/runner/work/public/public/packages/Bio/node_modules/jest-runtime/build/index.js:1185:12)
237
+ at Runtime.requireModule (/home/runner/work/public/public/packages/Bio/node_modules/jest-runtime/build/index.js:1009:12)
238
+ at jestAdapter (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:13)
239
+ at runTestInternal (/home/runner/work/public/public/packages/Bio/node_modules/jest-runner/build/runTest.js:389:16)
240
+ at runTest (/home/runner/work/public/public/packages/Bio/node_modules/jest-runner/build/runTest.js:475:34)
241
+ at TestRunner.runTests (/home/runner/work/public/public/packages/Bio/node_modules/jest-runner/build/index.js:101:12)
242
+ at TestScheduler.scheduleTests (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/TestScheduler.js:333:13)
243
+ at runJest (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/runJest.js:404:19)
244
+ at _run10000 (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/cli/index.js:320:7)
245
+ at runCLI (/home/runner/work/public/public/packages/Bio/node_modules/@jest/core/build/cli/index.js:173:3)
246
+ at Object.run (/home/runner/work/public/public/packages/Bio/node_modules/jest-cli/build/cli/index.js:155:37)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:63:11)
240
247
  at Generator.next (&lt;anonymous&gt;)
241
248
  at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:28:58)
242
249
  at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:24:11
@@ -246,14 +253,4 @@ Received: true
246
253
  at Object.&lt;anonymous&gt;.__awaiter (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:30:12)
247
254
  at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:22:23)
248
255
  at Promise.then.completed (/home/runner/work/public/public/packages/Bio/node_modules/jest-circus/build/utils.js:391:28)
249
- at new Promise (&lt;anonymous&gt;)</pre><pre class="suite-consolelog-item-message">Testing Bio package</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:47:11
250
- at Generator.next (&lt;anonymous&gt;)
251
- at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
252
- at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">MSA.is_correct: TypeError: Cannot read properties of undefined (reading 'split')
253
- sequenceSpace.sequenceSpaceOpens: TypeError: Cannot read properties of undefined (reading 'col')
254
- sequenceSpace.init: Operation caused an exception (FileSystemException: Cannot open file, path = '/home/grok/data/prod/packages/data/Bio/sample_FASTA.csv' (OS Error: No such file or directory, errno = 2))
255
- activityCliffs.activityCliffsOpen: TypeError: Cannot read properties of undefined (reading 'columns')
256
- activityCliffs.init: TypeError: Cannot read properties of undefined (reading 'close')
257
- activityCliffs.init: Operation caused an exception (FileSystemException: Cannot open file, path = '/home/grok/data/prod/packages/data/Bio/sample_MSA.csv' (OS Error: No such file or directory, errno = 2))
258
- renderers.afterMsa: Error: Expected "Macromolecule", got "null"
259
- </pre></div></div></div></div></body></html>
256
+ at new Promise (&lt;anonymous&gt;)</pre><pre class="suite-consolelog-item-message">Testing Bio package</pre></div></div></div></div></body></html>