@opencloning/ui 1.1.2 → 1.3.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 +36 -0
- package/package.json +5 -4
- package/src/components/MainSequenceEditor.jsx +2 -0
- package/src/components/assembler/Assembler.cy.jsx +364 -0
- package/src/components/assembler/Assembler.jsx +298 -206
- package/src/components/assembler/AssemblerPart.cy.jsx +52 -0
- package/src/components/assembler/AssemblerPart.jsx +51 -79
- package/src/components/assembler/ExistingSyntaxDialog.cy.jsx +194 -0
- package/src/components/assembler/ExistingSyntaxDialog.jsx +65 -0
- package/src/components/assembler/PlasmidSyntaxTable.jsx +83 -0
- package/src/components/assembler/assembler_utils.js +134 -0
- package/src/components/assembler/assembler_utils.test.js +193 -0
- package/src/components/assembler/assembly_component.module.css +1 -1
- package/src/components/assembler/graph_utils.js +153 -0
- package/src/components/assembler/graph_utils.test.js +239 -0
- package/src/components/assembler/index.js +9 -0
- package/src/components/assembler/useAssembler.js +59 -22
- package/src/components/assembler/useCombinatorialAssembly.js +76 -0
- package/src/components/assembler/usePlasmidsLogic.js +82 -0
- package/src/components/eLabFTW/utils.js +0 -9
- package/src/components/index.js +2 -0
- package/src/components/navigation/SelectTemplateDialog.jsx +0 -1
- package/src/components/primers/DownloadPrimersButton.jsx +0 -1
- package/src/components/primers/PrimerList.jsx +4 -3
- package/src/components/primers/import_primers/ImportPrimersButton.jsx +0 -1
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignContext.jsx +110 -91
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignGatewayBP.jsx +1 -1
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignGibsonAssembly.jsx +2 -2
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignHomologousRecombination.jsx +1 -1
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignRestriction.jsx +1 -1
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerDesignSimplePair.jsx +1 -1
- package/src/components/primers/primer_design/SequenceTabComponents/PrimerSpacerForm.jsx +5 -22
- package/src/components/primers/primer_design/SequenceTabComponents/TabPannelSettings.jsx +6 -4
- package/src/hooks/useStoreEditor.js +4 -0
- package/src/version.js +1 -1
- package/vitest.config.js +2 -4
- package/src/components/DraggableDialogPaper.jsx +0 -16
- package/src/components/assembler/AssemblePartWidget.jsx +0 -252
- package/src/components/assembler/StopIcon.jsx +0 -34
- package/src/components/assembler/assembler_data2.json +0 -50
- package/src/components/assembler/moclo.json +0 -110
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @opencloning/ui
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#597](https://github.com/manulera/OpenCloning_frontend/pull/597) [`d5a456d`](https://github.com/manulera/OpenCloning_frontend/commit/d5a456d70ccfe949b21aae260d2c99507ff6a88e) Thanks [@manulera](https://github.com/manulera)! - Changes associated with new "Syntax Builder" application for creating and managing modular cloning syntaxes, along with significant refactoring of assembler components to support both the new app and the existing OpenCloning application.
|
|
8
|
+
|
|
9
|
+
- Added a new standalone app (`apps/syntax-builder`) for building and editing cloning syntaxes with visual previews
|
|
10
|
+
- Refactored assembler components to be more modular and reusable across applications
|
|
11
|
+
- Enhanced file parsing utilities to support bidirectional conversion between JSON and delimited formats
|
|
12
|
+
- Added graph-based validation and visualization for syntax parts using the graphology library
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies [[`d5a456d`](https://github.com/manulera/OpenCloning_frontend/commit/d5a456d70ccfe949b21aae260d2c99507ff6a88e)]:
|
|
17
|
+
- @opencloning/store@1.3.0
|
|
18
|
+
- @opencloning/utils@1.3.0
|
|
19
|
+
|
|
20
|
+
## 1.2.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- [#595](https://github.com/manulera/OpenCloning_frontend/pull/595) [`1b28cc5`](https://github.com/manulera/OpenCloning_frontend/commit/1b28cc5852460a072982dc529b58fc9607fae21f) Thanks [@manulera](https://github.com/manulera)! - Minor improvements and bug fixes:
|
|
25
|
+
|
|
26
|
+
- include name of tracks in alignment + update ove to display correct Track Properties table
|
|
27
|
+
- fix display main sequence when alignments are present
|
|
28
|
+
- change default minimum hib length to 14 for primer design
|
|
29
|
+
- Gibson primer design: default to circular assembly, force circular for single input assemblies
|
|
30
|
+
- Gibson primer design: make product sequence preview circular when assembly is circular
|
|
31
|
+
- Primer design: in circular assemblies of one fragment only, display the spacer before the fragment in the preview.
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- Updated dependencies []:
|
|
36
|
+
- @opencloning/store@1.2.0
|
|
37
|
+
- @opencloning/utils@1.2.0
|
|
38
|
+
|
|
3
39
|
## 1.1.2
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencloning/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./src/index.js",
|
|
12
12
|
"./components": "./src/components/index.js",
|
|
13
|
+
"./components/assembler": "./src/components/assembler/index.js",
|
|
13
14
|
"./providers/ConfigProvider": "./src/providers/index.js",
|
|
14
15
|
"./hooks/useConfig": "./src/hooks/useConfig.js",
|
|
15
16
|
"./standalone": "./src/StandAloneOpenCloning.js"
|
|
@@ -24,10 +25,10 @@
|
|
|
24
25
|
"@emotion/styled": "^11.14.0",
|
|
25
26
|
"@mui/icons-material": "^5.15.17",
|
|
26
27
|
"@mui/material": "^5.15.17",
|
|
27
|
-
"@opencloning/store": "1.
|
|
28
|
-
"@opencloning/utils": "1.
|
|
28
|
+
"@opencloning/store": "1.3.0",
|
|
29
|
+
"@opencloning/utils": "1.3.0",
|
|
29
30
|
"@teselagen/bio-parsers": "^0.4.32",
|
|
30
|
-
"@teselagen/ove": "^0.8.
|
|
31
|
+
"@teselagen/ove": "^0.8.30",
|
|
31
32
|
"@teselagen/range-utils": "^0.3.13",
|
|
32
33
|
"@teselagen/sequence-utils": "^0.3.35",
|
|
33
34
|
"@zip.js/zip.js": "^2.7.62",
|
|
@@ -65,6 +65,8 @@ function MainSequenceEditor() {
|
|
|
65
65
|
(state) => {
|
|
66
66
|
const history = state.VectorEditor.mainEditor?.sequenceDataHistory;
|
|
67
67
|
if (!history) return false;
|
|
68
|
+
const sequenceId = state.VectorEditor.mainEditor?.sequenceData?.id;
|
|
69
|
+
if (sequenceId === 'opencloning_primer_design_product') return false;
|
|
68
70
|
return state.cloning.mainSequenceId && Object.keys(history).length > 0 && history.future.length === 0;
|
|
69
71
|
}
|
|
70
72
|
);
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { ConfigProvider } from '@opencloning/ui/providers/ConfigProvider';
|
|
4
|
+
import { AssemblerComponent, UploadPlasmidsButton } from './Assembler';
|
|
5
|
+
import mocloSyntax from '../../../../../cypress/test_files/syntax/moclo_syntax.json';
|
|
6
|
+
|
|
7
|
+
mocloSyntax.overhangNames = {
|
|
8
|
+
...mocloSyntax.overhangNames,
|
|
9
|
+
CCCT: 'CCCT_overhang',
|
|
10
|
+
AACG: 'AACG_overhang',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Test config
|
|
14
|
+
const testConfig = {
|
|
15
|
+
backendUrl: 'http://localhost:8000',
|
|
16
|
+
showAppBar: false,
|
|
17
|
+
noExternalRequests: false,
|
|
18
|
+
enableAssembler: true,
|
|
19
|
+
enablePlannotate: false,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const dummyResponse = {
|
|
23
|
+
sources: [
|
|
24
|
+
{
|
|
25
|
+
id: 1,
|
|
26
|
+
type: "ManuallyTypedSource",
|
|
27
|
+
output_name: null,
|
|
28
|
+
database_id: null,
|
|
29
|
+
input: []
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
sequences: [
|
|
33
|
+
{
|
|
34
|
+
id: 1,
|
|
35
|
+
type: "TextFileSequence",
|
|
36
|
+
sequence_file_format: "genbank",
|
|
37
|
+
overhang_crick_3prime: 0,
|
|
38
|
+
overhang_watson_3prime: 0,
|
|
39
|
+
file_content: "LOCUS name 5 bp DNA linear UNK 01-JAN-1980\nDEFINITION description.\nACCESSION id\nVERSION id\nKEYWORDS .\nSOURCE .\n ORGANISM .\n .\nFEATURES Location/Qualifiers\nORIGIN\n 1 aaaaa\n//"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Test data
|
|
45
|
+
const mockPlasmids = [
|
|
46
|
+
{
|
|
47
|
+
id: 1,
|
|
48
|
+
plasmid_name: 'Test Plasmid 1',
|
|
49
|
+
left_overhang: 'CCCT',
|
|
50
|
+
right_overhang: 'AACG',
|
|
51
|
+
key: 'CCCT-AACG',
|
|
52
|
+
type: 'AddgeneIdSource',
|
|
53
|
+
source: {
|
|
54
|
+
id: 1,
|
|
55
|
+
type: 'AddgeneIdSource',
|
|
56
|
+
input: [],
|
|
57
|
+
repository_id: '12345',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 2,
|
|
62
|
+
plasmid_name: 'Test Plasmid 2',
|
|
63
|
+
left_overhang: 'AACG',
|
|
64
|
+
right_overhang: 'CCCT',
|
|
65
|
+
key: 'AACG-CCCT',
|
|
66
|
+
type: 'AddgeneIdSource',
|
|
67
|
+
source: {
|
|
68
|
+
id: 2,
|
|
69
|
+
type: 'AddgeneIdSource',
|
|
70
|
+
input: [],
|
|
71
|
+
repository_id: '67890',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const mockCategories = [
|
|
77
|
+
{
|
|
78
|
+
id: 1,
|
|
79
|
+
displayName: 'Category 1',
|
|
80
|
+
left_overhang: 'CCCT',
|
|
81
|
+
right_overhang: 'AACG',
|
|
82
|
+
key: 'CCCT-AACG',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 2,
|
|
86
|
+
displayName: 'Category 2',
|
|
87
|
+
left_overhang: 'AACG',
|
|
88
|
+
right_overhang: 'CCCT',
|
|
89
|
+
key: 'AACG-CCCT',
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
describe('<AssemblerComponent />', () => {
|
|
94
|
+
beforeEach(() => {
|
|
95
|
+
// Set up a complete assembly for testing
|
|
96
|
+
cy.window().then((win) => {
|
|
97
|
+
// Ensure we have a clean state
|
|
98
|
+
win.localStorage.clear();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
cy.mount(
|
|
102
|
+
<ConfigProvider config={testConfig}>
|
|
103
|
+
<AssemblerComponent
|
|
104
|
+
plasmids={mockPlasmids}
|
|
105
|
+
categories={mockCategories}
|
|
106
|
+
/>
|
|
107
|
+
</ConfigProvider>,
|
|
108
|
+
);
|
|
109
|
+
// Select first plasmid
|
|
110
|
+
cy.get('[data-testid="plasmid-select"]').first().within(() => {
|
|
111
|
+
cy.get('input').click();
|
|
112
|
+
});
|
|
113
|
+
cy.get('li').contains('Test Plasmid 1').click();
|
|
114
|
+
|
|
115
|
+
// Select second plasmid
|
|
116
|
+
cy.get('[data-testid="plasmid-select"]').eq(1).within(() => {
|
|
117
|
+
cy.get('input').click();
|
|
118
|
+
});
|
|
119
|
+
cy.get('li').contains('Test Plasmid 2').click();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('displays error when fetching sequence for a plasmid fails', () => {
|
|
123
|
+
// Intercept the requestSources call (POST to addgene endpoint)
|
|
124
|
+
cy.intercept('POST', 'http://localhost:8000/repository_id*', {
|
|
125
|
+
statusCode: 500,
|
|
126
|
+
body: {
|
|
127
|
+
detail: 'Failed to fetch plasmid sequence',
|
|
128
|
+
},
|
|
129
|
+
}).as('fetchPlasmidError');
|
|
130
|
+
|
|
131
|
+
// Click submit button
|
|
132
|
+
cy.get('[data-testid="assembler-submit-button"]').should('be.visible').click();
|
|
133
|
+
|
|
134
|
+
// Wait for the error request
|
|
135
|
+
cy.wait('@fetchPlasmidError');
|
|
136
|
+
|
|
137
|
+
// Check that error message is displayed
|
|
138
|
+
cy.get('.MuiAlert-colorError').should('exist');
|
|
139
|
+
cy.contains('Error fetching sequence for').should('exist');
|
|
140
|
+
cy.contains('Test Plasmid 1').should('exist');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('displays error when assembling sequences fails', () => {
|
|
144
|
+
// Mock successful source fetching
|
|
145
|
+
cy.intercept('POST', 'http://localhost:8000/repository_id*', {
|
|
146
|
+
statusCode: 200,
|
|
147
|
+
body: dummyResponse,
|
|
148
|
+
}).as('fetchSourceSuccess');
|
|
149
|
+
|
|
150
|
+
// Mock failed assembly request
|
|
151
|
+
cy.intercept('POST', 'http://localhost:8000/restriction_and_ligation*', {
|
|
152
|
+
statusCode: 500,
|
|
153
|
+
body: {
|
|
154
|
+
detail: 'Failed to assemble sequences',
|
|
155
|
+
},
|
|
156
|
+
}).as('assemblyError');
|
|
157
|
+
|
|
158
|
+
// Click submit button
|
|
159
|
+
cy.get('[data-testid="assembler-submit-button"]').should('be.visible').click();
|
|
160
|
+
|
|
161
|
+
// Wait for both requests
|
|
162
|
+
cy.wait('@fetchSourceSuccess');
|
|
163
|
+
cy.wait('@assemblyError');
|
|
164
|
+
|
|
165
|
+
// Check that error message is displayed
|
|
166
|
+
cy.get('.MuiAlert-colorError').should('exist');
|
|
167
|
+
cy.contains('Error assembling').should('exist');
|
|
168
|
+
cy.contains('Test Plasmid 1').should('exist');
|
|
169
|
+
cy.contains('Test Plasmid 2').should('exist');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('displays network error message correctly', () => {
|
|
173
|
+
// Intercept with network error
|
|
174
|
+
cy.intercept('POST', 'http://localhost:8000/repository_id*', {
|
|
175
|
+
forceNetworkError: true,
|
|
176
|
+
}).as('networkError');
|
|
177
|
+
|
|
178
|
+
// Click submit button
|
|
179
|
+
cy.get('[data-testid="assembler-submit-button"]').should('be.visible').click();
|
|
180
|
+
|
|
181
|
+
// Wait for the error request
|
|
182
|
+
cy.wait('@networkError');
|
|
183
|
+
|
|
184
|
+
// Check that error message is displayed
|
|
185
|
+
cy.get('.MuiAlert-colorError').should('exist');
|
|
186
|
+
cy.contains('Error fetching sequence for').should('exist');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('clears error message when assembly selection is cleared', () => {
|
|
190
|
+
// Intercept with error
|
|
191
|
+
cy.intercept('POST', 'http://localhost:8000/repository_id*', {
|
|
192
|
+
statusCode: 500,
|
|
193
|
+
body: {
|
|
194
|
+
detail: 'Failed to fetch plasmid sequence',
|
|
195
|
+
},
|
|
196
|
+
}).as('fetchPlasmidError');
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
// Click submit button to trigger error
|
|
200
|
+
cy.get('[data-testid="assembler-submit-button"]').should('be.visible').click();
|
|
201
|
+
cy.wait('@fetchPlasmidError');
|
|
202
|
+
|
|
203
|
+
// Verify error is displayed
|
|
204
|
+
cy.get('.MuiAlert-colorError').should('exist');
|
|
205
|
+
|
|
206
|
+
// Clear the assembly by clicking the clear button in the first category select
|
|
207
|
+
cy.get('[data-testid="CancelIcon"]').first().click({ force: true });
|
|
208
|
+
|
|
209
|
+
// Error should be cleared
|
|
210
|
+
cy.get('.MuiAlert-colorError').should('not.exist');
|
|
211
|
+
});
|
|
212
|
+
it('works in normal case', () => {
|
|
213
|
+
// Mock successful source fetching
|
|
214
|
+
cy.intercept('POST', 'http://localhost:8000/repository_id*', {
|
|
215
|
+
statusCode: 200,
|
|
216
|
+
body: dummyResponse,
|
|
217
|
+
}).as('fetchSourceSuccess');
|
|
218
|
+
// Mock assembly request
|
|
219
|
+
cy.intercept('POST', 'http://localhost:8000/restriction_and_ligation*', {
|
|
220
|
+
statusCode: 200,
|
|
221
|
+
body: dummyResponse,
|
|
222
|
+
}).as('assemblySuccess');
|
|
223
|
+
|
|
224
|
+
// Click submit button
|
|
225
|
+
cy.get('[data-testid="assembler-submit-button"]').should('be.visible').click();
|
|
226
|
+
cy.wait('@fetchSourceSuccess');
|
|
227
|
+
|
|
228
|
+
// Check that the table displays the name
|
|
229
|
+
cy.get('[data-testid="assembler-product-table"]').contains('Category 1').should('exist');
|
|
230
|
+
cy.get('[data-testid="assembler-product-table"]').contains('Category 2').should('exist');
|
|
231
|
+
cy.get('[data-testid="assembler-product-table"]').contains('Test Plasmid 1').should('exist');
|
|
232
|
+
cy.get('[data-testid="assembler-product-table"]').contains('Test Plasmid 2').should('exist');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
describe('<UploadPlasmidsButton />', () => {
|
|
237
|
+
beforeEach(() => {
|
|
238
|
+
cy.window().then((win) => {
|
|
239
|
+
win.localStorage.clear();
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('calls addPlasmids with correctly formatted valid plasmid', () => {
|
|
244
|
+
const addPlasmidsSpy = cy.spy().as('addPlasmidsSpy');
|
|
245
|
+
|
|
246
|
+
cy.mount(
|
|
247
|
+
<ConfigProvider config={testConfig}>
|
|
248
|
+
<UploadPlasmidsButton addPlasmids={addPlasmidsSpy} syntax={mocloSyntax} />
|
|
249
|
+
</ConfigProvider>,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
cy.get('button').contains('Add Plasmids').siblings('input').selectFile([
|
|
253
|
+
'cypress/test_files/syntax/pYTK002.gb',
|
|
254
|
+
'cypress/test_files/syntax/moclo_ytk_multi_part.gb',
|
|
255
|
+
'cypress/test_files/syntax/pYTK095.gb',
|
|
256
|
+
'cypress/test_files/sequencing/locus.gb'],
|
|
257
|
+
{ force: true });
|
|
258
|
+
|
|
259
|
+
// Wait for the dialog to appear (indicating plasmids were processed)
|
|
260
|
+
cy.get('.MuiDialog-root', { timeout: 10000 }).should('be.visible');
|
|
261
|
+
|
|
262
|
+
cy.get('@addPlasmidsSpy').should('not.have.been.called');
|
|
263
|
+
|
|
264
|
+
cy.get('[data-testid="invalid-plasmids-box"]').contains('Invalid Plasmids').should('exist');
|
|
265
|
+
cy.get('[data-testid="valid-plasmids-box"]').contains('Valid Plasmids').should('exist');
|
|
266
|
+
|
|
267
|
+
cy.get('[data-testid="invalid-plasmids-box"]').contains('pYTK057')
|
|
268
|
+
cy.get('[data-testid="invalid-plasmids-box"]').contains('moclo_ytk_multi_part.gb')
|
|
269
|
+
cy.get('[data-testid="invalid-plasmids-box"] .MuiChip-label').contains('ATCC-TGGC')
|
|
270
|
+
cy.get('[data-testid="invalid-plasmids-box"] .MuiChip-label').contains('CCCT-AACG (CCCT_overhang-AACG_overhang)')
|
|
271
|
+
cy.get('[data-testid="invalid-plasmids-box"]').contains('Contains multiple parts')
|
|
272
|
+
cy.get('[data-testid="invalid-plasmids-box"]').contains('locus.gb')
|
|
273
|
+
|
|
274
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(1).find('td').eq(0).should('contain', 'pYTK002')
|
|
275
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(1).find('td').eq(1).should('contain', 'pYTK002.gb')
|
|
276
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(1).find('td').eq(2).should('contain', 'CCCT-AACG (CCCT_overhang-AACG_overhang)')
|
|
277
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(1).find('td').eq(3).should('contain', '1')
|
|
278
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(1).find('td').eq(4).should('contain', 'ConS')
|
|
279
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(1).then(($el) => {
|
|
280
|
+
const bgColor = window.getComputedStyle($el[0]).backgroundColor;
|
|
281
|
+
cy.wrap(bgColor).should('equal', 'rgb(132, 197, 222)');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(2).find('td').eq(0).should('contain', 'pYTK095')
|
|
285
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(2).find('td').eq(1).should('contain', 'pYTK095.gb')
|
|
286
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(2).find('td').eq(2).should('contain', 'TACA-CCCT (TACA-CCCT_overhang)')
|
|
287
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(2).find('td').eq(3).should('contain', 'Spans multiple parts')
|
|
288
|
+
cy.get('[data-testid="valid-plasmids-box"] tr').eq(2).find('td').eq(4).should('contain', 'AmpR')
|
|
289
|
+
|
|
290
|
+
// Click the import button
|
|
291
|
+
cy.contains('button', 'Import valid plasmids').click();
|
|
292
|
+
|
|
293
|
+
// Verify addPlasmids was called
|
|
294
|
+
cy.get('@addPlasmidsSpy').should('have.been.called');
|
|
295
|
+
|
|
296
|
+
// Verify it was called with an array and check structure
|
|
297
|
+
cy.get('@addPlasmidsSpy').then((spy) => {
|
|
298
|
+
const firstCall = spy.getCall(0);
|
|
299
|
+
console.log('firstCall', firstCall.args);
|
|
300
|
+
cy.wrap(firstCall.args[0]).should('be.an', 'array');
|
|
301
|
+
cy.wrap(firstCall.args[0]).should('have.length', 2);
|
|
302
|
+
|
|
303
|
+
const firstPlasmid = firstCall.args[0][0];
|
|
304
|
+
|
|
305
|
+
cy.wrap(firstPlasmid.file_name).should('equal', 'pYTK002.gb');
|
|
306
|
+
cy.wrap(firstPlasmid.plasmid_name).should('equal', 'pYTK002.gb (ConS)');
|
|
307
|
+
cy.wrap(firstPlasmid.left_overhang).should('equal', 'CCCT');
|
|
308
|
+
cy.wrap(firstPlasmid.right_overhang).should('equal', 'AACG');
|
|
309
|
+
cy.wrap(firstPlasmid.key).should('equal', 'CCCT-AACG');
|
|
310
|
+
|
|
311
|
+
const {appData} = firstPlasmid.sequenceData;
|
|
312
|
+
|
|
313
|
+
cy.wrap(appData.fileName).should('equal', 'pYTK002.gb');
|
|
314
|
+
cy.wrap(appData.correspondingParts).should('deep.equal', ['CCCT-AACG']);
|
|
315
|
+
cy.wrap(appData.correspondingPartsNames).should('deep.equal', ["CCCT_overhang-AACG_overhang"]);
|
|
316
|
+
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
it('does not allow to submit when all plasmids are invalid', () => {
|
|
322
|
+
cy.mount(
|
|
323
|
+
<ConfigProvider config={testConfig}>
|
|
324
|
+
<UploadPlasmidsButton addPlasmids={() => {}} syntax={mocloSyntax} />
|
|
325
|
+
</ConfigProvider>,
|
|
326
|
+
);
|
|
327
|
+
cy.get('button').contains('Add Plasmids').siblings('input').selectFile([
|
|
328
|
+
'cypress/test_files/sequencing/locus.gb'],
|
|
329
|
+
{ force: true });
|
|
330
|
+
|
|
331
|
+
// Wait for the dialog to appear (indicating plasmids were processed)
|
|
332
|
+
cy.get('.MuiDialog-root', { timeout: 10000 }).should('be.visible');
|
|
333
|
+
|
|
334
|
+
cy.get('[data-testid="invalid-plasmids-box"]').contains('Invalid Plasmids').should('exist');
|
|
335
|
+
cy.get('[data-testid="valid-plasmids-box"]').should('not.exist');
|
|
336
|
+
|
|
337
|
+
cy.get('button').contains('Import valid plasmids').should('be.disabled');
|
|
338
|
+
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('cancelling does not call addPlasmids', () => {
|
|
342
|
+
const addPlasmidsSpy = cy.spy().as('addPlasmidsSpy');
|
|
343
|
+
cy.mount(
|
|
344
|
+
<ConfigProvider config={testConfig}>
|
|
345
|
+
<UploadPlasmidsButton addPlasmids={addPlasmidsSpy} syntax={mocloSyntax} />
|
|
346
|
+
</ConfigProvider>,
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
cy.get('button').contains('Add Plasmids').siblings('input').selectFile([
|
|
350
|
+
'cypress/test_files/syntax/pYTK002.gb',
|
|
351
|
+
'cypress/test_files/syntax/moclo_ytk_multi_part.gb',
|
|
352
|
+
'cypress/test_files/syntax/pYTK095.gb',
|
|
353
|
+
'cypress/test_files/sequencing/locus.gb'],
|
|
354
|
+
{ force: true });
|
|
355
|
+
|
|
356
|
+
cy.get('.MuiDialog-root', { timeout: 10000 }).should('be.visible');
|
|
357
|
+
|
|
358
|
+
cy.get('button').contains('Cancel').click();
|
|
359
|
+
|
|
360
|
+
cy.get('@addPlasmidsSpy').should('not.have.been.called');
|
|
361
|
+
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
});
|