Skip to content

Commit 393030d

Browse files
committed
Adjusted Cypress tests to JSONEditor component
utilizing MonacoEditor. - Updated test selectors to target JSONEditor component. - Used force option for clicks to handle overlays in the editor. - Increased timeouts where necessary to account for MonacoEditor's loading times Signed-off-by: AmerMesanovic <amer.mesanovic@secomind.com>
1 parent b103c12 commit 393030d

File tree

3 files changed

+142
-93
lines changed

3 files changed

+142
-93
lines changed

cypress/e2e/interface_builder.cy.js

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ const parseMappingOptions = (mapping) => {
1313
};
1414

1515
const setupInterfaceEditorFromSource = (iface) => {
16-
cy.get('#interfaceSource').clear().paste(JSON.stringify(iface));
17-
cy.wait(500);
16+
cy.get('.monaco-editor')
17+
.should('be.visible')
18+
.then(() => {
19+
cy.window().then((win) => {
20+
const editor = win.monaco.editor.getModels()[0];
21+
editor.setValue(JSON.stringify(iface, null, 4));
22+
});
23+
});
1824
};
1925

2026
const setupInterfaceEditorFromUI = (iface) => {
@@ -597,6 +603,7 @@ describe('Interface builder tests', () => {
597603
interfaceFixtures.forEach((interfaceFixture) => {
598604
cy.fixture(interfaceFixture).then(({ data: iface }) => {
599605
setupInterfaceEditorFromSource(iface);
606+
setupInterfaceEditorFromUI(iface);
600607
checkInterfaceEditorUIValues(iface);
601608
});
602609
});
@@ -841,6 +848,14 @@ describe('Interface builder tests', () => {
841848
});
842849

843850
it('displays and saves an interface source with default values stripped out', function () {
851+
// Continuously wait for and check the Monaco editor
852+
function waitForEditor() {
853+
cy.waitForMonacoEditor().then((editor) => {
854+
const editorValue = editor.getValue();
855+
cy.wrap(editorValue).as('editorValue');
856+
});
857+
}
858+
844859
// Case with no default values to strip out
845860
cy.fixture('test.astarte.NoDefaultsInterface').then(({ data: iface }) => {
846861
cy.intercept(
@@ -863,22 +878,22 @@ describe('Interface builder tests', () => {
863878
doc: 'New documentation',
864879
});
865880

866-
// Source should be displayed equal, without adding default values
867-
cy.get('#interfaceSource')
868-
.invoke('val')
869-
.should((ifaceSource) => {
870-
expect(JSON.parse(ifaceSource)).to.deep.eq(iface);
871-
});
881+
// Check Monaco Editor content without adding default values
882+
cy.window().should('have.property', 'monaco');
883+
waitForEditor();
884+
cy.get('@editorValue').should((editorValue) => {
885+
expect(JSON.parse(editorValue)).to.deep.eq(iface);
886+
});
872887

873888
cy.get('#interfaceMinor').type(`{selectall}${newIface.version_minor}`);
874889
cy.get('#interfaceDocumentation').clear().paste(newIface.doc);
875890

876-
// Source should be displayed equal, without adding default values
877-
cy.get('#interfaceSource')
878-
.invoke('val')
879-
.should((ifaceSource) => {
880-
expect(JSON.parse(ifaceSource)).to.deep.eq(newIface);
881-
});
891+
// Check Monaco Editor content without adding default values
892+
cy.window().should('have.property', 'monaco');
893+
waitForEditor();
894+
cy.get('@editorValue').should((editorValue) => {
895+
expect(JSON.parse(editorValue)).to.deep.eq(newIface);
896+
});
882897

883898
// Interface should be saved without adding default values
884899
cy.get('button').contains('Apply changes').scrollIntoView().click();
@@ -910,22 +925,22 @@ describe('Interface builder tests', () => {
910925
doc: 'New documentation',
911926
});
912927

913-
// Source should not be displayed equal, since default values are stripped out
914-
cy.get('#interfaceSource')
915-
.invoke('val')
916-
.should((ifaceSource) => {
917-
expect(JSON.parse(ifaceSource)).not.to.deep.eq(iface);
918-
});
928+
// Check Monaco Editor content as default values are stripped out
929+
cy.window().should('have.property', 'monaco');
930+
waitForEditor();
931+
cy.get('@editorValue').should((editorValue) => {
932+
expect(JSON.parse(editorValue)).not.to.deep.eq(iface);
933+
});
919934

920935
cy.get('#interfaceMinor').type(`{selectall}${newIface.version_minor}`);
921936
cy.get('#interfaceDocumentation').clear().paste(newIface.doc);
922937

923-
// Source should not be displayed equal, since default values are stripped out
924-
cy.get('#interfaceSource')
925-
.invoke('val')
926-
.should((ifaceSource) => {
927-
expect(JSON.parse(ifaceSource)).not.to.deep.eq(newIface);
928-
});
938+
// Check Monaco Editor content as default values are stripped out
939+
cy.window().should('have.property', 'monaco');
940+
waitForEditor();
941+
cy.get('@editorValue').should((editorValue) => {
942+
expect(JSON.parse(editorValue)).not.to.deep.eq(newIface);
943+
});
929944

930945
// Interface should be saved with default values stripped out
931946
cy.get('button').contains('Apply changes').scrollIntoView().click();
@@ -954,15 +969,12 @@ describe('Interface builder tests', () => {
954969
...initialIface,
955970
mappings: [restOfElements],
956971
};
957-
cy.get('#interfaceSource')
958-
.clear()
959-
.invoke('val', JSON.stringify(updatedIface, null, 4))
960-
.type('{enter}');
961972

973+
// Set the updatedIface value in MonacoEditor using setupInterfaceEditorFromSource
974+
setupInterfaceEditorFromSource(updatedIface);
962975
cy.get('[data-testid="/test"]').within(() => {
963976
// Check if the mapping endpoint is displayed
964977
cy.contains('/test');
965-
966978
// Check that the Edit and Delete buttons are not present
967979
cy.get('button').contains('Edit...').should('not.exist');
968980
cy.get('button').contains('Delete').should('not.exist');
@@ -975,11 +987,9 @@ describe('Interface builder tests', () => {
975987
...updatedIface,
976988
version_minor: updatedIface.version_minor + 1,
977989
};
978-
cy.get('#interfaceSource')
979-
.clear()
980-
.invoke('val', JSON.stringify(newIface, null, 4))
981-
.type('{enter}');
982990

991+
// Set the newIface value in MonacoEditor using setupInterfaceEditorFromSource
992+
setupInterfaceEditorFromSource(newIface);
983993
cy.intercept(
984994
'PUT',
985995
`/realmmanagement/v1/*/interfaces/${newIface.interface_name}/${newIface.version_major}`,

cypress/e2e/trigger_builder.cy.js

Lines changed: 68 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const triggerOperatorToLabel = {
2424
};
2525

2626
const setupTriggerEditorFromSource = (trigger) => {
27-
cy.get('#triggerSource').scrollIntoView().paste(JSON.stringify(trigger));
27+
cy.pasteJsonIntoEditor({ json_object: trigger });
2828
cy.wait(1500);
2929
};
3030

@@ -81,33 +81,32 @@ const checkTriggerEditorUIValues = (trigger) => {
8181
.contains('Any interface')
8282
.should('be.selected');
8383
} else {
84-
cy.get('#triggerInterfaceName')
85-
.scrollIntoView()
86-
.should('be.visible')
87-
.contains(iface)
88-
.should('be.selected');
89-
cy.get('#triggerInterfaceMajor')
90-
.scrollIntoView()
91-
.should('be.visible')
92-
.contains(simpleTrigger.interface_major)
93-
.should('be.selected');
94-
cy.get('#triggerPath')
84+
cy.window().should('have.property', 'monaco');
85+
cy.window().should((win) => {
86+
const models = win.monaco.editor.getModels();
87+
expect(models).to.have.length.gt(0);
88+
});
89+
cy.window().then((win) => {
90+
const editor = win.monaco.editor.getModels()[0];
91+
const editorContent = editor.getValue();
92+
const editorJson = JSON.parse(editorContent);
93+
expect(editorJson.simple_triggers[0].interface_name).to.equal(iface);
94+
expect(editorJson.simple_triggers[0].interface_major).to.equal(simpleTrigger.interface_major);
95+
expect(editorJson.simple_triggers[0].match_path).to.equal(simpleTrigger.match_path);
96+
});
97+
}
98+
if (simpleTrigger.value_match_operator) {
99+
cy.get('#triggerOperator')
100+
.scrollIntoView()
101+
.should('be.visible')
102+
.contains(triggerOperatorToLabel[simpleTrigger.value_match_operator])
103+
.should('be.selected');
104+
}
105+
if (simpleTrigger.known_value != null) {
106+
cy.get('#triggerKnownValue')
95107
.scrollIntoView()
96108
.should('be.visible')
97-
.and('have.value', simpleTrigger.match_path);
98-
if (simpleTrigger.value_match_operator) {
99-
cy.get('#triggerOperator')
100-
.scrollIntoView()
101-
.should('be.visible')
102-
.contains(triggerOperatorToLabel[simpleTrigger.value_match_operator])
103-
.should('be.selected');
104-
}
105-
if (simpleTrigger.known_value != null) {
106-
cy.get('#triggerKnownValue')
107-
.scrollIntoView()
108-
.should('be.visible')
109-
.and('have.value', simpleTrigger.known_value);
110-
}
109+
.and('have.value', simpleTrigger.known_value);
111110
}
112111
}
113112

@@ -636,14 +635,16 @@ describe('Trigger builder tests', () => {
636635
});
637636
cy.get('table tr').contains('X-Custom-Header');
638637
cy.get('table tr').contains('Header value');
639-
cy.get('#triggerSource')
640-
.invoke('val')
641-
.should((triggerSource) => {
642-
const trigger = JSON.parse(triggerSource);
638+
cy.window().then((win) => {
639+
if (win.monaco && win.monaco.editor) {
640+
const editor = win.monaco.editor.getModels()[0];
641+
const editorContent = editor.getValue();
642+
const trigger = JSON.parse(editorContent);
643643
expect(trigger.action.http_static_headers).to.deep.eq({
644644
'X-Custom-Header': 'Header value',
645645
});
646-
});
646+
}
647+
});
647648

648649
// Edit http header
649650
cy.get('table tr').contains('X-Custom-Header').parents('tr').get('i.fa-pencil-alt').click();
@@ -655,14 +656,16 @@ describe('Trigger builder tests', () => {
655656
cy.get('button').contains('Update').click();
656657
});
657658
cy.get('table tr').contains('Header new value');
658-
cy.get('#triggerSource')
659-
.invoke('val')
660-
.should((triggerSource) => {
661-
const trigger = JSON.parse(triggerSource);
659+
cy.window().then((win) => {
660+
if (win.monaco && win.monaco.editor) {
661+
const editor = win.monaco.editor.getModels()[0];
662+
const editorContent = editor.getValue();
663+
const trigger = JSON.parse(editorContent);
662664
expect(trigger.action.http_static_headers).to.deep.eq({
663665
'X-Custom-Header': 'Header new value',
664666
});
665-
});
667+
}
668+
});
666669

667670
// Delete http header
668671
cy.get('table tr').contains('X-Custom-Header').parents('tr').get('i.fa-eraser').click();
@@ -671,13 +674,15 @@ describe('Trigger builder tests', () => {
671674
cy.get('.modal-body').contains('Delete custom header "X-Custom-Header"?');
672675
cy.get('button').contains('Delete').click();
673676
});
674-
cy.contains('X-Custom-Header').should('not.exist');
675-
cy.get('#triggerSource')
676-
.invoke('val')
677-
.should((triggerSource) => {
678-
const trigger = JSON.parse(triggerSource);
677+
cy.contains('X-Custom-Header').should('not.exist');
678+
cy.window().then((win) => {
679+
if (win.monaco && win.monaco.editor) {
680+
const editor = win.monaco.editor.getModels()[0];
681+
const editorContent = editor.getValue();
682+
const trigger = JSON.parse(editorContent);
679683
expect(trigger.action.http_static_headers || {}).to.deep.eq({});
680-
});
684+
}
685+
});
681686
});
682687

683688
it('can add, edit, remove AMQP headers', () => {
@@ -697,14 +702,16 @@ describe('Trigger builder tests', () => {
697702
});
698703
cy.get('table tr').contains('X-Custom-Header');
699704
cy.get('table tr').contains('Header value');
700-
cy.get('#triggerSource')
701-
.invoke('val')
702-
.should((triggerSource) => {
703-
const trigger = JSON.parse(triggerSource);
705+
cy.window().then((win) => {
706+
if (win.monaco && win.monaco.editor) {
707+
const editor = win.monaco.editor.getModels()[0];
708+
const editorContent = editor.getValue();
709+
const trigger = JSON.parse(editorContent);
704710
expect(trigger.action.amqp_static_headers).to.deep.eq({
705711
'X-Custom-Header': 'Header value',
706712
});
707-
});
713+
}
714+
});
708715

709716
// Edit amqp header
710717
cy.get('table tr').contains('X-Custom-Header').parents('tr').get('i.fa-pencil-alt').click();
@@ -716,14 +723,16 @@ describe('Trigger builder tests', () => {
716723
cy.get('button').contains('Update').click();
717724
});
718725
cy.get('table tr').contains('Header new value');
719-
cy.get('#triggerSource')
720-
.invoke('val')
721-
.should((triggerSource) => {
722-
const trigger = JSON.parse(triggerSource);
726+
cy.window().then((win) => {
727+
if (win.monaco && win.monaco.editor) {
728+
const editor = win.monaco.editor.getModels()[0];
729+
const editorContent = editor.getValue();
730+
const trigger = JSON.parse(editorContent);
723731
expect(trigger.action.amqp_static_headers).to.deep.eq({
724732
'X-Custom-Header': 'Header new value',
725733
});
726-
});
734+
}
735+
});
727736

728737
// Delete amqp header
729738
cy.get('table tr').contains('X-Custom-Header').parents('tr').get('i.fa-eraser').click();
@@ -733,12 +742,14 @@ describe('Trigger builder tests', () => {
733742
cy.get('button').contains('Delete').click();
734743
});
735744
cy.contains('X-Custom-Header').should('not.exist');
736-
cy.get('#triggerSource')
737-
.invoke('val')
738-
.should((triggerSource) => {
739-
const trigger = JSON.parse(triggerSource);
745+
cy.window().then((win) => {
746+
if (win.monaco && win.monaco.editor) {
747+
const editor = win.monaco.editor.getModels()[0];
748+
const editorContent = editor.getValue();
749+
const trigger = JSON.parse(editorContent);
740750
expect(trigger.action.amqp_static_headers || {}).to.deep.eq({});
741-
});
751+
}
752+
});
742753
});
743754

744755
it('correctly loads trigger from its source', () => {
@@ -781,7 +792,6 @@ describe('Trigger builder tests', () => {
781792
it('correctly shows trigger data in the Editor UI', function () {
782793
const encodedTriggerName = encodeURIComponent(this.test_trigger.data.name);
783794
cy.visit(`/triggers/${encodedTriggerName}/edit`);
784-
cy.wait(1000);
785795
cy.location('pathname').should('eq', `/triggers/${encodedTriggerName}/edit`);
786796
checkTriggerEditorUIValues(this.test_trigger.data);
787797
});

cypress/support/e2e.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,32 @@ Cypress.Commands.add(
103103
});
104104
},
105105
);
106+
107+
Cypress.Commands.add('pasteJsonIntoEditor', ({ json_object }) => {
108+
cy.waitForMonacoEditor().then((editor) => {
109+
editor.setValue(JSON.stringify(json_object, null, 2));
110+
});
111+
});
112+
113+
Cypress.Commands.add('waitForMonacoEditor', () => {
114+
cy.window().should('have.property', 'monaco').then((monaco) => {
115+
return new Cypress.Promise((resolve, reject) => {
116+
const checkEditorInitialized = () => {
117+
const editorModels = monaco.editor.getModels();
118+
if (editorModels.length > 0) {
119+
resolve(editorModels[0]);
120+
} else {
121+
setTimeout(checkEditorInitialized, 1000);
122+
}
123+
};
124+
checkEditorInitialized();
125+
});
126+
});
127+
});
128+
129+
Cypress.on('uncaught:exception', (err, runnable) => {
130+
if (err.message.includes("Failed to execute 'importScripts' on 'WorkerGlobalScope'") &&
131+
err.message.includes("monaco-editor")) {
132+
return false;
133+
}
134+
});

0 commit comments

Comments
 (0)